From 757094bc23287cd383d85e96738ec92b2904cfaa Mon Sep 17 00:00:00 2001 From: otsmr Date: Sat, 11 Apr 2026 21:28:18 +0200 Subject: [PATCH 01/86] poc --- flutter_rust_bridge.yaml | 3 + integration_test/simple_test.dart | 13 + ios/Podfile.lock | 12 + lib/core/frb_generated.dart | 397 +++ lib/core/frb_generated.io.dart | 151 ++ lib/core/frb_generated.web.dart | 150 ++ lib/core/twonly.dart | 35 + lib/core/twonly/database.dart | 20 + lib/core/twonly/database/contact.dart | 32 + lib/main.dart | 10 + lib/src/database/twonly.db.dart | 7 +- pubspec.lock | 62 + pubspec.yaml | 5 + rust/.gitignore | 1 + rust/Cargo.lock | 2228 +++++++++++++++++ rust/Cargo.toml | 25 + rust/src/frb_generated.rs | 410 +++ rust/src/lib.rs | 3 + rust/src/twonly/database/contact.rs | 40 + rust/src/twonly/database/mod.rs | 63 + rust/src/twonly/error.rs | 13 + rust/src/twonly/log/mod.rs | 44 + rust/src/twonly/mod.rs | 41 + rust/src/user_discovery/memory.rs | 0 rust/src/user_discovery/mod.rs | 0 rust_builder/.gitignore | 29 + rust_builder/README.md | 1 + rust_builder/android/.gitignore | 9 + rust_builder/android/build.gradle | 56 + rust_builder/android/settings.gradle | 1 + .../android/src/main/AndroidManifest.xml | 3 + rust_builder/cargokit/.gitignore | 4 + rust_builder/cargokit/LICENSE | 42 + rust_builder/cargokit/README | 11 + rust_builder/cargokit/build_pod.sh | 58 + rust_builder/cargokit/build_tool/README.md | 5 + .../cargokit/build_tool/analysis_options.yaml | 34 + .../cargokit/build_tool/bin/build_tool.dart | 8 + .../cargokit/build_tool/lib/build_tool.dart | 8 + .../lib/src/android_environment.dart | 195 ++ .../lib/src/artifacts_provider.dart | 266 ++ .../build_tool/lib/src/build_cmake.dart | 40 + .../build_tool/lib/src/build_gradle.dart | 49 + .../build_tool/lib/src/build_pod.dart | 89 + .../build_tool/lib/src/build_tool.dart | 276 ++ .../cargokit/build_tool/lib/src/builder.dart | 209 ++ .../cargokit/build_tool/lib/src/cargo.dart | 48 + .../build_tool/lib/src/crate_hash.dart | 124 + .../build_tool/lib/src/environment.dart | 68 + .../cargokit/build_tool/lib/src/logging.dart | 52 + .../cargokit/build_tool/lib/src/options.dart | 309 +++ .../lib/src/precompile_binaries.dart | 205 ++ .../cargokit/build_tool/lib/src/rustup.dart | 149 ++ .../cargokit/build_tool/lib/src/target.dart | 147 ++ .../cargokit/build_tool/lib/src/util.dart | 172 ++ .../build_tool/lib/src/verify_binaries.dart | 84 + rust_builder/cargokit/build_tool/pubspec.lock | 453 ++++ rust_builder/cargokit/build_tool/pubspec.yaml | 33 + rust_builder/cargokit/cmake/cargokit.cmake | 99 + .../cargokit/cmake/resolve_symlinks.ps1 | 34 + rust_builder/cargokit/gradle/plugin.gradle | 184 ++ rust_builder/cargokit/run_build_tool.cmd | 91 + rust_builder/cargokit/run_build_tool.sh | 99 + rust_builder/ios/Classes/dummy_file.c | 1 + rust_builder/ios/rust_lib_twonly.podspec | 45 + rust_builder/linux/CMakeLists.txt | 19 + rust_builder/macos/Classes/dummy_file.c | 1 + rust_builder/macos/rust_lib_twonly.podspec | 44 + rust_builder/pubspec.yaml | 34 + rust_builder/windows/.gitignore | 17 + rust_builder/windows/CMakeLists.txt | 20 + test/drift/twonly_db/migration_test.dart | 108 +- test_driver/integration_test.dart | 3 + 73 files changed, 7766 insertions(+), 35 deletions(-) create mode 100644 flutter_rust_bridge.yaml create mode 100644 integration_test/simple_test.dart create mode 100644 lib/core/frb_generated.dart create mode 100644 lib/core/frb_generated.io.dart create mode 100644 lib/core/frb_generated.web.dart create mode 100644 lib/core/twonly.dart create mode 100644 lib/core/twonly/database.dart create mode 100644 lib/core/twonly/database/contact.dart create mode 100644 rust/.gitignore create mode 100644 rust/Cargo.lock create mode 100644 rust/Cargo.toml create mode 100644 rust/src/frb_generated.rs create mode 100644 rust/src/lib.rs create mode 100644 rust/src/twonly/database/contact.rs create mode 100644 rust/src/twonly/database/mod.rs create mode 100644 rust/src/twonly/error.rs create mode 100644 rust/src/twonly/log/mod.rs create mode 100644 rust/src/twonly/mod.rs create mode 100644 rust/src/user_discovery/memory.rs create mode 100644 rust/src/user_discovery/mod.rs create mode 100644 rust_builder/.gitignore create mode 100644 rust_builder/README.md create mode 100644 rust_builder/android/.gitignore create mode 100644 rust_builder/android/build.gradle create mode 100644 rust_builder/android/settings.gradle create mode 100644 rust_builder/android/src/main/AndroidManifest.xml create mode 100644 rust_builder/cargokit/.gitignore create mode 100644 rust_builder/cargokit/LICENSE create mode 100644 rust_builder/cargokit/README create mode 100755 rust_builder/cargokit/build_pod.sh create mode 100644 rust_builder/cargokit/build_tool/README.md create mode 100644 rust_builder/cargokit/build_tool/analysis_options.yaml create mode 100644 rust_builder/cargokit/build_tool/bin/build_tool.dart create mode 100644 rust_builder/cargokit/build_tool/lib/build_tool.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/android_environment.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/artifacts_provider.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/build_cmake.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/build_gradle.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/build_pod.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/build_tool.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/builder.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/cargo.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/crate_hash.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/environment.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/logging.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/options.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/precompile_binaries.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/rustup.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/target.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/util.dart create mode 100644 rust_builder/cargokit/build_tool/lib/src/verify_binaries.dart create mode 100644 rust_builder/cargokit/build_tool/pubspec.lock create mode 100644 rust_builder/cargokit/build_tool/pubspec.yaml create mode 100644 rust_builder/cargokit/cmake/cargokit.cmake create mode 100644 rust_builder/cargokit/cmake/resolve_symlinks.ps1 create mode 100644 rust_builder/cargokit/gradle/plugin.gradle create mode 100755 rust_builder/cargokit/run_build_tool.cmd create mode 100755 rust_builder/cargokit/run_build_tool.sh create mode 100644 rust_builder/ios/Classes/dummy_file.c create mode 100644 rust_builder/ios/rust_lib_twonly.podspec create mode 100644 rust_builder/linux/CMakeLists.txt create mode 100644 rust_builder/macos/Classes/dummy_file.c create mode 100644 rust_builder/macos/rust_lib_twonly.podspec create mode 100644 rust_builder/pubspec.yaml create mode 100644 rust_builder/windows/.gitignore create mode 100644 rust_builder/windows/CMakeLists.txt create mode 100644 test_driver/integration_test.dart diff --git a/flutter_rust_bridge.yaml b/flutter_rust_bridge.yaml new file mode 100644 index 00000000..bbdc703e --- /dev/null +++ b/flutter_rust_bridge.yaml @@ -0,0 +1,3 @@ +rust_input: crate::twonly +rust_root: rust/ +dart_output: lib/core \ No newline at end of file diff --git a/integration_test/simple_test.dart b/integration_test/simple_test.dart new file mode 100644 index 00000000..2923b76c --- /dev/null +++ b/integration_test/simple_test.dart @@ -0,0 +1,13 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:twonly/core/frb_generated.dart'; +import 'package:twonly/main.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + setUpAll(() async => RustLib.init()); + testWidgets('Can call rust function', (tester) async { + await tester.pumpWidget(const MyApp()); + expect(find.textContaining('Result: `Hello, Tom!`'), findsOneWidget); + }); +} diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d8c25ba3..a09dc56e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -231,6 +231,8 @@ PODS: - in_app_purchase_storekit (0.0.1): - Flutter - FlutterMacOS + - integration_test (0.0.1): + - Flutter - libwebp (1.5.0): - libwebp/demux (= 1.5.0) - libwebp/mux (= 1.5.0) @@ -285,6 +287,8 @@ PODS: - PromisesObjC (2.4.0) - restart_app (1.7.3): - Flutter + - rust_lib_twonly (0.0.1): + - Flutter - SDWebImage (5.21.7): - SDWebImage/Core (= 5.21.7) - SDWebImage/Core (5.21.7) @@ -370,12 +374,14 @@ DEPENDENCIES: - GoogleUtilities - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`) + - integration_test (from `.symlinks/plugins/integration_test/ios`) - local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`) - no_screenshot (from `.symlinks/plugins/no_screenshot/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - pro_video_editor (from `.symlinks/plugins/pro_video_editor/ios`) - restart_app (from `.symlinks/plugins/restart_app/ios`) + - rust_lib_twonly (from `.symlinks/plugins/rust_lib_twonly/ios`) - sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) @@ -470,6 +476,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/image_picker_ios/ios" in_app_purchase_storekit: :path: ".symlinks/plugins/in_app_purchase_storekit/darwin" + integration_test: + :path: ".symlinks/plugins/integration_test/ios" local_auth_darwin: :path: ".symlinks/plugins/local_auth_darwin/darwin" no_screenshot: @@ -482,6 +490,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/pro_video_editor/ios" restart_app: :path: ".symlinks/plugins/restart_app/ios" + rust_lib_twonly: + :path: ".symlinks/plugins/rust_lib_twonly/ios" sentry_flutter: :path: ".symlinks/plugins/sentry_flutter/ios" share_plus: @@ -540,6 +550,7 @@ SPEC CHECKSUMS: GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 in_app_purchase_storekit: 22cca7d08eebca9babdf4d07d0baccb73325d3c8 + integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d @@ -555,6 +566,7 @@ SPEC CHECKSUMS: pro_video_editor: 44ef9a6d48dbd757ed428cf35396dd05f35c7830 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 restart_app: 0714144901e260eae68f7afc2fc4aacc1a323ad2 + rust_lib_twonly: 73165b05d0cda50db45852db63f49caa7f319520 SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf SDWebImageWebPCoder: 0e06e365080397465cc73a7a9b472d8a3bd0f377 Sentry: d587a8fe91ca13503ecd69a1905f3e8a0fcf61be diff --git a/lib/core/frb_generated.dart b/lib/core/frb_generated.dart new file mode 100644 index 00000000..05958612 --- /dev/null +++ b/lib/core/frb_generated.dart @@ -0,0 +1,397 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.12.0. + +// ignore_for_file: unused_import, annotate_overrides, non_constant_identifier_names, prefer_const_literals_to_create_immutables + +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +import 'frb_generated.dart'; +import 'frb_generated.io.dart' + if (dart.library.js_interop) 'frb_generated.web.dart'; +import 'twonly.dart'; +import 'twonly/database/contact.dart'; + +/// Main entrypoint of the Rust API +class RustLib extends BaseEntrypoint { + RustLib._(); + @internal + static final instance = RustLib._(); + + /// Initialize flutter_rust_bridge + static Future init({ + RustLibApi? api, + BaseHandler? handler, + ExternalLibrary? externalLibrary, + bool forceSameCodegenVersion = true, + }) async { + await instance.initImpl( + api: api, + handler: handler, + externalLibrary: externalLibrary, + forceSameCodegenVersion: forceSameCodegenVersion, + ); + } + + /// Initialize flutter_rust_bridge in mock mode. + /// No libraries for FFI are loaded. + static void initMock({ + required RustLibApi api, + }) { + instance.initMockImpl( + api: api, + ); + } + + /// Dispose flutter_rust_bridge + /// + /// The call to this function is optional, since flutter_rust_bridge (and everything else) + /// is automatically disposed when the app stops. + static void dispose() => instance.disposeImpl(); + + @override + ApiImplConstructor get apiImplConstructor => + RustLibApiImpl.new; + + @override + WireConstructor get wireConstructor => + RustLibWire.fromExternalLibrary; + + @override + Future executeRustInitializers() async {} + + @override + ExternalLibraryLoaderConfig get defaultExternalLibraryLoaderConfig => + kDefaultExternalLibraryLoaderConfig; + + @override + String get codegenVersion => '2.12.0'; + + @override + int get rustContentHash => 741438464; + + static const kDefaultExternalLibraryLoaderConfig = + ExternalLibraryLoaderConfig( + stem: 'rust_lib_twonly', + ioDirectory: 'rust/target/release/', + webPrefix: 'pkg/', + ); +} + +abstract class RustLibApi extends BaseApi { + Future> crateTwonlyGetAllContacts(); + + Future crateTwonlyInitializeTwonly({required TwonlyConfig config}); +} + +class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { + RustLibApiImpl({ + required super.handler, + required super.wire, + required super.generalizedFrbRustBinding, + required super.portManager, + }); + + @override + Future> crateTwonlyGetAllContacts() { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 1, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_list_contact, + decodeErrorData: sse_decode_AnyhowException, + ), + constMeta: kCrateTwonlyGetAllContactsConstMeta, + argValues: [], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateTwonlyGetAllContactsConstMeta => const TaskConstMeta( + debugName: 'get_all_contacts', + argNames: [], + ); + + @override + Future crateTwonlyInitializeTwonly({required TwonlyConfig config}) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_box_autoadd_twonly_config(config, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 2, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_AnyhowException, + ), + constMeta: kCrateTwonlyInitializeTwonlyConstMeta, + argValues: [config], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateTwonlyInitializeTwonlyConstMeta => + const TaskConstMeta( + debugName: 'initialize_twonly', + argNames: ['config'], + ); + + @protected + AnyhowException dco_decode_AnyhowException(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return AnyhowException(raw as String); + } + + @protected + String dco_decode_String(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as String; + } + + @protected + TwonlyConfig dco_decode_box_autoadd_twonly_config(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dco_decode_twonly_config(raw); + } + + @protected + Contact dco_decode_contact(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 2) + throw Exception('unexpected arr length: expect 2 but see ${arr.length}'); + return Contact( + userId: dco_decode_i_64(arr[0]), + username: dco_decode_String(arr[1]), + ); + } + + @protected + PlatformInt64 dco_decode_i_64(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dcoDecodeI64(raw); + } + + @protected + List dco_decode_list_contact(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return (raw as List).map(dco_decode_contact).toList(); + } + + @protected + Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as Uint8List; + } + + @protected + TwonlyConfig dco_decode_twonly_config(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 1) + throw Exception('unexpected arr length: expect 1 but see ${arr.length}'); + return TwonlyConfig( + databasePath: dco_decode_String(arr[0]), + ); + } + + @protected + int dco_decode_u_8(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as int; + } + + @protected + void dco_decode_unit(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return; + } + + @protected + AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final inner = sse_decode_String(deserializer); + return AnyhowException(inner); + } + + @protected + String sse_decode_String(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final inner = sse_decode_list_prim_u_8_strict(deserializer); + return utf8.decoder.convert(inner); + } + + @protected + TwonlyConfig sse_decode_box_autoadd_twonly_config( + SseDeserializer deserializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + return sse_decode_twonly_config(deserializer); + } + + @protected + Contact sse_decode_contact(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final var_userId = sse_decode_i_64(deserializer); + final var_username = sse_decode_String(deserializer); + return Contact(userId: var_userId, username: var_username); + } + + @protected + PlatformInt64 sse_decode_i_64(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getPlatformInt64(); + } + + @protected + List sse_decode_list_contact(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + final len_ = sse_decode_i_32(deserializer); + final ans_ = []; + for (var idx_ = 0; idx_ < len_; ++idx_) { + ans_.add(sse_decode_contact(deserializer)); + } + return ans_; + } + + @protected + Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final len_ = sse_decode_i_32(deserializer); + return deserializer.buffer.getUint8List(len_); + } + + @protected + TwonlyConfig sse_decode_twonly_config(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final var_databasePath = sse_decode_String(deserializer); + return TwonlyConfig(databasePath: var_databasePath); + } + + @protected + int sse_decode_u_8(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint8(); + } + + @protected + void sse_decode_unit(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + } + + @protected + int sse_decode_i_32(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getInt32(); + } + + @protected + bool sse_decode_bool(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint8() != 0; + } + + @protected + void sse_encode_AnyhowException( + AnyhowException self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_String(self.message, serializer); + } + + @protected + void sse_encode_String(String self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer); + } + + @protected + void sse_encode_box_autoadd_twonly_config( + TwonlyConfig self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_twonly_config(self, serializer); + } + + @protected + void sse_encode_contact(Contact self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_64(self.userId, serializer); + sse_encode_String(self.username, serializer); + } + + @protected + void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putPlatformInt64(self); + } + + @protected + void sse_encode_list_contact(List self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + for (final item in self) { + sse_encode_contact(item, serializer); + } + } + + @protected + void sse_encode_list_prim_u_8_strict( + Uint8List self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + serializer.buffer.putUint8List(self); + } + + @protected + void sse_encode_twonly_config(TwonlyConfig self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_String(self.databasePath, serializer); + } + + @protected + void sse_encode_u_8(int self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint8(self); + } + + @protected + void sse_encode_unit(void self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + } + + @protected + void sse_encode_i_32(int self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putInt32(self); + } + + @protected + void sse_encode_bool(bool self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint8(self ? 1 : 0); + } +} diff --git a/lib/core/frb_generated.io.dart b/lib/core/frb_generated.io.dart new file mode 100644 index 00000000..93c3b489 --- /dev/null +++ b/lib/core/frb_generated.io.dart @@ -0,0 +1,151 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.12.0. + +// ignore_for_file: unused_import, non_constant_identifier_names, unused_field + +import 'dart:async'; +import 'dart:convert'; +import 'dart:ffi' as ffi; + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart'; + +import 'frb_generated.dart'; +import 'twonly.dart'; +import 'twonly/database/contact.dart'; + +abstract class RustLibApiImplPlatform extends BaseApiImpl { + RustLibApiImplPlatform({ + required super.handler, + required super.wire, + required super.generalizedFrbRustBinding, + required super.portManager, + }); + + @protected + AnyhowException dco_decode_AnyhowException(dynamic raw); + + @protected + String dco_decode_String(dynamic raw); + + @protected + TwonlyConfig dco_decode_box_autoadd_twonly_config(dynamic raw); + + @protected + Contact dco_decode_contact(dynamic raw); + + @protected + PlatformInt64 dco_decode_i_64(dynamic raw); + + @protected + List dco_decode_list_contact(dynamic raw); + + @protected + Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); + + @protected + TwonlyConfig dco_decode_twonly_config(dynamic raw); + + @protected + int dco_decode_u_8(dynamic raw); + + @protected + void dco_decode_unit(dynamic raw); + + @protected + AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer); + + @protected + String sse_decode_String(SseDeserializer deserializer); + + @protected + TwonlyConfig sse_decode_box_autoadd_twonly_config( + SseDeserializer deserializer, + ); + + @protected + Contact sse_decode_contact(SseDeserializer deserializer); + + @protected + PlatformInt64 sse_decode_i_64(SseDeserializer deserializer); + + @protected + List sse_decode_list_contact(SseDeserializer deserializer); + + @protected + Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); + + @protected + TwonlyConfig sse_decode_twonly_config(SseDeserializer deserializer); + + @protected + int sse_decode_u_8(SseDeserializer deserializer); + + @protected + void sse_decode_unit(SseDeserializer deserializer); + + @protected + int sse_decode_i_32(SseDeserializer deserializer); + + @protected + bool sse_decode_bool(SseDeserializer deserializer); + + @protected + void sse_encode_AnyhowException( + AnyhowException self, + SseSerializer serializer, + ); + + @protected + void sse_encode_String(String self, SseSerializer serializer); + + @protected + void sse_encode_box_autoadd_twonly_config( + TwonlyConfig self, + SseSerializer serializer, + ); + + @protected + void sse_encode_contact(Contact self, SseSerializer serializer); + + @protected + void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer); + + @protected + void sse_encode_list_contact(List self, SseSerializer serializer); + + @protected + void sse_encode_list_prim_u_8_strict( + Uint8List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_twonly_config(TwonlyConfig self, SseSerializer serializer); + + @protected + void sse_encode_u_8(int self, SseSerializer serializer); + + @protected + void sse_encode_unit(void self, SseSerializer serializer); + + @protected + void sse_encode_i_32(int self, SseSerializer serializer); + + @protected + void sse_encode_bool(bool self, SseSerializer serializer); +} + +// Section: wire_class + +class RustLibWire implements BaseWire { + /// The symbols are looked up in [dynamicLibrary]. + RustLibWire(ffi.DynamicLibrary dynamicLibrary) + : _lookup = dynamicLibrary.lookup; + + factory RustLibWire.fromExternalLibrary(ExternalLibrary lib) => + RustLibWire(lib.ffiDynamicLibrary); + + /// Holds the symbol lookup function. + final ffi.Pointer Function(String symbolName) + _lookup; +} diff --git a/lib/core/frb_generated.web.dart b/lib/core/frb_generated.web.dart new file mode 100644 index 00000000..e737ff43 --- /dev/null +++ b/lib/core/frb_generated.web.dart @@ -0,0 +1,150 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.12.0. + +// ignore_for_file: unused_import, non_constant_identifier_names + +// Static analysis wrongly picks the IO variant, thus ignore this + +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart'; + +import 'frb_generated.dart'; +import 'twonly.dart'; +import 'twonly/database/contact.dart'; + +abstract class RustLibApiImplPlatform extends BaseApiImpl { + RustLibApiImplPlatform({ + required super.handler, + required super.wire, + required super.generalizedFrbRustBinding, + required super.portManager, + }); + + @protected + AnyhowException dco_decode_AnyhowException(dynamic raw); + + @protected + String dco_decode_String(dynamic raw); + + @protected + TwonlyConfig dco_decode_box_autoadd_twonly_config(dynamic raw); + + @protected + Contact dco_decode_contact(dynamic raw); + + @protected + PlatformInt64 dco_decode_i_64(dynamic raw); + + @protected + List dco_decode_list_contact(dynamic raw); + + @protected + Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); + + @protected + TwonlyConfig dco_decode_twonly_config(dynamic raw); + + @protected + int dco_decode_u_8(dynamic raw); + + @protected + void dco_decode_unit(dynamic raw); + + @protected + AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer); + + @protected + String sse_decode_String(SseDeserializer deserializer); + + @protected + TwonlyConfig sse_decode_box_autoadd_twonly_config( + SseDeserializer deserializer, + ); + + @protected + Contact sse_decode_contact(SseDeserializer deserializer); + + @protected + PlatformInt64 sse_decode_i_64(SseDeserializer deserializer); + + @protected + List sse_decode_list_contact(SseDeserializer deserializer); + + @protected + Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); + + @protected + TwonlyConfig sse_decode_twonly_config(SseDeserializer deserializer); + + @protected + int sse_decode_u_8(SseDeserializer deserializer); + + @protected + void sse_decode_unit(SseDeserializer deserializer); + + @protected + int sse_decode_i_32(SseDeserializer deserializer); + + @protected + bool sse_decode_bool(SseDeserializer deserializer); + + @protected + void sse_encode_AnyhowException( + AnyhowException self, + SseSerializer serializer, + ); + + @protected + void sse_encode_String(String self, SseSerializer serializer); + + @protected + void sse_encode_box_autoadd_twonly_config( + TwonlyConfig self, + SseSerializer serializer, + ); + + @protected + void sse_encode_contact(Contact self, SseSerializer serializer); + + @protected + void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer); + + @protected + void sse_encode_list_contact(List self, SseSerializer serializer); + + @protected + void sse_encode_list_prim_u_8_strict( + Uint8List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_twonly_config(TwonlyConfig self, SseSerializer serializer); + + @protected + void sse_encode_u_8(int self, SseSerializer serializer); + + @protected + void sse_encode_unit(void self, SseSerializer serializer); + + @protected + void sse_encode_i_32(int self, SseSerializer serializer); + + @protected + void sse_encode_bool(bool self, SseSerializer serializer); +} + +// Section: wire_class + +class RustLibWire implements BaseWire { + RustLibWire.fromExternalLibrary(); +} + +@JS('wasm_bindgen') +external RustLibWasmModule get wasmModule; + +@JS() +@anonymous +extension type RustLibWasmModule._(JSObject _) implements JSObject {} diff --git a/lib/core/twonly.dart b/lib/core/twonly.dart new file mode 100644 index 00000000..65484480 --- /dev/null +++ b/lib/core/twonly.dart @@ -0,0 +1,35 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.12.0. + +// ignore_for_file: invalid_use_of_internal_member, unused_import + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +import 'frb_generated.dart'; +import 'twonly/database/contact.dart'; + +// These functions are ignored because they are not marked as `pub`: `get_instance` +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `Twonly` + +Future initializeTwonly({required TwonlyConfig config}) => + RustLib.instance.api.crateTwonlyInitializeTwonly(config: config); + +Future> getAllContacts() => + RustLib.instance.api.crateTwonlyGetAllContacts(); + +class TwonlyConfig { + const TwonlyConfig({ + required this.databasePath, + }); + final String databasePath; + + @override + int get hashCode => databasePath.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is TwonlyConfig && + runtimeType == other.runtimeType && + databasePath == other.databasePath; +} diff --git a/lib/core/twonly/database.dart b/lib/core/twonly/database.dart new file mode 100644 index 00000000..98b7e34b --- /dev/null +++ b/lib/core/twonly/database.dart @@ -0,0 +1,20 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.12.0. + +// ignore_for_file: unused_import + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +import '../frb_generated.dart'; + +// These functions are ignored because they are not marked as `pub`: `new` + +// Rust type: RustOpaqueMoi> +abstract class Database implements RustOpaqueInterface { + SqlitePool get pool; + + set pool(SqlitePool pool); +} + +// Rust type: RustOpaqueMoi> +abstract class SqlitePool implements RustOpaqueInterface {} diff --git a/lib/core/twonly/database/contact.dart b/lib/core/twonly/database/contact.dart new file mode 100644 index 00000000..aa7b3f4c --- /dev/null +++ b/lib/core/twonly/database/contact.dart @@ -0,0 +1,32 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.12.0. + +// ignore_for_file: unused_import + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +import '../../frb_generated.dart'; + +// These functions are ignored because they are not marked as `pub`: `get_all_contacts` +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `ContactRow` +// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `fmt`, `from_row`, `from` + +class Contact { + const Contact({ + required this.userId, + required this.username, + }); + final PlatformInt64 userId; + final String username; + + @override + int get hashCode => userId.hashCode ^ username.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Contact && + runtimeType == other.runtimeType && + userId == other.userId && + username == other.username; +} diff --git a/lib/main.dart b/lib/main.dart index f148c744..657ebabf 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,6 +7,8 @@ import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:twonly/app.dart'; +import 'package:twonly/core/frb_generated.dart'; +import 'package:twonly/core/twonly.dart' as core; import 'package:twonly/globals.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/providers/connection.provider.dart'; @@ -29,10 +31,18 @@ import 'package:twonly/src/utils/storage.dart'; void main() async { SentryWidgetsFlutterBinding.ensureInitialized(); + await RustLib.init(); + globalApplicationCacheDirectory = (await getApplicationCacheDirectory()).path; globalApplicationSupportDirectory = (await getApplicationSupportDirectory()).path; + await core.initializeTwonly( + config: core.TwonlyConfig( + databasePath: '$globalApplicationSupportDirectory/twonly.sqlite', + ), + ); + await initFCMService(); final user = await getUser(); diff --git a/lib/src/database/twonly.db.dart b/lib/src/database/twonly.db.dart index 9431a584..1fe3f517 100644 --- a/lib/src/database/twonly.db.dart +++ b/lib/src/database/twonly.db.dart @@ -67,9 +67,14 @@ class TwonlyDB extends _$TwonlyDB { static QueryExecutor _openConnection() { return driftDatabase( name: 'twonly', - native: const DriftNativeOptions( + native: DriftNativeOptions( databaseDirectory: getApplicationSupportDirectory, shareAcrossIsolates: true, + setup: (rawDb) { + rawDb + ..execute('PRAGMA journal_mode=WAL;') + ..execute('PRAGMA busy_timeout=5000;'); + }, ), ); } diff --git a/pubspec.lock b/pubspec.lock index 522e1cc5..4af8361e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -128,6 +128,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.5" + build_cli_annotations: + dependency: transitive + description: + name: build_cli_annotations + sha256: e563c2e01de8974566a1998410d3f6f03521788160a02503b0b1f1a46c7b3d95 + url: "https://pub.dev" + source: hosted + version: "2.1.1" build_config: dependency: transitive description: @@ -606,6 +614,11 @@ packages: url: "https://pub.dev" source: hosted version: "3.4.1" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" flutter_image_compress: dependency: "direct main" description: @@ -755,6 +768,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.34" + flutter_rust_bridge: + dependency: "direct main" + description: + name: flutter_rust_bridge + sha256: e87d6b9ee934dcd24a128ccb2bd91905d2d5fe5c06245d6a8f5477d4907a437a + url: "https://pub.dev" + source: hosted + version: "2.12.0" flutter_secure_storage: dependency: "direct main" description: @@ -844,6 +865,11 @@ packages: url: "https://pub.dev" source: hosted version: "10.12.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" gal: dependency: "direct main" description: @@ -1081,6 +1107,11 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.8+1" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" intl: dependency: "direct main" description: @@ -1513,6 +1544,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.14.2" + process: + dependency: transitive + description: + name: process + sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 + url: "https://pub.dev" + source: hosted + version: "5.0.5" protobuf: dependency: "direct main" description: @@ -1574,6 +1613,13 @@ packages: relative: true source: path version: "1.7.3" + rust_lib_twonly: + dependency: "direct main" + description: + path: rust_builder + relative: true + source: path + version: "0.0.1" rxdart: dependency: transitive description: @@ -1819,6 +1865,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" synchronized: dependency: transitive description: @@ -2051,6 +2105,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + webdriver: + dependency: transitive + description: + name: webdriver + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + url: "https://pub.dev" + source: hosted + version: "3.1.0" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 98816bc7..82a47b1e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -108,6 +108,9 @@ dependencies: google_mlkit_barcode_scanning: ^0.14.1 google_mlkit_face_detection: ^0.13.1 pro_video_editor: ^1.6.1 + rust_lib_twonly: + path: rust_builder + flutter_rust_bridge: 2.12.0 dependency_overrides: dots_indicator: @@ -174,6 +177,8 @@ dev_dependencies: json_serializable: ^6.8.0 very_good_analysis: ^10.0.0 in_app_purchase_platform_interface: ^1.4.0 + integration_test: + sdk: flutter flutter_launcher_icons: android: true diff --git a/rust/.gitignore b/rust/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/rust/.gitignore @@ -0,0 +1 @@ +/target diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 00000000..5276fa8d --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,2228 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "allo-isolate" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "449e356a4864c017286dbbec0e12767ea07efba29e3b7d984194c2a7ff3c4550" +dependencies = [ + "anyhow", + "atomic", + "backtrace", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_log-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" + +[[package]] +name = "android_logger" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb4e440d04be07da1f1bf44fb4495ebd58669372fe0cffa6e48595ac5bd88a3" +dependencies = [ + "android_log-sys", + "env_filter", + "log", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "build-target" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832133bbabbbaa9fbdba793456a2827627a7d2b8fb96032fa1e7666d7895832b" + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "windows-link", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dart-sys" +version = "4.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57967e4b200d767d091b961d6ab42cc7d0cc14fe9e052e75d0d3cf9eb732d895" +dependencies = [ + "cc", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "delegate-attr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51aac4c99b2e6775164b412ea33ae8441b2fde2dbf05a20bc0052a63d08c475b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "etcetera" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c7b13d0780cb82722fd59f6f57f925e143427e4a75313a6c77243bf5326ae6" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.59.0", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + +[[package]] +name = "flutter_rust_bridge" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0884853aae8a6517b5b58cf36f55da487f2fe110e1686938eb29b6640aae4a5" +dependencies = [ + "allo-isolate", + "android_logger", + "anyhow", + "build-target", + "bytemuck", + "byteorder", + "console_error_panic_hook", + "dart-sys", + "delegate-attr", + "flutter_rust_bridge_macros", + "futures", + "js-sys", + "lazy_static", + "log", + "oslog", + "portable-atomic", + "threadpool", + "tokio", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "flutter_rust_bridge_macros" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b5ce32f35f710ced8c5aa557f023f1a624e737b5460cee2b70fcd3a8df09e1b" +dependencies = [ + "hex", + "md-5", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "libc" +version = "0.2.184" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +dependencies = [ + "bitflags", + "libc", + "plain", + "redox_syscall 0.7.4", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "oslog" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d2043d1f61d77cb2f4b1f7b7b2295f40507f5f8e9d1c8bf10a1ca5f97a3969" +dependencies = [ + "cc", + "dashmap", + "log", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rust_lib_twonly" +version = "0.1.0" +dependencies = [ + "flutter_rust_bridge", + "sqlx", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlx" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "decccfa5f2f3eac95eb68085cfe69a0172fa9711666c3a634cfc806d4fb74a47" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86854e8c6aba0dafcf1c04b4836b0b7fa3a20c560e3554567afefe1258fa4e60" +dependencies = [ + "base64", + "bytes", + "cfg-if", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.16.1", + "hashlink", + "indexmap", + "log", + "memchr", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7aab9442ed1568e3aed6c368737226ee4e0e8d1deb0e0887fa6bf15282ace44" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34eb4976b8f02ac57ee98d4ce40cd1aad7ab31d9792977bc3171f787ba6ba2fb" +dependencies = [ + "cfg-if", + "dotenvy", + "either", + "heck", + "hex", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fef16f3d52a3710a672b48175b713e86476e2df85576a753c8b37ad11a483c0" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f053cf36ecb2793a9d9bb02d01bbad1ef66481d5db6ff5ab2dfb7b070cc0d13c" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "rand", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe2cd6cee87120b1e1dd31356b5589911995c777707e49f2750eec7c7fe43eef" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror", + "tracing", + "url", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "whoami" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 00000000..528bd713 --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "rust_lib_twonly" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "staticlib"] + +[dependencies] +flutter_rust_bridge = "=2.12.0" +thiserror = "2.0.18" +sqlx = { version = "0.9.0-alpha.1", default-features = false, features = [ + "runtime-tokio", + "sqlite", + "migrate", + "macros", + "chrono", + "derive", + "json", +] } +tokio = { version = "1.44", features = ["full"] } +tracing = "0.1.44" + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(frb_expand)'] } diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs new file mode 100644 index 00000000..60ced766 --- /dev/null +++ b/rust/src/frb_generated.rs @@ -0,0 +1,410 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.12.0. + +#![allow( + non_camel_case_types, + unused, + non_snake_case, + clippy::needless_return, + clippy::redundant_closure_call, + clippy::redundant_closure, + clippy::useless_conversion, + clippy::unit_arg, + clippy::unused_unit, + clippy::double_parens, + clippy::let_and_return, + clippy::too_many_arguments, + clippy::match_single_binding, + clippy::clone_on_copy, + clippy::let_unit_value, + clippy::deref_addrof, + clippy::explicit_auto_deref, + clippy::borrow_deref_ref, + clippy::uninlined_format_args, + clippy::needless_borrow +)] + +// Section: imports + +use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; +use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; +use flutter_rust_bridge::{Handler, IntoIntoDart}; + +// Section: boilerplate + +flutter_rust_bridge::frb_generated_boilerplate!( + default_stream_sink_codec = SseCodec, + default_rust_opaque = RustOpaqueMoi, + default_rust_auto_opaque = RustAutoOpaqueMoi, +); +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0"; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 741438464; + +// Section: executor + +flutter_rust_bridge::frb_generated_default_handler!(); + +// Section: wire_funcs + +fn wire__crate__twonly__get_all_contacts_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "get_all_contacts", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + deserializer.end(); + move |context| async move { + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || async move { + let output_ok = crate::twonly::get_all_contacts().await?; + Ok(output_ok) + })() + .await, + ) + } + }, + ) +} +fn wire__crate__twonly__initialize_twonly_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "initialize_twonly", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_config = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| async move { + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || async move { + let output_ok = crate::twonly::initialize_twonly(api_config).await?; + Ok(output_ok) + })() + .await, + ) + } + }, + ) +} + +// Section: dart2rust + +impl SseDecode for flutter_rust_bridge::for_generated::anyhow::Error { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = ::sse_decode(deserializer); + return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner); + } +} + +impl SseDecode for String { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = >::sse_decode(deserializer); + return String::from_utf8(inner).unwrap(); + } +} + +impl SseDecode for crate::twonly::database::contact::Contact { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_userId = ::sse_decode(deserializer); + let mut var_username = ::sse_decode(deserializer); + return crate::twonly::database::contact::Contact { + user_id: var_userId, + username: var_username, + }; + } +} + +impl SseDecode for i64 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_i64::().unwrap() + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = Vec::with_capacity(len_ as usize); + for idx_ in 0..len_ { + ans_.push(::sse_decode( + deserializer, + )); + } + return ans_; + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = Vec::with_capacity(len_ as usize); + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for crate::twonly::TwonlyConfig { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_databasePath = ::sse_decode(deserializer); + return crate::twonly::TwonlyConfig { + database_path: var_databasePath, + }; + } +} + +impl SseDecode for u8 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u8().unwrap() + } +} + +impl SseDecode for () { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {} +} + +impl SseDecode for i32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_i32::().unwrap() + } +} + +impl SseDecode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u8().unwrap() != 0 + } +} + +fn pde_ffi_dispatcher_primary_impl( + func_id: i32, + port: flutter_rust_bridge::for_generated::MessagePort, + ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len: i32, + data_len: i32, +) { + // Codec=Pde (Serialization + dispatch), see doc to use other codecs + match func_id { + 1 => wire__crate__twonly__get_all_contacts_impl(port, ptr, rust_vec_len, data_len), + 2 => wire__crate__twonly__initialize_twonly_impl(port, ptr, rust_vec_len, data_len), + _ => unreachable!(), + } +} + +fn pde_ffi_dispatcher_sync_impl( + func_id: i32, + ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len: i32, + data_len: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + // Codec=Pde (Serialization + dispatch), see doc to use other codecs + match func_id { + _ => unreachable!(), + } +} + +// Section: rust2dart + +// Codec=Dco (DartCObject based), see doc to use other codecs +impl flutter_rust_bridge::IntoDart for crate::twonly::database::contact::Contact { + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + [ + self.user_id.into_into_dart().into_dart(), + self.username.into_into_dart().into_dart(), + ] + .into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive + for crate::twonly::database::contact::Contact +{ +} +impl flutter_rust_bridge::IntoIntoDart + for crate::twonly::database::contact::Contact +{ + fn into_into_dart(self) -> crate::twonly::database::contact::Contact { + self + } +} +// Codec=Dco (DartCObject based), see doc to use other codecs +impl flutter_rust_bridge::IntoDart for crate::twonly::TwonlyConfig { + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + [self.database_path.into_into_dart().into_dart()].into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::twonly::TwonlyConfig {} +impl flutter_rust_bridge::IntoIntoDart + for crate::twonly::TwonlyConfig +{ + fn into_into_dart(self) -> crate::twonly::TwonlyConfig { + self + } +} + +impl SseEncode for flutter_rust_bridge::for_generated::anyhow::Error { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(format!("{:?}", self), serializer); + } +} + +impl SseEncode for String { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >::sse_encode(self.into_bytes(), serializer); + } +} + +impl SseEncode for crate::twonly::database::contact::Contact { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.user_id, serializer); + ::sse_encode(self.username, serializer); + } +} + +impl SseEncode for i64 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_i64::(self).unwrap(); + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); + } + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); + } + } +} + +impl SseEncode for crate::twonly::TwonlyConfig { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.database_path, serializer); + } +} + +impl SseEncode for u8 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u8(self).unwrap(); + } +} + +impl SseEncode for () { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {} +} + +impl SseEncode for i32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_i32::(self).unwrap(); + } +} + +impl SseEncode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u8(self as _).unwrap(); + } +} + +#[cfg(not(target_family = "wasm"))] +mod io { + // This file is automatically generated, so please do not edit it. + // @generated by `flutter_rust_bridge`@ 2.12.0. + + // Section: imports + + use super::*; + use flutter_rust_bridge::for_generated::byteorder::{ + NativeEndian, ReadBytesExt, WriteBytesExt, + }; + use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; + use flutter_rust_bridge::{Handler, IntoIntoDart}; + + // Section: boilerplate + + flutter_rust_bridge::frb_generated_boilerplate_io!(); +} +#[cfg(not(target_family = "wasm"))] +pub use io::*; + +/// cbindgen:ignore +#[cfg(target_family = "wasm")] +mod web { + // This file is automatically generated, so please do not edit it. + // @generated by `flutter_rust_bridge`@ 2.12.0. + + // Section: imports + + use super::*; + use flutter_rust_bridge::for_generated::byteorder::{ + NativeEndian, ReadBytesExt, WriteBytesExt, + }; + use flutter_rust_bridge::for_generated::wasm_bindgen; + use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*; + use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; + use flutter_rust_bridge::{Handler, IntoIntoDart}; + + // Section: boilerplate + + flutter_rust_bridge::frb_generated_boilerplate_web!(); +} +#[cfg(target_family = "wasm")] +pub use web::*; diff --git a/rust/src/lib.rs b/rust/src/lib.rs new file mode 100644 index 00000000..71cb3dfe --- /dev/null +++ b/rust/src/lib.rs @@ -0,0 +1,3 @@ +mod frb_generated; +mod twonly; +mod user_discovery; diff --git a/rust/src/twonly/database/contact.rs b/rust/src/twonly/database/contact.rs new file mode 100644 index 00000000..9d48df43 --- /dev/null +++ b/rust/src/twonly/database/contact.rs @@ -0,0 +1,40 @@ +// Table is defined in contacts.table.dart + +use sqlx::{ + types::chrono::{DateTime, Utc}, + FromRow, +}; + +use crate::twonly::{database::Database, error::Result}; + +#[derive(FromRow, Clone, Debug)] +struct ContactRow { + pub(crate) user_id: i64, + pub(crate) username: String, + pub(crate) created_at: DateTime, +} + +pub struct Contact { + pub user_id: i64, + pub username: String, + // pub created_at: DateTime, +} + +impl From for Contact { + fn from(row: ContactRow) -> Self { + Self { + user_id: row.user_id, + username: row.username, + // created_at: row.created_at, + } + } +} + +impl Contact { + pub(crate) async fn get_all_contacts(db: &Database) -> Result> { + let rows = sqlx::query_as::<_, ContactRow>("SELECT * FROM contacts") + .fetch_all(&db.pool) + .await?; + Ok(rows.into_iter().map(Into::into).collect()) + } +} diff --git a/rust/src/twonly/database/mod.rs b/rust/src/twonly/database/mod.rs new file mode 100644 index 00000000..d35dff71 --- /dev/null +++ b/rust/src/twonly/database/mod.rs @@ -0,0 +1,63 @@ +pub mod contact; + +use crate::twonly::error::TwonlyError; + +use super::error::Result; +use sqlx::{ + migrate::MigrateDatabase, + sqlite::{SqliteConnectOptions, SqlitePoolOptions}, + ConnectOptions, Sqlite, SqlitePool, +}; +use std::time::Duration; + +pub(crate) struct Database { + pub(crate) pool: SqlitePool, +} + +impl Database { + pub(crate) async fn new(db_path: &String) -> Result { + let db_url = format!("sqlite://{}", db_path); + + match Sqlite::database_exists(&db_url).await { + Ok(true) => { + tracing::debug!("database exists"); + } + Ok(false) => { + tracing::error!("could not open the sqlite3 database"); + return Err(TwonlyError::DatabaseNotFound); + } + Err(e) => { + tracing::error!( + "Could not check if database exists: {:?}, attempting to create", + e + ); + return Err(TwonlyError::DatabaseNotFound); + } + } + + tracing::debug!("Creating database connection pool"); + + let log_statements_level = if std::env::var("SQLX_LOG_STATEMENTS").is_ok() { + tracing::log::LevelFilter::Info + } else { + tracing::log::LevelFilter::Off + }; + + let connect_options = format!("{db_url}?mode=rwc") + .parse::()? + .log_statements(log_statements_level) + .journal_mode(sqlx::sqlite::SqliteJournalMode::Wal) + .foreign_keys(true) + .busy_timeout(Duration::from_millis(5000)) + .pragma("recursive_triggers", "ON") + .log_slow_statements(tracing::log::LevelFilter::Warn, Duration::from_millis(500)); + + let pool = SqlitePoolOptions::new() + .acquire_timeout(Duration::from_secs(5)) + .max_connections(10) + .connect_with(connect_options) + .await?; + + Ok(Self { pool: pool }) + } +} diff --git a/rust/src/twonly/error.rs b/rust/src/twonly/error.rs new file mode 100644 index 00000000..9838940e --- /dev/null +++ b/rust/src/twonly/error.rs @@ -0,0 +1,13 @@ +use thiserror::Error; + +pub type Result = core::result::Result; + +#[derive(Error, Debug)] +pub enum TwonlyError { + #[error("global twonly is not initialized")] + Initialization, + #[error("Could not find the given database")] + DatabaseNotFound, + #[error("sqlx error")] + SqliteError(#[from] sqlx::Error), +} diff --git a/rust/src/twonly/log/mod.rs b/rust/src/twonly/log/mod.rs new file mode 100644 index 00000000..dc1bdf26 --- /dev/null +++ b/rust/src/twonly/log/mod.rs @@ -0,0 +1,44 @@ +static TRACING_INIT: OnceLock<()> = OnceLock::new(); + +pub(crate) fn init_tracing(logs_dir: &std::path::Path) { + TRACING_INIT.get_or_init(|| { + let (non_blocking_stdout, non_blocking_file) = build_writers(logs_dir); + + let stdout_layer = Layer::new() + .with_writer(non_blocking_stdout) + .with_ansi(true) + .with_target(true); + + let file_layer = Layer::new() + .with_writer(non_blocking_file) + .with_ansi(false) + .with_target(true); + + Registry::default() + .with( + EnvFilter::try_from_default_env() + .unwrap_or_else(|_| EnvFilter::new("info,refinery_core=warn,refinery=warn")), + ) + .with(stdout_layer) + .with(file_layer) + .init(); + }); +} + +fn build_writers(logs_dir: &std::path::Path) -> (NonBlocking, NonBlocking) { + let file_appender = tracing_appender::rolling::RollingFileAppender::builder() + .rotation(tracing_appender::rolling::Rotation::DAILY) + .filename_prefix("whitenoise") + .filename_suffix("log") + .build(logs_dir) + .expect("Failed to create file appender"); + + let (non_blocking_file, file_guard) = tracing_appender::non_blocking(file_appender); + let (non_blocking_stdout, stdout_guard) = tracing_appender::non_blocking(std::io::stdout()); + + TRACING_GUARDS + .set(Mutex::new(Some((file_guard, stdout_guard)))) + .ok(); + + (non_blocking_stdout, non_blocking_file) +} diff --git a/rust/src/twonly/mod.rs b/rust/src/twonly/mod.rs new file mode 100644 index 00000000..9186868e --- /dev/null +++ b/rust/src/twonly/mod.rs @@ -0,0 +1,41 @@ +pub mod database; +pub mod error; +use crate::twonly::{database::contact::Contact, error::TwonlyError}; +use database::Database; +use error::Result; +use std::sync::Arc; +use tokio::sync::OnceCell; + +pub struct TwonlyConfig { + pub database_path: String, +} + +struct Twonly { + pub(crate) config: TwonlyConfig, + database: Arc, +} + +static GLOBAL_TWONLY: OnceCell = OnceCell::const_new(); + +fn get_instance() -> Result<&'static Twonly> { + GLOBAL_TWONLY.get().ok_or(TwonlyError::Initialization) +} + +pub async fn initialize_twonly(config: TwonlyConfig) -> Result<()> { + println!("initialized twonly"); + let twonly_res: Result<&'static Twonly> = GLOBAL_TWONLY + .get_or_try_init(|| async { + let database = Arc::new(Database::new(&config.database_path).await?); + Ok(Twonly { config, database }) + }) + .await; + + twonly_res?; + + Ok(()) +} + +pub async fn get_all_contacts() -> Result> { + let twonly = get_instance()?; + Contact::get_all_contacts(twonly.database.as_ref()).await +} diff --git a/rust/src/user_discovery/memory.rs b/rust/src/user_discovery/memory.rs new file mode 100644 index 00000000..e69de29b diff --git a/rust/src/user_discovery/mod.rs b/rust/src/user_discovery/mod.rs new file mode 100644 index 00000000..e69de29b diff --git a/rust_builder/.gitignore b/rust_builder/.gitignore new file mode 100644 index 00000000..ac5aa989 --- /dev/null +++ b/rust_builder/.gitignore @@ -0,0 +1,29 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ diff --git a/rust_builder/README.md b/rust_builder/README.md new file mode 100644 index 00000000..922615f9 --- /dev/null +++ b/rust_builder/README.md @@ -0,0 +1 @@ +Please ignore this folder, which is just glue to build Rust with Flutter. \ No newline at end of file diff --git a/rust_builder/android/.gitignore b/rust_builder/android/.gitignore new file mode 100644 index 00000000..161bdcda --- /dev/null +++ b/rust_builder/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.cxx diff --git a/rust_builder/android/build.gradle b/rust_builder/android/build.gradle new file mode 100644 index 00000000..484fdf6c --- /dev/null +++ b/rust_builder/android/build.gradle @@ -0,0 +1,56 @@ +// The Android Gradle Plugin builds the native code with the Android NDK. + +group 'com.flutter_rust_bridge.rust_lib_twonly' +version '1.0' + +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + // The Android Gradle Plugin knows how to build native code with the NDK. + classpath 'com.android.tools.build:gradle:7.3.0' + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' + +android { + if (project.android.hasProperty("namespace")) { + namespace 'com.flutter_rust_bridge.rust_lib_twonly' + } + + // Bumping the plugin compileSdkVersion requires all clients of this plugin + // to bump the version in their app. + compileSdkVersion 33 + + // Use the NDK version + // declared in /android/app/build.gradle file of the Flutter project. + // Replace it with a version number if this plugin requires a specfic NDK version. + // (e.g. ndkVersion "23.1.7779620") + ndkVersion android.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 19 + } +} + +apply from: "../cargokit/gradle/plugin.gradle" +cargokit { + manifestDir = "../../rust" + libname = "rust_lib_twonly" +} diff --git a/rust_builder/android/settings.gradle b/rust_builder/android/settings.gradle new file mode 100644 index 00000000..4ce498d0 --- /dev/null +++ b/rust_builder/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'rust_lib_twonly' diff --git a/rust_builder/android/src/main/AndroidManifest.xml b/rust_builder/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000..dd460d96 --- /dev/null +++ b/rust_builder/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/rust_builder/cargokit/.gitignore b/rust_builder/cargokit/.gitignore new file mode 100644 index 00000000..cf7bb868 --- /dev/null +++ b/rust_builder/cargokit/.gitignore @@ -0,0 +1,4 @@ +target +.dart_tool +*.iml +!pubspec.lock diff --git a/rust_builder/cargokit/LICENSE b/rust_builder/cargokit/LICENSE new file mode 100644 index 00000000..d33a5fea --- /dev/null +++ b/rust_builder/cargokit/LICENSE @@ -0,0 +1,42 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +Copyright 2022 Matej Knopp + +================================================================================ + +MIT LICENSE + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +================================================================================ + +APACHE LICENSE, VERSION 2.0 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/rust_builder/cargokit/README b/rust_builder/cargokit/README new file mode 100644 index 00000000..398474db --- /dev/null +++ b/rust_builder/cargokit/README @@ -0,0 +1,11 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +Experimental repository to provide glue for seamlessly integrating cargo build +with flutter plugins and packages. + +See https://matejknopp.com/post/flutter_plugin_in_rust_with_no_prebuilt_binaries/ +for a tutorial on how to use Cargokit. + +Example plugin available at https://github.com/irondash/hello_rust_ffi_plugin. + diff --git a/rust_builder/cargokit/build_pod.sh b/rust_builder/cargokit/build_pod.sh new file mode 100755 index 00000000..ed0e0d98 --- /dev/null +++ b/rust_builder/cargokit/build_pod.sh @@ -0,0 +1,58 @@ +#!/bin/sh +set -e + +BASEDIR=$(dirname "$0") + +# Workaround for https://github.com/dart-lang/pub/issues/4010 +BASEDIR=$(cd "$BASEDIR" ; pwd -P) + +# Remove XCode SDK from path. Otherwise this breaks tool compilation when building iOS project +NEW_PATH=`echo $PATH | tr ":" "\n" | grep -v "Contents/Developer/" | tr "\n" ":"` + +export PATH=${NEW_PATH%?} # remove trailing : + +env + +# Platform name (macosx, iphoneos, iphonesimulator) +export CARGOKIT_DARWIN_PLATFORM_NAME=$PLATFORM_NAME + +# Arctive architectures (arm64, armv7, x86_64), space separated. +export CARGOKIT_DARWIN_ARCHS=$ARCHS + +# Current build configuration (Debug, Release) +export CARGOKIT_CONFIGURATION=$CONFIGURATION + +# Path to directory containing Cargo.toml. +export CARGOKIT_MANIFEST_DIR=$PODS_TARGET_SRCROOT/$1 + +# Temporary directory for build artifacts. +export CARGOKIT_TARGET_TEMP_DIR=$TARGET_TEMP_DIR + +# Output directory for final artifacts. +export CARGOKIT_OUTPUT_DIR=$PODS_CONFIGURATION_BUILD_DIR/$PRODUCT_NAME + +# Directory to store built tool artifacts. +export CARGOKIT_TOOL_TEMP_DIR=$TARGET_TEMP_DIR/build_tool + +# Directory inside root project. Not necessarily the top level directory of root project. +export CARGOKIT_ROOT_PROJECT_DIR=$SRCROOT + +FLUTTER_EXPORT_BUILD_ENVIRONMENT=( + "$PODS_ROOT/../Flutter/ephemeral/flutter_export_environment.sh" # macOS + "$PODS_ROOT/../Flutter/flutter_export_environment.sh" # iOS +) + +for path in "${FLUTTER_EXPORT_BUILD_ENVIRONMENT[@]}" +do + if [[ -f "$path" ]]; then + source "$path" + fi +done + +sh "$BASEDIR/run_build_tool.sh" build-pod "$@" + +# Make a symlink from built framework to phony file, which will be used as input to +# build script. This should force rebuild (podspec currently doesn't support alwaysOutOfDate +# attribute on custom build phase) +ln -fs "$OBJROOT/XCBuildData/build.db" "${BUILT_PRODUCTS_DIR}/cargokit_phony" +ln -fs "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" "${BUILT_PRODUCTS_DIR}/cargokit_phony_out" diff --git a/rust_builder/cargokit/build_tool/README.md b/rust_builder/cargokit/build_tool/README.md new file mode 100644 index 00000000..a878c279 --- /dev/null +++ b/rust_builder/cargokit/build_tool/README.md @@ -0,0 +1,5 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +A sample command-line application with an entrypoint in `bin/`, library code +in `lib/`, and example unit test in `test/`. diff --git a/rust_builder/cargokit/build_tool/analysis_options.yaml b/rust_builder/cargokit/build_tool/analysis_options.yaml new file mode 100644 index 00000000..0e16a8b0 --- /dev/null +++ b/rust_builder/cargokit/build_tool/analysis_options.yaml @@ -0,0 +1,34 @@ +# This is copied from Cargokit (which is the official way to use it currently) +# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +linter: + rules: + - prefer_relative_imports + - directives_ordering + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/rust_builder/cargokit/build_tool/bin/build_tool.dart b/rust_builder/cargokit/build_tool/bin/build_tool.dart new file mode 100644 index 00000000..268eb524 --- /dev/null +++ b/rust_builder/cargokit/build_tool/bin/build_tool.dart @@ -0,0 +1,8 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'package:build_tool/build_tool.dart' as build_tool; + +void main(List arguments) { + build_tool.runMain(arguments); +} diff --git a/rust_builder/cargokit/build_tool/lib/build_tool.dart b/rust_builder/cargokit/build_tool/lib/build_tool.dart new file mode 100644 index 00000000..7c1bb750 --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/build_tool.dart @@ -0,0 +1,8 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'src/build_tool.dart' as build_tool; + +Future runMain(List args) async { + return build_tool.runMain(args); +} diff --git a/rust_builder/cargokit/build_tool/lib/src/android_environment.dart b/rust_builder/cargokit/build_tool/lib/src/android_environment.dart new file mode 100644 index 00000000..15fc9eed --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/android_environment.dart @@ -0,0 +1,195 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; +import 'dart:isolate'; +import 'dart:math' as math; + +import 'package:collection/collection.dart'; +import 'package:path/path.dart' as path; +import 'package:version/version.dart'; + +import 'target.dart'; +import 'util.dart'; + +class AndroidEnvironment { + AndroidEnvironment({ + required this.sdkPath, + required this.ndkVersion, + required this.minSdkVersion, + required this.targetTempDir, + required this.target, + }); + + static void clangLinkerWrapper(List args) { + final clang = Platform.environment['_CARGOKIT_NDK_LINK_CLANG']; + if (clang == null) { + throw Exception( + "cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_CLANG env var"); + } + final target = Platform.environment['_CARGOKIT_NDK_LINK_TARGET']; + if (target == null) { + throw Exception( + "cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_TARGET env var"); + } + + runCommand(clang, [ + target, + ...args, + ]); + } + + /// Full path to Android SDK. + final String sdkPath; + + /// Full version of Android NDK. + final String ndkVersion; + + /// Minimum supported SDK version. + final int minSdkVersion; + + /// Target directory for build artifacts. + final String targetTempDir; + + /// Target being built. + final Target target; + + bool ndkIsInstalled() { + final ndkPath = path.join(sdkPath, 'ndk', ndkVersion); + final ndkPackageXml = File(path.join(ndkPath, 'package.xml')); + return ndkPackageXml.existsSync(); + } + + void installNdk({ + required String javaHome, + }) { + final sdkManagerExtension = Platform.isWindows ? '.bat' : ''; + final sdkManager = path.join( + sdkPath, + 'cmdline-tools', + 'latest', + 'bin', + 'sdkmanager$sdkManagerExtension', + ); + + log.info('Installing NDK $ndkVersion'); + runCommand(sdkManager, [ + '--install', + 'ndk;$ndkVersion', + ], environment: { + 'JAVA_HOME': javaHome, + }); + } + + Future> buildEnvironment() async { + final hostArch = Platform.isMacOS + ? "darwin-x86_64" + : (Platform.isLinux ? "linux-x86_64" : "windows-x86_64"); + + final ndkPath = path.join(sdkPath, 'ndk', ndkVersion); + final toolchainPath = path.join( + ndkPath, + 'toolchains', + 'llvm', + 'prebuilt', + hostArch, + 'bin', + ); + + final minSdkVersion = + math.max(target.androidMinSdkVersion!, this.minSdkVersion); + + final exe = Platform.isWindows ? '.exe' : ''; + + final arKey = 'AR_${target.rust}'; + final arValue = ['${target.rust}-ar', 'llvm-ar', 'llvm-ar.exe'] + .map((e) => path.join(toolchainPath, e)) + .firstWhereOrNull((element) => File(element).existsSync()); + if (arValue == null) { + throw Exception('Failed to find ar for $target in $toolchainPath'); + } + + final targetArg = '--target=${target.rust}$minSdkVersion'; + + final ccKey = 'CC_${target.rust}'; + final ccValue = path.join(toolchainPath, 'clang$exe'); + final cfFlagsKey = 'CFLAGS_${target.rust}'; + final cFlagsValue = targetArg; + + final cxxKey = 'CXX_${target.rust}'; + final cxxValue = path.join(toolchainPath, 'clang++$exe'); + final cxxFlagsKey = 'CXXFLAGS_${target.rust}'; + final cxxFlagsValue = targetArg; + + final linkerKey = + 'cargo_target_${target.rust.replaceAll('-', '_')}_linker'.toUpperCase(); + + final ranlibKey = 'RANLIB_${target.rust}'; + final ranlibValue = path.join(toolchainPath, 'llvm-ranlib$exe'); + + final ndkVersionParsed = Version.parse(ndkVersion); + final rustFlagsKey = 'CARGO_ENCODED_RUSTFLAGS'; + final rustFlagsValue = _libGccWorkaround(targetTempDir, ndkVersionParsed); + + final runRustTool = + Platform.isWindows ? 'run_build_tool.cmd' : 'run_build_tool.sh'; + + final packagePath = (await Isolate.resolvePackageUri( + Uri.parse('package:build_tool/buildtool.dart')))! + .toFilePath(); + final selfPath = path.canonicalize(path.join( + packagePath, + '..', + '..', + '..', + runRustTool, + )); + + // Make sure that run_build_tool is working properly even initially launched directly + // through dart run. + final toolTempDir = + Platform.environment['CARGOKIT_TOOL_TEMP_DIR'] ?? targetTempDir; + + return { + arKey: arValue, + ccKey: ccValue, + cfFlagsKey: cFlagsValue, + cxxKey: cxxValue, + cxxFlagsKey: cxxFlagsValue, + ranlibKey: ranlibValue, + rustFlagsKey: rustFlagsValue, + linkerKey: selfPath, + // Recognized by main() so we know when we're acting as a wrapper + '_CARGOKIT_NDK_LINK_TARGET': targetArg, + '_CARGOKIT_NDK_LINK_CLANG': ccValue, + 'CARGOKIT_TOOL_TEMP_DIR': toolTempDir, + }; + } + + // Workaround for libgcc missing in NDK23, inspired by cargo-ndk + String _libGccWorkaround(String buildDir, Version ndkVersion) { + final workaroundDir = path.join( + buildDir, + 'cargokit', + 'libgcc_workaround', + '${ndkVersion.major}', + ); + Directory(workaroundDir).createSync(recursive: true); + if (ndkVersion.major >= 23) { + File(path.join(workaroundDir, 'libgcc.a')) + .writeAsStringSync('INPUT(-lunwind)'); + } else { + // Other way around, untested, forward libgcc.a from libunwind once Rust + // gets updated for NDK23+. + File(path.join(workaroundDir, 'libunwind.a')) + .writeAsStringSync('INPUT(-lgcc)'); + } + + var rustFlags = Platform.environment['CARGO_ENCODED_RUSTFLAGS'] ?? ''; + if (rustFlags.isNotEmpty) { + rustFlags = '$rustFlags\x1f'; + } + rustFlags = '$rustFlags-L\x1f$workaroundDir'; + return rustFlags; + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/artifacts_provider.dart b/rust_builder/cargokit/build_tool/lib/src/artifacts_provider.dart new file mode 100644 index 00000000..e608cece --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/artifacts_provider.dart @@ -0,0 +1,266 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:http/http.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'builder.dart'; +import 'crate_hash.dart'; +import 'options.dart'; +import 'precompile_binaries.dart'; +import 'rustup.dart'; +import 'target.dart'; + +class Artifact { + /// File system location of the artifact. + final String path; + + /// Actual file name that the artifact should have in destination folder. + final String finalFileName; + + AritifactType get type { + if (finalFileName.endsWith('.dll') || + finalFileName.endsWith('.dll.lib') || + finalFileName.endsWith('.pdb') || + finalFileName.endsWith('.so') || + finalFileName.endsWith('.dylib')) { + return AritifactType.dylib; + } else if (finalFileName.endsWith('.lib') || finalFileName.endsWith('.a')) { + return AritifactType.staticlib; + } else { + throw Exception('Unknown artifact type for $finalFileName'); + } + } + + Artifact({ + required this.path, + required this.finalFileName, + }); +} + +final _log = Logger('artifacts_provider'); + +class ArtifactProvider { + ArtifactProvider({ + required this.environment, + required this.userOptions, + }); + + final BuildEnvironment environment; + final CargokitUserOptions userOptions; + + Future>> getArtifacts(List targets) async { + final result = await _getPrecompiledArtifacts(targets); + + final pendingTargets = List.of(targets); + pendingTargets.removeWhere((element) => result.containsKey(element)); + + if (pendingTargets.isEmpty) { + return result; + } + + final rustup = Rustup(); + for (final target in targets) { + final builder = RustBuilder(target: target, environment: environment); + builder.prepare(rustup); + _log.info('Building ${environment.crateInfo.packageName} for $target'); + final targetDir = await builder.build(); + // For local build accept both static and dynamic libraries. + final artifactNames = { + ...getArtifactNames( + target: target, + libraryName: environment.crateInfo.packageName, + aritifactType: AritifactType.dylib, + remote: false, + ), + ...getArtifactNames( + target: target, + libraryName: environment.crateInfo.packageName, + aritifactType: AritifactType.staticlib, + remote: false, + ) + }; + final artifacts = artifactNames + .map((artifactName) => Artifact( + path: path.join(targetDir, artifactName), + finalFileName: artifactName, + )) + .where((element) => File(element.path).existsSync()) + .toList(); + result[target] = artifacts; + } + return result; + } + + Future>> _getPrecompiledArtifacts( + List targets) async { + if (userOptions.usePrecompiledBinaries == false) { + _log.info('Precompiled binaries are disabled'); + return {}; + } + if (environment.crateOptions.precompiledBinaries == null) { + _log.fine('Precompiled binaries not enabled for this crate'); + return {}; + } + + final start = Stopwatch()..start(); + final crateHash = CrateHash.compute(environment.manifestDir, + tempStorage: environment.targetTempDir); + _log.fine( + 'Computed crate hash $crateHash in ${start.elapsedMilliseconds}ms'); + + final downloadedArtifactsDir = + path.join(environment.targetTempDir, 'precompiled', crateHash); + Directory(downloadedArtifactsDir).createSync(recursive: true); + + final res = >{}; + + for (final target in targets) { + final requiredArtifacts = getArtifactNames( + target: target, + libraryName: environment.crateInfo.packageName, + remote: true, + ); + final artifactsForTarget = []; + + for (final artifact in requiredArtifacts) { + final fileName = PrecompileBinaries.fileName(target, artifact); + final downloadedPath = path.join(downloadedArtifactsDir, fileName); + if (!File(downloadedPath).existsSync()) { + final signatureFileName = + PrecompileBinaries.signatureFileName(target, artifact); + await _tryDownloadArtifacts( + crateHash: crateHash, + fileName: fileName, + signatureFileName: signatureFileName, + finalPath: downloadedPath, + ); + } + if (File(downloadedPath).existsSync()) { + artifactsForTarget.add(Artifact( + path: downloadedPath, + finalFileName: artifact, + )); + } else { + break; + } + } + + // Only provide complete set of artifacts. + if (artifactsForTarget.length == requiredArtifacts.length) { + _log.fine('Found precompiled artifacts for $target'); + res[target] = artifactsForTarget; + } + } + + return res; + } + + static Future _get(Uri url, {Map? headers}) async { + int attempt = 0; + const maxAttempts = 10; + while (true) { + try { + return await get(url, headers: headers); + } on SocketException catch (e) { + // Try to detect reset by peer error and retry. + if (attempt++ < maxAttempts && + (e.osError?.errorCode == 54 || e.osError?.errorCode == 10054)) { + _log.severe( + 'Failed to download $url: $e, attempt $attempt of $maxAttempts, will retry...'); + await Future.delayed(Duration(seconds: 1)); + continue; + } else { + rethrow; + } + } + } + } + + Future _tryDownloadArtifacts({ + required String crateHash, + required String fileName, + required String signatureFileName, + required String finalPath, + }) async { + final precompiledBinaries = environment.crateOptions.precompiledBinaries!; + final prefix = precompiledBinaries.uriPrefix; + final url = Uri.parse('$prefix$crateHash/$fileName'); + final signatureUrl = Uri.parse('$prefix$crateHash/$signatureFileName'); + _log.fine('Downloading signature from $signatureUrl'); + final signature = await _get(signatureUrl); + if (signature.statusCode == 404) { + _log.warning( + 'Precompiled binaries not available for crate hash $crateHash ($fileName)'); + return; + } + if (signature.statusCode != 200) { + _log.severe( + 'Failed to download signature $signatureUrl: status ${signature.statusCode}'); + return; + } + _log.fine('Downloading binary from $url'); + final res = await _get(url); + if (res.statusCode != 200) { + _log.severe('Failed to download binary $url: status ${res.statusCode}'); + return; + } + if (verify( + precompiledBinaries.publicKey, res.bodyBytes, signature.bodyBytes)) { + File(finalPath).writeAsBytesSync(res.bodyBytes); + } else { + _log.shout('Signature verification failed! Ignoring binary.'); + } + } +} + +enum AritifactType { + staticlib, + dylib, +} + +AritifactType artifactTypeForTarget(Target target) { + if (target.darwinPlatform != null) { + return AritifactType.staticlib; + } else { + return AritifactType.dylib; + } +} + +List getArtifactNames({ + required Target target, + required String libraryName, + required bool remote, + AritifactType? aritifactType, +}) { + aritifactType ??= artifactTypeForTarget(target); + if (target.darwinArch != null) { + if (aritifactType == AritifactType.staticlib) { + return ['lib$libraryName.a']; + } else { + return ['lib$libraryName.dylib']; + } + } else if (target.rust.contains('-windows-')) { + if (aritifactType == AritifactType.staticlib) { + return ['$libraryName.lib']; + } else { + return [ + '$libraryName.dll', + '$libraryName.dll.lib', + if (!remote) '$libraryName.pdb' + ]; + } + } else if (target.rust.contains('-linux-')) { + if (aritifactType == AritifactType.staticlib) { + return ['lib$libraryName.a']; + } else { + return ['lib$libraryName.so']; + } + } else { + throw Exception("Unsupported target: ${target.rust}"); + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/build_cmake.dart b/rust_builder/cargokit/build_tool/lib/src/build_cmake.dart new file mode 100644 index 00000000..6f3b2a4e --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/build_cmake.dart @@ -0,0 +1,40 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'target.dart'; + +class BuildCMake { + final CargokitUserOptions userOptions; + + BuildCMake({required this.userOptions}); + + Future build() async { + final targetPlatform = Environment.targetPlatform; + final target = Target.forFlutterName(Environment.targetPlatform); + if (target == null) { + throw Exception("Unknown target platform: $targetPlatform"); + } + + final environment = BuildEnvironment.fromEnvironment(isAndroid: false); + final provider = + ArtifactProvider(environment: environment, userOptions: userOptions); + final artifacts = await provider.getArtifacts([target]); + + final libs = artifacts[target]!; + + for (final lib in libs) { + if (lib.type == AritifactType.dylib) { + File(lib.path) + .copySync(path.join(Environment.outputDir, lib.finalFileName)); + } + } + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/build_gradle.dart b/rust_builder/cargokit/build_tool/lib/src/build_gradle.dart new file mode 100644 index 00000000..7e61fcbb --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/build_gradle.dart @@ -0,0 +1,49 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'target.dart'; + +final log = Logger('build_gradle'); + +class BuildGradle { + BuildGradle({required this.userOptions}); + + final CargokitUserOptions userOptions; + + Future build() async { + final targets = Environment.targetPlatforms.map((arch) { + final target = Target.forFlutterName(arch); + if (target == null) { + throw Exception( + "Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}"); + } + return target; + }).toList(); + + final environment = BuildEnvironment.fromEnvironment(isAndroid: true); + final provider = + ArtifactProvider(environment: environment, userOptions: userOptions); + final artifacts = await provider.getArtifacts(targets); + + for (final target in targets) { + final libs = artifacts[target]!; + final outputDir = path.join(Environment.outputDir, target.android!); + Directory(outputDir).createSync(recursive: true); + + for (final lib in libs) { + if (lib.type == AritifactType.dylib) { + File(lib.path).copySync(path.join(outputDir, lib.finalFileName)); + } + } + } + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/build_pod.dart b/rust_builder/cargokit/build_tool/lib/src/build_pod.dart new file mode 100644 index 00000000..8a9c0db5 --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/build_pod.dart @@ -0,0 +1,89 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'target.dart'; +import 'util.dart'; + +class BuildPod { + BuildPod({required this.userOptions}); + + final CargokitUserOptions userOptions; + + Future build() async { + final targets = Environment.darwinArchs.map((arch) { + final target = Target.forDarwin( + platformName: Environment.darwinPlatformName, darwinAarch: arch); + if (target == null) { + throw Exception( + "Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}"); + } + return target; + }).toList(); + + final environment = BuildEnvironment.fromEnvironment(isAndroid: false); + final provider = + ArtifactProvider(environment: environment, userOptions: userOptions); + final artifacts = await provider.getArtifacts(targets); + + void performLipo(String targetFile, Iterable sourceFiles) { + runCommand("lipo", [ + '-create', + ...sourceFiles, + '-output', + targetFile, + ]); + } + + final outputDir = Environment.outputDir; + + Directory(outputDir).createSync(recursive: true); + + final staticLibs = artifacts.values + .expand((element) => element) + .where((element) => element.type == AritifactType.staticlib) + .toList(); + final dynamicLibs = artifacts.values + .expand((element) => element) + .where((element) => element.type == AritifactType.dylib) + .toList(); + + final libName = environment.crateInfo.packageName; + + // If there is static lib, use it and link it with pod + if (staticLibs.isNotEmpty) { + final finalTargetFile = path.join(outputDir, "lib$libName.a"); + performLipo(finalTargetFile, staticLibs.map((e) => e.path)); + } else { + // Otherwise try to replace bundle dylib with our dylib + final bundlePaths = [ + '$libName.framework/Versions/A/$libName', + '$libName.framework/$libName', + ]; + + for (final bundlePath in bundlePaths) { + final targetFile = path.join(outputDir, bundlePath); + if (File(targetFile).existsSync()) { + performLipo(targetFile, dynamicLibs.map((e) => e.path)); + + // Replace absolute id with @rpath one so that it works properly + // when moved to Frameworks. + runCommand("install_name_tool", [ + '-id', + '@rpath/$bundlePath', + targetFile, + ]); + return; + } + } + throw Exception('Unable to find bundle for dynamic library'); + } + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/build_tool.dart b/rust_builder/cargokit/build_tool/lib/src/build_tool.dart new file mode 100644 index 00000000..70dfe0eb --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/build_tool.dart @@ -0,0 +1,276 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:github/github.dart'; +import 'package:hex/hex.dart'; +import 'package:logging/logging.dart'; + +import 'android_environment.dart'; +import 'build_cmake.dart'; +import 'build_gradle.dart'; +import 'build_pod.dart'; +import 'logging.dart'; +import 'options.dart'; +import 'precompile_binaries.dart'; +import 'target.dart'; +import 'util.dart'; +import 'verify_binaries.dart'; + +final log = Logger('build_tool'); + +abstract class BuildCommand extends Command { + Future runBuildCommand(CargokitUserOptions options); + + @override + Future run() async { + final options = CargokitUserOptions.load(); + + if (options.verboseLogging || + Platform.environment['CARGOKIT_VERBOSE'] == '1') { + enableVerboseLogging(); + } + + await runBuildCommand(options); + } +} + +class BuildPodCommand extends BuildCommand { + @override + final name = 'build-pod'; + + @override + final description = 'Build cocoa pod library'; + + @override + Future runBuildCommand(CargokitUserOptions options) async { + final build = BuildPod(userOptions: options); + await build.build(); + } +} + +class BuildGradleCommand extends BuildCommand { + @override + final name = 'build-gradle'; + + @override + final description = 'Build android library'; + + @override + Future runBuildCommand(CargokitUserOptions options) async { + final build = BuildGradle(userOptions: options); + await build.build(); + } +} + +class BuildCMakeCommand extends BuildCommand { + @override + final name = 'build-cmake'; + + @override + final description = 'Build CMake library'; + + @override + Future runBuildCommand(CargokitUserOptions options) async { + final build = BuildCMake(userOptions: options); + await build.build(); + } +} + +class GenKeyCommand extends Command { + @override + final name = 'gen-key'; + + @override + final description = 'Generate key pair for signing precompiled binaries'; + + @override + void run() { + final kp = generateKey(); + final private = HEX.encode(kp.privateKey.bytes); + final public = HEX.encode(kp.publicKey.bytes); + print("Private Key: $private"); + print("Public Key: $public"); + } +} + +class PrecompileBinariesCommand extends Command { + PrecompileBinariesCommand() { + argParser + ..addOption( + 'repository', + mandatory: true, + help: 'Github repository slug in format owner/name', + ) + ..addOption( + 'manifest-dir', + mandatory: true, + help: 'Directory containing Cargo.toml', + ) + ..addMultiOption('target', + help: 'Rust target triple of artifact to build.\n' + 'Can be specified multiple times or omitted in which case\n' + 'all targets for current platform will be built.') + ..addOption( + 'android-sdk-location', + help: 'Location of Android SDK (if available)', + ) + ..addOption( + 'android-ndk-version', + help: 'Android NDK version (if available)', + ) + ..addOption( + 'android-min-sdk-version', + help: 'Android minimum rquired version (if available)', + ) + ..addOption( + 'temp-dir', + help: 'Directory to store temporary build artifacts', + ) + ..addOption( + 'glibc-version', + help: 'GLIBC version to use for linux builds', + ) + ..addFlag( + "verbose", + abbr: "v", + defaultsTo: false, + help: "Enable verbose logging", + ); + } + + @override + final name = 'precompile-binaries'; + + @override + final description = 'Prebuild and upload binaries\n' + 'Private key must be passed through PRIVATE_KEY environment variable. ' + 'Use gen_key through generate priave key.\n' + 'Github token must be passed as GITHUB_TOKEN environment variable.\n'; + + @override + Future run() async { + final verbose = argResults!['verbose'] as bool; + if (verbose) { + enableVerboseLogging(); + } + + final privateKeyString = Platform.environment['PRIVATE_KEY']; + if (privateKeyString == null) { + throw ArgumentError('Missing PRIVATE_KEY environment variable'); + } + final githubToken = Platform.environment['GITHUB_TOKEN']; + if (githubToken == null) { + throw ArgumentError('Missing GITHUB_TOKEN environment variable'); + } + final privateKey = HEX.decode(privateKeyString); + if (privateKey.length != 64) { + throw ArgumentError('Private key must be 64 bytes long'); + } + final manifestDir = argResults!['manifest-dir'] as String; + if (!Directory(manifestDir).existsSync()) { + throw ArgumentError('Manifest directory does not exist: $manifestDir'); + } + String? androidMinSdkVersionString = + argResults!['android-min-sdk-version'] as String?; + int? androidMinSdkVersion; + if (androidMinSdkVersionString != null) { + androidMinSdkVersion = int.tryParse(androidMinSdkVersionString); + if (androidMinSdkVersion == null) { + throw ArgumentError( + 'Invalid android-min-sdk-version: $androidMinSdkVersionString'); + } + } + final targetStrigns = argResults!['target'] as List; + final targets = targetStrigns.map((target) { + final res = Target.forRustTriple(target); + if (res == null) { + throw ArgumentError('Invalid target: $target'); + } + return res; + }).toList(growable: false); + final precompileBinaries = PrecompileBinaries( + privateKey: PrivateKey(privateKey), + githubToken: githubToken, + manifestDir: manifestDir, + repositorySlug: RepositorySlug.full(argResults!['repository'] as String), + targets: targets, + androidSdkLocation: argResults!['android-sdk-location'] as String?, + androidNdkVersion: argResults!['android-ndk-version'] as String?, + androidMinSdkVersion: androidMinSdkVersion, + tempDir: argResults!['temp-dir'] as String?, + glibcVersion: argResults!['glibc-version'] as String?, + ); + + await precompileBinaries.run(); + } +} + +class VerifyBinariesCommand extends Command { + VerifyBinariesCommand() { + argParser.addOption( + 'manifest-dir', + mandatory: true, + help: 'Directory containing Cargo.toml', + ); + } + + @override + final name = "verify-binaries"; + + @override + final description = 'Verifies published binaries\n' + 'Checks whether there is a binary published for each targets\n' + 'and checks the signature.'; + + @override + Future run() async { + final manifestDir = argResults!['manifest-dir'] as String; + final verifyBinaries = VerifyBinaries( + manifestDir: manifestDir, + ); + await verifyBinaries.run(); + } +} + +Future runMain(List args) async { + try { + // Init logging before options are loaded + initLogging(); + + if (Platform.environment['_CARGOKIT_NDK_LINK_TARGET'] != null) { + return AndroidEnvironment.clangLinkerWrapper(args); + } + + final runner = CommandRunner('build_tool', 'Cargokit built_tool') + ..addCommand(BuildPodCommand()) + ..addCommand(BuildGradleCommand()) + ..addCommand(BuildCMakeCommand()) + ..addCommand(GenKeyCommand()) + ..addCommand(PrecompileBinariesCommand()) + ..addCommand(VerifyBinariesCommand()); + + await runner.run(args); + } on ArgumentError catch (e) { + stderr.writeln(e.toString()); + exit(1); + } catch (e, s) { + log.severe(kDoubleSeparator); + log.severe('Cargokit BuildTool failed with error:'); + log.severe(kSeparator); + log.severe(e); + // This tells user to install Rust, there's no need to pollute the log with + // stack trace. + if (e is! RustupNotFoundException) { + log.severe(kSeparator); + log.severe(s); + log.severe(kSeparator); + log.severe('BuildTool arguments: $args'); + } + log.severe(kDoubleSeparator); + exit(1); + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/builder.dart b/rust_builder/cargokit/build_tool/lib/src/builder.dart new file mode 100644 index 00000000..cd5269f1 --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/builder.dart @@ -0,0 +1,209 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'package:collection/collection.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'android_environment.dart'; +import 'cargo.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'rustup.dart'; +import 'target.dart'; +import 'util.dart'; + +final _log = Logger('builder'); + +enum BuildConfiguration { + debug, + release, + profile, +} + +extension on BuildConfiguration { + bool get isDebug => this == BuildConfiguration.debug; + String get rustName => switch (this) { + BuildConfiguration.debug => 'debug', + BuildConfiguration.release => 'release', + BuildConfiguration.profile => 'release', + }; +} + +class BuildException implements Exception { + final String message; + + BuildException(this.message); + + @override + String toString() { + return 'BuildException: $message'; + } +} + +class BuildEnvironment { + final BuildConfiguration configuration; + final CargokitCrateOptions crateOptions; + final String targetTempDir; + final String manifestDir; + final CrateInfo crateInfo; + + final bool isAndroid; + final String? androidSdkPath; + final String? androidNdkVersion; + final int? androidMinSdkVersion; + final String? javaHome; + + final String? glibcVersion; + + BuildEnvironment({ + required this.configuration, + required this.crateOptions, + required this.targetTempDir, + required this.manifestDir, + required this.crateInfo, + required this.isAndroid, + this.androidSdkPath, + this.androidNdkVersion, + this.androidMinSdkVersion, + this.javaHome, + this.glibcVersion, + }); + + static BuildConfiguration parseBuildConfiguration(String value) { + // XCode configuration adds the flavor to configuration name. + final firstSegment = value.split('-').first; + final buildConfiguration = BuildConfiguration.values.firstWhereOrNull( + (e) => e.name == firstSegment, + ); + if (buildConfiguration == null) { + _log.warning('Unknown build configuraiton $value, will assume release'); + return BuildConfiguration.release; + } + return buildConfiguration; + } + + static BuildEnvironment fromEnvironment({ + required bool isAndroid, + }) { + final buildConfiguration = + parseBuildConfiguration(Environment.configuration); + final manifestDir = Environment.manifestDir; + final crateOptions = CargokitCrateOptions.load( + manifestDir: manifestDir, + ); + final crateInfo = CrateInfo.load(manifestDir); + return BuildEnvironment( + configuration: buildConfiguration, + crateOptions: crateOptions, + targetTempDir: Environment.targetTempDir, + manifestDir: manifestDir, + crateInfo: crateInfo, + isAndroid: isAndroid, + androidSdkPath: isAndroid ? Environment.sdkPath : null, + androidNdkVersion: isAndroid ? Environment.ndkVersion : null, + androidMinSdkVersion: + isAndroid ? int.parse(Environment.minSdkVersion) : null, + javaHome: isAndroid ? Environment.javaHome : null, + ); + } +} + +class RustBuilder { + final Target target; + final BuildEnvironment environment; + + RustBuilder({ + required this.target, + required this.environment, + }); + + void prepare( + Rustup rustup, + ) { + final toolchain = _toolchain; + if (rustup.installedTargets(toolchain) == null) { + rustup.installToolchain(toolchain); + } + if (toolchain == 'nightly') { + rustup.installRustSrcForNightly(); + } + if (!rustup.installedTargets(toolchain)!.contains(target.rust)) { + rustup.installTarget(target.rust, toolchain: toolchain); + } + if (environment.glibcVersion != null) { + rustup.installZigBuild(toolchain); + } + } + + CargoBuildOptions? get _buildOptions => + environment.crateOptions.cargo[environment.configuration]; + + String get _toolchain => _buildOptions?.toolchain.name ?? 'stable'; + + /// Returns the path of directory containing build artifacts. + Future build() async { + final extraArgs = _buildOptions?.flags ?? []; + final manifestPath = path.join(environment.manifestDir, 'Cargo.toml'); + runCommand( + 'rustup', + [ + 'run', + _toolchain, + 'cargo', + (target.android == null && environment.glibcVersion != null) + ? 'zigbuild' + : 'build', + ...extraArgs, + '--manifest-path', + manifestPath, + '-p', + environment.crateInfo.packageName, + if (!environment.configuration.isDebug) '--release', + '--target', + target.rust + + ((target.android == null && environment.glibcVersion != null) + ? '.${environment.glibcVersion!}' + : ""), + '--target-dir', + environment.targetTempDir, + ], + environment: await _buildEnvironment(), + ); + return path.join( + environment.targetTempDir, + target.rust, + environment.configuration.rustName, + ); + } + + Future> _buildEnvironment() async { + if (target.android == null) { + return {}; + } else { + final sdkPath = environment.androidSdkPath; + final ndkVersion = environment.androidNdkVersion; + final minSdkVersion = environment.androidMinSdkVersion; + if (sdkPath == null) { + throw BuildException('androidSdkPath is not set'); + } + if (ndkVersion == null) { + throw BuildException('androidNdkVersion is not set'); + } + if (minSdkVersion == null) { + throw BuildException('androidMinSdkVersion is not set'); + } + final env = AndroidEnvironment( + sdkPath: sdkPath, + ndkVersion: ndkVersion, + minSdkVersion: minSdkVersion, + targetTempDir: environment.targetTempDir, + target: target, + ); + if (!env.ndkIsInstalled() && environment.javaHome != null) { + env.installNdk(javaHome: environment.javaHome!); + } + return env.buildEnvironment(); + } + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/cargo.dart b/rust_builder/cargokit/build_tool/lib/src/cargo.dart new file mode 100644 index 00000000..0d8958ff --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/cargo.dart @@ -0,0 +1,48 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:path/path.dart' as path; +import 'package:toml/toml.dart'; + +class ManifestException { + ManifestException(this.message, {required this.fileName}); + + final String? fileName; + final String message; + + @override + String toString() { + if (fileName != null) { + return 'Failed to parse package manifest at $fileName: $message'; + } else { + return 'Failed to parse package manifest: $message'; + } + } +} + +class CrateInfo { + CrateInfo({required this.packageName}); + + final String packageName; + + static CrateInfo parseManifest(String manifest, {final String? fileName}) { + final toml = TomlDocument.parse(manifest); + final package = toml.toMap()['package']; + if (package == null) { + throw ManifestException('Missing package section', fileName: fileName); + } + final name = package['name']; + if (name == null) { + throw ManifestException('Missing package name', fileName: fileName); + } + return CrateInfo(packageName: name); + } + + static CrateInfo load(String manifestDir) { + final manifestFile = File(path.join(manifestDir, 'Cargo.toml')); + final manifest = manifestFile.readAsStringSync(); + return parseManifest(manifest, fileName: manifestFile.path); + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/crate_hash.dart b/rust_builder/cargokit/build_tool/lib/src/crate_hash.dart new file mode 100644 index 00000000..0c4d88d1 --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/crate_hash.dart @@ -0,0 +1,124 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:collection/collection.dart'; +import 'package:convert/convert.dart'; +import 'package:crypto/crypto.dart'; +import 'package:path/path.dart' as path; + +class CrateHash { + /// Computes a hash uniquely identifying crate content. This takes into account + /// content all all .rs files inside the src directory, as well as Cargo.toml, + /// Cargo.lock, build.rs and cargokit.yaml. + /// + /// If [tempStorage] is provided, computed hash is stored in a file in that directory + /// and reused on subsequent calls if the crate content hasn't changed. + static String compute(String manifestDir, {String? tempStorage}) { + return CrateHash._( + manifestDir: manifestDir, + tempStorage: tempStorage, + )._compute(); + } + + CrateHash._({ + required this.manifestDir, + required this.tempStorage, + }); + + String _compute() { + final files = getFiles(); + final tempStorage = this.tempStorage; + if (tempStorage != null) { + final quickHash = _computeQuickHash(files); + final quickHashFolder = Directory(path.join(tempStorage, 'crate_hash')); + quickHashFolder.createSync(recursive: true); + final quickHashFile = File(path.join(quickHashFolder.path, quickHash)); + if (quickHashFile.existsSync()) { + return quickHashFile.readAsStringSync(); + } + final hash = _computeHash(files); + quickHashFile.writeAsStringSync(hash); + return hash; + } else { + return _computeHash(files); + } + } + + /// Computes a quick hash based on files stat (without reading contents). This + /// is used to cache the real hash, which is slower to compute since it involves + /// reading every single file. + String _computeQuickHash(List files) { + final output = AccumulatorSink(); + final input = sha256.startChunkedConversion(output); + + final data = ByteData(8); + for (final file in files) { + input.add(utf8.encode(file.path)); + final stat = file.statSync(); + data.setUint64(0, stat.size); + input.add(data.buffer.asUint8List()); + data.setUint64(0, stat.modified.millisecondsSinceEpoch); + input.add(data.buffer.asUint8List()); + } + + input.close(); + return base64Url.encode(output.events.single.bytes); + } + + String _computeHash(List files) { + final output = AccumulatorSink(); + final input = sha256.startChunkedConversion(output); + + void addTextFile(File file) { + // text Files are hashed by lines in case we're dealing with github checkout + // that auto-converts line endings. + final splitter = LineSplitter(); + if (file.existsSync()) { + final data = file.readAsStringSync(); + final lines = splitter.convert(data); + for (final line in lines) { + input.add(utf8.encode(line)); + } + } + } + + for (final file in files) { + addTextFile(file); + } + + input.close(); + final res = output.events.single; + + // Truncate to 128bits. + final hash = res.bytes.sublist(0, 16); + return hex.encode(hash); + } + + List getFiles() { + final src = Directory(path.join(manifestDir, 'src')); + final files = src + .listSync(recursive: true, followLinks: false) + .whereType() + .toList(); + files.sortBy((element) => element.path); + void addFile(String relative) { + final file = File(path.join(manifestDir, relative)); + if (file.existsSync()) { + files.add(file); + } + } + + addFile('Cargo.toml'); + addFile('Cargo.lock'); + addFile('build.rs'); + addFile('cargokit.yaml'); + return files; + } + + final String manifestDir; + final String? tempStorage; +} diff --git a/rust_builder/cargokit/build_tool/lib/src/environment.dart b/rust_builder/cargokit/build_tool/lib/src/environment.dart new file mode 100644 index 00000000..996483a1 --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/environment.dart @@ -0,0 +1,68 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +extension on String { + String resolveSymlink() => File(this).resolveSymbolicLinksSync(); +} + +class Environment { + /// Current build configuration (debug or release). + static String get configuration => + _getEnv("CARGOKIT_CONFIGURATION").toLowerCase(); + + static bool get isDebug => configuration == 'debug'; + static bool get isRelease => configuration == 'release'; + + /// Temporary directory where Rust build artifacts are placed. + static String get targetTempDir => _getEnv("CARGOKIT_TARGET_TEMP_DIR"); + + /// Final output directory where the build artifacts are placed. + static String get outputDir => _getEnvPath('CARGOKIT_OUTPUT_DIR'); + + /// Path to the crate manifest (containing Cargo.toml). + static String get manifestDir => _getEnvPath('CARGOKIT_MANIFEST_DIR'); + + /// Directory inside root project. Not necessarily root folder. Symlinks are + /// not resolved on purpose. + static String get rootProjectDir => _getEnv('CARGOKIT_ROOT_PROJECT_DIR'); + + // Pod + + /// Platform name (macosx, iphoneos, iphonesimulator). + static String get darwinPlatformName => + _getEnv("CARGOKIT_DARWIN_PLATFORM_NAME"); + + /// List of architectures to build for (arm64, armv7, x86_64). + static List get darwinArchs => + _getEnv("CARGOKIT_DARWIN_ARCHS").split(' '); + + // Gradle + static String get minSdkVersion => _getEnv("CARGOKIT_MIN_SDK_VERSION"); + static String get ndkVersion => _getEnv("CARGOKIT_NDK_VERSION"); + static String get sdkPath => _getEnvPath("CARGOKIT_SDK_DIR"); + static String get javaHome => _getEnvPath("CARGOKIT_JAVA_HOME"); + static List get targetPlatforms => + _getEnv("CARGOKIT_TARGET_PLATFORMS").split(','); + + // CMAKE + static String get targetPlatform => _getEnv("CARGOKIT_TARGET_PLATFORM"); + + static String _getEnv(String key) { + final res = Platform.environment[key]; + if (res == null) { + throw Exception("Missing environment variable $key"); + } + return res; + } + + static String _getEnvPath(String key) { + final res = _getEnv(key); + if (Directory(res).existsSync()) { + return res.resolveSymlink(); + } else { + return res; + } + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/logging.dart b/rust_builder/cargokit/build_tool/lib/src/logging.dart new file mode 100644 index 00000000..5edd4fd1 --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/logging.dart @@ -0,0 +1,52 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:logging/logging.dart'; + +const String kSeparator = "--"; +const String kDoubleSeparator = "=="; + +bool _lastMessageWasSeparator = false; + +void _log(LogRecord rec) { + final prefix = '${rec.level.name}: '; + final out = rec.level == Level.SEVERE ? stderr : stdout; + if (rec.message == kSeparator) { + if (!_lastMessageWasSeparator) { + out.write(prefix); + out.writeln('-' * 80); + _lastMessageWasSeparator = true; + } + return; + } else if (rec.message == kDoubleSeparator) { + out.write(prefix); + out.writeln('=' * 80); + _lastMessageWasSeparator = true; + return; + } + out.write(prefix); + out.writeln(rec.message); + _lastMessageWasSeparator = false; +} + +void initLogging() { + Logger.root.level = Level.INFO; + Logger.root.onRecord.listen((LogRecord rec) { + final lines = rec.message.split('\n'); + for (final line in lines) { + if (line.isNotEmpty || lines.length == 1 || line != lines.last) { + _log(LogRecord( + rec.level, + line, + rec.loggerName, + )); + } + } + }); +} + +void enableVerboseLogging() { + Logger.root.level = Level.ALL; +} diff --git a/rust_builder/cargokit/build_tool/lib/src/options.dart b/rust_builder/cargokit/build_tool/lib/src/options.dart new file mode 100644 index 00000000..22aef1d3 --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/options.dart @@ -0,0 +1,309 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:collection/collection.dart'; +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:hex/hex.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; +import 'package:source_span/source_span.dart'; +import 'package:yaml/yaml.dart'; + +import 'builder.dart'; +import 'environment.dart'; +import 'rustup.dart'; + +final _log = Logger('options'); + +/// A class for exceptions that have source span information attached. +class SourceSpanException implements Exception { + // This is a getter so that subclasses can override it. + /// A message describing the exception. + String get message => _message; + final String _message; + + // This is a getter so that subclasses can override it. + /// The span associated with this exception. + /// + /// This may be `null` if the source location can't be determined. + SourceSpan? get span => _span; + final SourceSpan? _span; + + SourceSpanException(this._message, this._span); + + /// Returns a string representation of `this`. + /// + /// [color] may either be a [String], a [bool], or `null`. If it's a string, + /// it indicates an ANSI terminal color escape that should be used to + /// highlight the span's text. If it's `true`, it indicates that the text + /// should be highlighted using the default color. If it's `false` or `null`, + /// it indicates that the text shouldn't be highlighted. + @override + String toString({Object? color}) { + if (span == null) return message; + return 'Error on ${span!.message(message, color: color)}'; + } +} + +enum Toolchain { + stable, + beta, + nightly, +} + +class CargoBuildOptions { + final Toolchain toolchain; + final List flags; + + CargoBuildOptions({ + required this.toolchain, + required this.flags, + }); + + static Toolchain _toolchainFromNode(YamlNode node) { + if (node case YamlScalar(value: String name)) { + final toolchain = + Toolchain.values.firstWhereOrNull((element) => element.name == name); + if (toolchain != null) { + return toolchain; + } + } + throw SourceSpanException( + 'Unknown toolchain. Must be one of ${Toolchain.values.map((e) => e.name)}.', + node.span); + } + + static CargoBuildOptions parse(YamlNode node) { + if (node is! YamlMap) { + throw SourceSpanException('Cargo options must be a map', node.span); + } + Toolchain toolchain = Toolchain.stable; + List flags = []; + for (final MapEntry(:key, :value) in node.nodes.entries) { + if (key case YamlScalar(value: 'toolchain')) { + toolchain = _toolchainFromNode(value); + } else if (key case YamlScalar(value: 'extra_flags')) { + if (value case YamlList(nodes: List list)) { + if (list.every((element) { + if (element case YamlScalar(value: String _)) { + return true; + } + return false; + })) { + flags = list.map((e) => e.value as String).toList(); + continue; + } + } + throw SourceSpanException( + 'Extra flags must be a list of strings', value.span); + } else { + throw SourceSpanException( + 'Unknown cargo option type. Must be "toolchain" or "extra_flags".', + key.span); + } + } + return CargoBuildOptions(toolchain: toolchain, flags: flags); + } +} + +extension on YamlMap { + /// Map that extracts keys so that we can do map case check on them. + Map get valueMap => + nodes.map((key, value) => MapEntry(key.value, value)); +} + +class PrecompiledBinaries { + final String uriPrefix; + final PublicKey publicKey; + + PrecompiledBinaries({ + required this.uriPrefix, + required this.publicKey, + }); + + static PublicKey _publicKeyFromHex(String key, SourceSpan? span) { + final bytes = HEX.decode(key); + if (bytes.length != 32) { + throw SourceSpanException( + 'Invalid public key. Must be 32 bytes long.', span); + } + return PublicKey(bytes); + } + + static PrecompiledBinaries parse(YamlNode node) { + if (node case YamlMap(valueMap: Map map)) { + if (map + case { + 'url_prefix': YamlNode urlPrefixNode, + 'public_key': YamlNode publicKeyNode, + }) { + final urlPrefix = switch (urlPrefixNode) { + YamlScalar(value: String urlPrefix) => urlPrefix, + _ => throw SourceSpanException( + 'Invalid URL prefix value.', urlPrefixNode.span), + }; + final publicKey = switch (publicKeyNode) { + YamlScalar(value: String publicKey) => + _publicKeyFromHex(publicKey, publicKeyNode.span), + _ => throw SourceSpanException( + 'Invalid public key value.', publicKeyNode.span), + }; + return PrecompiledBinaries( + uriPrefix: urlPrefix, + publicKey: publicKey, + ); + } + } + throw SourceSpanException( + 'Invalid precompiled binaries value. ' + 'Expected Map with "url_prefix" and "public_key".', + node.span); + } +} + +/// Cargokit options specified for Rust crate. +class CargokitCrateOptions { + CargokitCrateOptions({ + this.cargo = const {}, + this.precompiledBinaries, + }); + + final Map cargo; + final PrecompiledBinaries? precompiledBinaries; + + static CargokitCrateOptions parse(YamlNode node) { + if (node is! YamlMap) { + throw SourceSpanException('Cargokit options must be a map', node.span); + } + final options = {}; + PrecompiledBinaries? precompiledBinaries; + + for (final entry in node.nodes.entries) { + if (entry + case MapEntry( + key: YamlScalar(value: 'cargo'), + value: YamlNode node, + )) { + if (node is! YamlMap) { + throw SourceSpanException('Cargo options must be a map', node.span); + } + for (final MapEntry(:YamlNode key, :value) in node.nodes.entries) { + if (key case YamlScalar(value: String name)) { + final configuration = BuildConfiguration.values + .firstWhereOrNull((element) => element.name == name); + if (configuration != null) { + options[configuration] = CargoBuildOptions.parse(value); + continue; + } + } + throw SourceSpanException( + 'Unknown build configuration. Must be one of ${BuildConfiguration.values.map((e) => e.name)}.', + key.span); + } + } else if (entry.key case YamlScalar(value: 'precompiled_binaries')) { + precompiledBinaries = PrecompiledBinaries.parse(entry.value); + } else { + throw SourceSpanException( + 'Unknown cargokit option type. Must be "cargo" or "precompiled_binaries".', + entry.key.span); + } + } + return CargokitCrateOptions( + cargo: options, + precompiledBinaries: precompiledBinaries, + ); + } + + static CargokitCrateOptions load({ + required String manifestDir, + }) { + final uri = Uri.file(path.join(manifestDir, "cargokit.yaml")); + final file = File.fromUri(uri); + if (file.existsSync()) { + final contents = loadYamlNode(file.readAsStringSync(), sourceUrl: uri); + return parse(contents); + } else { + return CargokitCrateOptions(); + } + } +} + +class CargokitUserOptions { + // When Rustup is installed always build locally unless user opts into + // using precompiled binaries. + static bool defaultUsePrecompiledBinaries() { + return Rustup.executablePath() == null; + } + + CargokitUserOptions({ + required this.usePrecompiledBinaries, + required this.verboseLogging, + }); + + CargokitUserOptions._() + : usePrecompiledBinaries = defaultUsePrecompiledBinaries(), + verboseLogging = false; + + static CargokitUserOptions parse(YamlNode node) { + if (node is! YamlMap) { + throw SourceSpanException('Cargokit options must be a map', node.span); + } + bool usePrecompiledBinaries = defaultUsePrecompiledBinaries(); + bool verboseLogging = false; + + for (final entry in node.nodes.entries) { + if (entry.key case YamlScalar(value: 'use_precompiled_binaries')) { + if (entry.value case YamlScalar(value: bool value)) { + usePrecompiledBinaries = value; + continue; + } + throw SourceSpanException( + 'Invalid value for "use_precompiled_binaries". Must be a boolean.', + entry.value.span); + } else if (entry.key case YamlScalar(value: 'verbose_logging')) { + if (entry.value case YamlScalar(value: bool value)) { + verboseLogging = value; + continue; + } + throw SourceSpanException( + 'Invalid value for "verbose_logging". Must be a boolean.', + entry.value.span); + } else { + throw SourceSpanException( + 'Unknown cargokit option type. Must be "use_precompiled_binaries" or "verbose_logging".', + entry.key.span); + } + } + return CargokitUserOptions( + usePrecompiledBinaries: usePrecompiledBinaries, + verboseLogging: verboseLogging, + ); + } + + static CargokitUserOptions load() { + String fileName = "cargokit_options.yaml"; + var userProjectDir = Directory(Environment.rootProjectDir); + + while (userProjectDir.parent.path != userProjectDir.path) { + final configFile = File(path.join(userProjectDir.path, fileName)); + if (configFile.existsSync()) { + final contents = loadYamlNode( + configFile.readAsStringSync(), + sourceUrl: configFile.uri, + ); + final res = parse(contents); + if (res.verboseLogging) { + _log.info('Found user options file at ${configFile.path}'); + } + return res; + } + userProjectDir = userProjectDir.parent; + } + return CargokitUserOptions._(); + } + + final bool usePrecompiledBinaries; + final bool verboseLogging; +} diff --git a/rust_builder/cargokit/build_tool/lib/src/precompile_binaries.dart b/rust_builder/cargokit/build_tool/lib/src/precompile_binaries.dart new file mode 100644 index 00000000..019859c3 --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/precompile_binaries.dart @@ -0,0 +1,205 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:github/github.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'cargo.dart'; +import 'crate_hash.dart'; +import 'options.dart'; +import 'rustup.dart'; +import 'target.dart'; + +final _log = Logger('precompile_binaries'); + +class PrecompileBinaries { + PrecompileBinaries({ + required this.privateKey, + required this.githubToken, + required this.repositorySlug, + required this.manifestDir, + required this.targets, + this.androidSdkLocation, + this.androidNdkVersion, + this.androidMinSdkVersion, + this.tempDir, + this.glibcVersion, + }); + + final PrivateKey privateKey; + final String githubToken; + final RepositorySlug repositorySlug; + final String manifestDir; + final List targets; + final String? androidSdkLocation; + final String? androidNdkVersion; + final int? androidMinSdkVersion; + final String? tempDir; + final String? glibcVersion; + + static String fileName(Target target, String name) { + return '${target.rust}_$name'; + } + + static String signatureFileName(Target target, String name) { + return '${target.rust}_$name.sig'; + } + + Future run() async { + final crateInfo = CrateInfo.load(manifestDir); + + final targets = List.of(this.targets); + if (targets.isEmpty) { + targets.addAll([ + ...Target.buildableTargets(), + if (androidSdkLocation != null) ...Target.androidTargets(), + ]); + } + + _log.info('Precompiling binaries for $targets'); + + final hash = CrateHash.compute(manifestDir); + _log.info('Computed crate hash: $hash'); + + final String tagName = 'precompiled_$hash'; + + final github = GitHub(auth: Authentication.withToken(githubToken)); + final repo = github.repositories; + final release = await _getOrCreateRelease( + repo: repo, + tagName: tagName, + packageName: crateInfo.packageName, + hash: hash, + ); + + final tempDir = this.tempDir != null + ? Directory(this.tempDir!) + : Directory.systemTemp.createTempSync('precompiled_'); + + tempDir.createSync(recursive: true); + + final crateOptions = CargokitCrateOptions.load( + manifestDir: manifestDir, + ); + + final buildEnvironment = BuildEnvironment( + configuration: BuildConfiguration.release, + crateOptions: crateOptions, + targetTempDir: tempDir.path, + manifestDir: manifestDir, + crateInfo: crateInfo, + isAndroid: androidSdkLocation != null, + androidSdkPath: androidSdkLocation, + androidNdkVersion: androidNdkVersion, + androidMinSdkVersion: androidMinSdkVersion, + glibcVersion: glibcVersion, + ); + + final rustup = Rustup(); + + for (final target in targets) { + final artifactNames = getArtifactNames( + target: target, + libraryName: crateInfo.packageName, + remote: true, + ); + + if (artifactNames.every((name) { + final fileName = PrecompileBinaries.fileName(target, name); + return (release.assets ?? []).any((e) => e.name == fileName); + })) { + _log.info("All artifacts for $target already exist - skipping"); + continue; + } + + _log.info('Building for $target'); + + final builder = + RustBuilder(target: target, environment: buildEnvironment); + builder.prepare(rustup); + final res = await builder.build(); + + final assets = []; + for (final name in artifactNames) { + final file = File(path.join(res, name)); + if (!file.existsSync()) { + throw Exception('Missing artifact: ${file.path}'); + } + + final data = file.readAsBytesSync(); + final create = CreateReleaseAsset( + name: PrecompileBinaries.fileName(target, name), + contentType: "application/octet-stream", + assetData: data, + ); + final signature = sign(privateKey, data); + final signatureCreate = CreateReleaseAsset( + name: signatureFileName(target, name), + contentType: "application/octet-stream", + assetData: signature, + ); + bool verified = verify(public(privateKey), data, signature); + if (!verified) { + throw Exception('Signature verification failed'); + } + assets.add(create); + assets.add(signatureCreate); + } + _log.info('Uploading assets: ${assets.map((e) => e.name)}'); + for (final asset in assets) { + // This seems to be failing on CI so do it one by one + int retryCount = 0; + while (true) { + try { + await repo.uploadReleaseAssets(release, [asset]); + break; + } on Exception catch (e) { + if (retryCount == 10) { + rethrow; + } + ++retryCount; + _log.shout( + 'Upload failed (attempt $retryCount, will retry): ${e.toString()}'); + await Future.delayed(Duration(seconds: 2)); + } + } + } + } + + _log.info('Cleaning up'); + tempDir.deleteSync(recursive: true); + } + + Future _getOrCreateRelease({ + required RepositoriesService repo, + required String tagName, + required String packageName, + required String hash, + }) async { + Release release; + try { + _log.info('Fetching release $tagName'); + release = await repo.getReleaseByTagName(repositorySlug, tagName); + } on ReleaseNotFound { + _log.info('Release not found - creating release $tagName'); + release = await repo.createRelease( + repositorySlug, + CreateRelease.from( + tagName: tagName, + name: 'Precompiled binaries ${hash.substring(0, 8)}', + targetCommitish: null, + isDraft: false, + isPrerelease: false, + body: 'Precompiled binaries for crate $packageName, ' + 'crate hash $hash.', + )); + } + return release; + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/rustup.dart b/rust_builder/cargokit/build_tool/lib/src/rustup.dart new file mode 100644 index 00000000..e46722be --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/rustup.dart @@ -0,0 +1,149 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:collection/collection.dart'; +import 'package:path/path.dart' as path; + +import 'util.dart'; + +class _Toolchain { + _Toolchain( + this.name, + this.targets, + ); + + final String name; + final List targets; +} + +class Rustup { + List? installedTargets(String toolchain) { + final targets = _installedTargets(toolchain); + return targets != null ? List.unmodifiable(targets) : null; + } + + void installToolchain(String toolchain) { + log.info("Installing Rust toolchain: $toolchain"); + runCommand("rustup", ['toolchain', 'install', toolchain]); + _installedToolchains + .add(_Toolchain(toolchain, _getInstalledTargets(toolchain))); + } + + void installTarget( + String target, { + required String toolchain, + }) { + log.info("Installing Rust target: $target"); + runCommand("rustup", ['target', 'add', '--toolchain', toolchain, target]); + _installedTargets(toolchain)?.add(target); + } + + bool _didInstallZigBuild = false; + + void installZigBuild(String toolchain) { + if (_didInstallZigBuild) { + return; + } + + log.info("Installing Zig build"); + runCommand("rustup", [ + 'run', + toolchain, + 'cargo', + 'install', + '--locked', + 'cargo-zigbuild', + ]); + _didInstallZigBuild = true; + } + + final List<_Toolchain> _installedToolchains; + + Rustup() : _installedToolchains = _getInstalledToolchains(); + + List? _installedTargets(String toolchain) => _installedToolchains + .firstWhereOrNull( + (e) => e.name == toolchain || e.name.startsWith('$toolchain-')) + ?.targets; + + static List<_Toolchain> _getInstalledToolchains() { + String extractToolchainName(String line) { + // ignore (default) after toolchain name + final parts = line.split(' '); + return parts[0]; + } + + final res = runCommand("rustup", ['toolchain', 'list']); + + // To list all non-custom toolchains, we need to filter out lines that + // don't start with "stable", "beta", or "nightly". + Pattern nonCustom = RegExp(r"^(stable|beta|nightly)"); + final lines = res.stdout + .toString() + .split('\n') + .where((e) => e.isNotEmpty && e.startsWith(nonCustom)) + .map(extractToolchainName) + .toList(growable: true); + + return lines + .map( + (name) => _Toolchain( + name, + _getInstalledTargets(name), + ), + ) + .toList(growable: true); + } + + static List _getInstalledTargets(String toolchain) { + final res = runCommand("rustup", [ + 'target', + 'list', + '--toolchain', + toolchain, + '--installed', + ]); + final lines = res.stdout + .toString() + .split('\n') + .where((e) => e.isNotEmpty) + .toList(growable: true); + return lines; + } + + bool _didInstallRustSrcForNightly = false; + + void installRustSrcForNightly() { + if (_didInstallRustSrcForNightly) { + return; + } + // Useful for -Z build-std + runCommand( + "rustup", + ['component', 'add', 'rust-src', '--toolchain', 'nightly'], + ); + _didInstallRustSrcForNightly = true; + } + + static String? executablePath() { + final envPath = Platform.environment['PATH']; + final envPathSeparator = Platform.isWindows ? ';' : ':'; + final home = Platform.isWindows + ? Platform.environment['USERPROFILE'] + : Platform.environment['HOME']; + final paths = [ + if (home != null) path.join(home, '.cargo', 'bin'), + if (envPath != null) ...envPath.split(envPathSeparator), + ]; + for (final p in paths) { + final rustup = Platform.isWindows ? 'rustup.exe' : 'rustup'; + final rustupPath = path.join(p, rustup); + if (File(rustupPath).existsSync()) { + return rustupPath; + } + } + return null; + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/target.dart b/rust_builder/cargokit/build_tool/lib/src/target.dart new file mode 100644 index 00000000..624504ed --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/target.dart @@ -0,0 +1,147 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:collection/collection.dart'; + +import 'util.dart'; + +class Target { + Target({ + required this.rust, + this.flutter, + this.android, + this.androidMinSdkVersion, + this.darwinPlatform, + this.darwinArch, + }); + + static final all = [ + Target( + rust: 'armv7-linux-androideabi', + flutter: 'android-arm', + android: 'armeabi-v7a', + androidMinSdkVersion: 16, + ), + Target( + rust: 'aarch64-linux-android', + flutter: 'android-arm64', + android: 'arm64-v8a', + androidMinSdkVersion: 21, + ), + Target( + rust: 'i686-linux-android', + flutter: 'android-x86', + android: 'x86', + androidMinSdkVersion: 16, + ), + Target( + rust: 'x86_64-linux-android', + flutter: 'android-x64', + android: 'x86_64', + androidMinSdkVersion: 21, + ), + Target( + rust: 'x86_64-pc-windows-msvc', + flutter: 'windows-x64', + ), + Target( + rust: 'aarch64-pc-windows-msvc', + flutter: 'windows-arm64', + ), + Target( + rust: 'x86_64-unknown-linux-gnu', + flutter: 'linux-x64', + ), + Target( + rust: 'aarch64-unknown-linux-gnu', + flutter: 'linux-arm64', + ), + Target(rust: 'riscv64gc-unknown-linux-gnu', flutter: 'linux-riscv64'), + Target( + rust: 'x86_64-apple-darwin', + darwinPlatform: 'macosx', + darwinArch: 'x86_64', + ), + Target( + rust: 'aarch64-apple-darwin', + darwinPlatform: 'macosx', + darwinArch: 'arm64', + ), + Target( + rust: 'aarch64-apple-ios', + darwinPlatform: 'iphoneos', + darwinArch: 'arm64', + ), + Target( + rust: 'aarch64-apple-ios-sim', + darwinPlatform: 'iphonesimulator', + darwinArch: 'arm64', + ), + Target( + rust: 'x86_64-apple-ios', + darwinPlatform: 'iphonesimulator', + darwinArch: 'x86_64', + ), + ]; + + static Target? forFlutterName(String flutterName) { + return all.firstWhereOrNull((element) => element.flutter == flutterName); + } + + static Target? forDarwin({ + required String platformName, + required String darwinAarch, + }) { + return all.firstWhereOrNull((element) => // + element.darwinPlatform == platformName && + element.darwinArch == darwinAarch); + } + + static Target? forRustTriple(String triple) { + return all.firstWhereOrNull((element) => element.rust == triple); + } + + static List androidTargets() { + return all + .where((element) => element.android != null) + .toList(growable: false); + } + + /// Returns buildable targets on current host platform ignoring Android targets. + static List buildableTargets() { + if (Platform.isLinux) { + // Right now we don't support cross-compiling on Linux. So we just return + // the host target. + final arch = (runCommand('arch', []).stdout as String).trim(); + if (arch == 'aarch64') { + return [Target.forRustTriple('aarch64-unknown-linux-gnu')!]; + } else if (arch == 'riscv64') { + return [Target.forRustTriple('riscv64gc-unknown-linux-gnu')!]; + } else { + return [Target.forRustTriple('x86_64-unknown-linux-gnu')!]; + } + } + return all.where((target) { + if (Platform.isWindows) { + return target.rust.contains('-windows-'); + } else if (Platform.isMacOS) { + return target.darwinPlatform != null; + } + return false; + }).toList(growable: false); + } + + @override + String toString() { + return rust; + } + + final String? flutter; + final String rust; + final String? android; + final int? androidMinSdkVersion; + final String? darwinPlatform; + final String? darwinArch; +} diff --git a/rust_builder/cargokit/build_tool/lib/src/util.dart b/rust_builder/cargokit/build_tool/lib/src/util.dart new file mode 100644 index 00000000..8bb6a872 --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/util.dart @@ -0,0 +1,172 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:convert'; +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'logging.dart'; +import 'rustup.dart'; + +final log = Logger("process"); + +class CommandFailedException implements Exception { + final String executable; + final List arguments; + final ProcessResult result; + + CommandFailedException({ + required this.executable, + required this.arguments, + required this.result, + }); + + @override + String toString() { + final stdout = result.stdout.toString().trim(); + final stderr = result.stderr.toString().trim(); + return [ + "External Command: $executable ${arguments.map((e) => '"$e"').join(' ')}", + "Returned Exit Code: ${result.exitCode}", + kSeparator, + "STDOUT:", + if (stdout.isNotEmpty) stdout, + kSeparator, + "STDERR:", + if (stderr.isNotEmpty) stderr, + ].join('\n'); + } +} + +class TestRunCommandArgs { + final String executable; + final List arguments; + final String? workingDirectory; + final Map? environment; + final bool includeParentEnvironment; + final bool runInShell; + final Encoding? stdoutEncoding; + final Encoding? stderrEncoding; + + TestRunCommandArgs({ + required this.executable, + required this.arguments, + this.workingDirectory, + this.environment, + this.includeParentEnvironment = true, + this.runInShell = false, + this.stdoutEncoding, + this.stderrEncoding, + }); +} + +class TestRunCommandResult { + TestRunCommandResult({ + this.pid = 1, + this.exitCode = 0, + this.stdout = '', + this.stderr = '', + }); + + final int pid; + final int exitCode; + final String stdout; + final String stderr; +} + +TestRunCommandResult Function(TestRunCommandArgs args)? testRunCommandOverride; + +ProcessResult runCommand( + String executable, + List arguments, { + String? workingDirectory, + Map? environment, + bool includeParentEnvironment = true, + bool runInShell = false, + Encoding? stdoutEncoding = systemEncoding, + Encoding? stderrEncoding = systemEncoding, +}) { + if (testRunCommandOverride != null) { + final result = testRunCommandOverride!(TestRunCommandArgs( + executable: executable, + arguments: arguments, + workingDirectory: workingDirectory, + environment: environment, + includeParentEnvironment: includeParentEnvironment, + runInShell: runInShell, + stdoutEncoding: stdoutEncoding, + stderrEncoding: stderrEncoding, + )); + return ProcessResult( + result.pid, + result.exitCode, + result.stdout, + result.stderr, + ); + } + log.finer('Running command $executable ${arguments.join(' ')}'); + final res = Process.runSync( + _resolveExecutable(executable), + arguments, + workingDirectory: workingDirectory, + environment: environment, + includeParentEnvironment: includeParentEnvironment, + runInShell: runInShell, + stderrEncoding: stderrEncoding, + stdoutEncoding: stdoutEncoding, + ); + if (res.exitCode != 0) { + throw CommandFailedException( + executable: executable, + arguments: arguments, + result: res, + ); + } else { + return res; + } +} + +class RustupNotFoundException implements Exception { + @override + String toString() { + return [ + ' ', + 'rustup not found in PATH.', + ' ', + 'Maybe you need to install Rust? It only takes a minute:', + ' ', + if (Platform.isWindows) 'https://www.rust-lang.org/tools/install', + if (hasHomebrewRustInPath()) ...[ + '\$ brew unlink rust # Unlink homebrew Rust from PATH', + ], + if (!Platform.isWindows) + "\$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh", + ' ', + ].join('\n'); + } + + static bool hasHomebrewRustInPath() { + if (!Platform.isMacOS) { + return false; + } + final envPath = Platform.environment['PATH'] ?? ''; + final paths = envPath.split(':'); + return paths.any((p) { + return p.contains('homebrew') && File(path.join(p, 'rustc')).existsSync(); + }); + } +} + +String _resolveExecutable(String executable) { + if (executable == 'rustup') { + final resolved = Rustup.executablePath(); + if (resolved != null) { + return resolved; + } + throw RustupNotFoundException(); + } else { + return executable; + } +} diff --git a/rust_builder/cargokit/build_tool/lib/src/verify_binaries.dart b/rust_builder/cargokit/build_tool/lib/src/verify_binaries.dart new file mode 100644 index 00000000..2366b57b --- /dev/null +++ b/rust_builder/cargokit/build_tool/lib/src/verify_binaries.dart @@ -0,0 +1,84 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:http/http.dart'; + +import 'artifacts_provider.dart'; +import 'cargo.dart'; +import 'crate_hash.dart'; +import 'options.dart'; +import 'precompile_binaries.dart'; +import 'target.dart'; + +class VerifyBinaries { + VerifyBinaries({ + required this.manifestDir, + }); + + final String manifestDir; + + Future run() async { + final crateInfo = CrateInfo.load(manifestDir); + + final config = CargokitCrateOptions.load(manifestDir: manifestDir); + final precompiledBinaries = config.precompiledBinaries; + if (precompiledBinaries == null) { + stdout.writeln('Crate does not support precompiled binaries.'); + } else { + final crateHash = CrateHash.compute(manifestDir); + stdout.writeln('Crate hash: $crateHash'); + + for (final target in Target.all) { + final message = 'Checking ${target.rust}...'; + stdout.write(message.padRight(40)); + stdout.flush(); + + final artifacts = getArtifactNames( + target: target, + libraryName: crateInfo.packageName, + remote: true, + ); + + final prefix = precompiledBinaries.uriPrefix; + + bool ok = true; + + for (final artifact in artifacts) { + final fileName = PrecompileBinaries.fileName(target, artifact); + final signatureFileName = + PrecompileBinaries.signatureFileName(target, artifact); + + final url = Uri.parse('$prefix$crateHash/$fileName'); + final signatureUrl = + Uri.parse('$prefix$crateHash/$signatureFileName'); + + final signature = await get(signatureUrl); + if (signature.statusCode != 200) { + stdout.writeln('MISSING'); + ok = false; + break; + } + final asset = await get(url); + if (asset.statusCode != 200) { + stdout.writeln('MISSING'); + ok = false; + break; + } + + if (!verify(precompiledBinaries.publicKey, asset.bodyBytes, + signature.bodyBytes)) { + stdout.writeln('INVALID SIGNATURE'); + ok = false; + } + } + + if (ok) { + stdout.writeln('OK'); + } + } + } + } +} diff --git a/rust_builder/cargokit/build_tool/pubspec.lock b/rust_builder/cargokit/build_tool/pubspec.lock new file mode 100644 index 00000000..343bdd36 --- /dev/null +++ b/rust_builder/cargokit/build_tool/pubspec.lock @@ -0,0 +1,453 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + url: "https://pub.dev" + source: hosted + version: "64.0.0" + adaptive_number: + dependency: transitive + description: + name: adaptive_number + sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + url: "https://pub.dev" + source: hosted + version: "6.2.0" + args: + dependency: "direct main" + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + collection: + dependency: "direct main" + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: "direct main" + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" + url: "https://pub.dev" + source: hosted + version: "1.6.3" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + ed25519_edwards: + dependency: "direct main" + description: + name: ed25519_edwards + sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + github: + dependency: "direct main" + description: + name: github + sha256: "9966bc13bf612342e916b0a343e95e5f046c88f602a14476440e9b75d2295411" + url: "https://pub.dev" + source: hosted + version: "9.17.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + hex: + dependency: "direct main" + description: + name: hex + sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + http: + dependency: "direct main" + description: + name: http + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + lints: + dependency: "direct dev" + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + logging: + dependency: "direct main" + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" + source: hosted + version: "0.12.16" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: "direct main" + description: + name: path + sha256: "2ad4cddff7f5cc0e2d13069f2a3f7a73ca18f66abd6f5ecf215219cdb3638edb" + url: "https://pub.dev" + source: hosted + version: "1.8.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: "direct main" + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: "9b0dd8e36af4a5b1569029949d50a52cb2a2a2fdaa20cebb96e6603b9ae241f9" + url: "https://pub.dev" + source: hosted + version: "1.24.6" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" + source: hosted + version: "0.6.1" + test_core: + dependency: transitive + description: + name: test_core + sha256: "4bef837e56375537055fdbbbf6dd458b1859881f4c7e6da936158f77d61ab265" + url: "https://pub.dev" + source: hosted + version: "0.5.6" + toml: + dependency: "direct main" + description: + name: toml + sha256: "157c5dca5160fced243f3ce984117f729c788bb5e475504f3dbcda881accee44" + url: "https://pub.dev" + source: hosted + version: "0.14.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + version: + dependency: "direct main" + description: + name: version + sha256: "2307e23a45b43f96469eeab946208ed63293e8afca9c28cd8b5241ff31c55f55" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0fae432c85c4ea880b33b497d32824b97795b04cdaa74d270219572a1f50268d" + url: "https://pub.dev" + source: hosted + version: "11.9.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + yaml: + dependency: "direct main" + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.0.0 <4.0.0" diff --git a/rust_builder/cargokit/build_tool/pubspec.yaml b/rust_builder/cargokit/build_tool/pubspec.yaml new file mode 100644 index 00000000..18c61e33 --- /dev/null +++ b/rust_builder/cargokit/build_tool/pubspec.yaml @@ -0,0 +1,33 @@ +# This is copied from Cargokit (which is the official way to use it currently) +# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +name: build_tool +description: Cargokit build_tool. Facilitates the build of Rust crate during Flutter application build. +publish_to: none +version: 1.0.0 + +environment: + sdk: ">=3.0.0 <4.0.0" + +# Add regular dependencies here. +dependencies: + # these are pinned on purpose because the bundle_tool_runner doesn't have + # pubspec.lock. See run_build_tool.sh + logging: 1.2.0 + path: 1.8.0 + version: 3.0.0 + collection: 1.18.0 + ed25519_edwards: 0.3.1 + hex: 0.2.0 + yaml: 3.1.2 + source_span: 1.10.0 + github: 9.17.0 + args: 2.4.2 + crypto: 3.0.3 + convert: 3.1.1 + http: 1.1.0 + toml: 0.14.0 + +dev_dependencies: + lints: ^2.1.0 + test: ^1.24.0 diff --git a/rust_builder/cargokit/cmake/cargokit.cmake b/rust_builder/cargokit/cmake/cargokit.cmake new file mode 100644 index 00000000..ddd05df9 --- /dev/null +++ b/rust_builder/cargokit/cmake/cargokit.cmake @@ -0,0 +1,99 @@ +SET(cargokit_cmake_root "${CMAKE_CURRENT_LIST_DIR}/..") + +# Workaround for https://github.com/dart-lang/pub/issues/4010 +get_filename_component(cargokit_cmake_root "${cargokit_cmake_root}" REALPATH) + +if(WIN32) + # REALPATH does not properly resolve symlinks on windows :-/ + execute_process(COMMAND powershell -ExecutionPolicy Bypass -File "${CMAKE_CURRENT_LIST_DIR}/resolve_symlinks.ps1" "${cargokit_cmake_root}" OUTPUT_VARIABLE cargokit_cmake_root OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +# Arguments +# - target: CMAKE target to which rust library is linked +# - manifest_dir: relative path from current folder to directory containing cargo manifest +# - lib_name: cargo package name +# - any_symbol_name: name of any exported symbol from the library. +# used on windows to force linking with library. +function(apply_cargokit target manifest_dir lib_name any_symbol_name) + + set(CARGOKIT_LIB_NAME "${lib_name}") + set(CARGOKIT_LIB_FULL_NAME "${CMAKE_SHARED_MODULE_PREFIX}${CARGOKIT_LIB_NAME}${CMAKE_SHARED_MODULE_SUFFIX}") + if (CMAKE_CONFIGURATION_TYPES) + set(CARGOKIT_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/$") + set(OUTPUT_LIB "${CMAKE_CURRENT_BINARY_DIR}/$/${CARGOKIT_LIB_FULL_NAME}") + else() + set(CARGOKIT_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + set(OUTPUT_LIB "${CMAKE_CURRENT_BINARY_DIR}/${CARGOKIT_LIB_FULL_NAME}") + endif() + set(CARGOKIT_TEMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/cargokit_build") + + if (FLUTTER_TARGET_PLATFORM) + set(CARGOKIT_TARGET_PLATFORM "${FLUTTER_TARGET_PLATFORM}") + else() + set(CARGOKIT_TARGET_PLATFORM "windows-x64") + endif() + + set(CARGOKIT_ENV + "CARGOKIT_CMAKE=${CMAKE_COMMAND}" + "CARGOKIT_CONFIGURATION=$" + "CARGOKIT_MANIFEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/${manifest_dir}" + "CARGOKIT_TARGET_TEMP_DIR=${CARGOKIT_TEMP_DIR}" + "CARGOKIT_OUTPUT_DIR=${CARGOKIT_OUTPUT_DIR}" + "CARGOKIT_TARGET_PLATFORM=${CARGOKIT_TARGET_PLATFORM}" + "CARGOKIT_TOOL_TEMP_DIR=${CARGOKIT_TEMP_DIR}/tool" + "CARGOKIT_ROOT_PROJECT_DIR=${CMAKE_SOURCE_DIR}" + ) + + if (WIN32) + set(SCRIPT_EXTENSION ".cmd") + set(IMPORT_LIB_EXTENSION ".lib") + else() + set(SCRIPT_EXTENSION ".sh") + set(IMPORT_LIB_EXTENSION "") + execute_process(COMMAND chmod +x "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}") + endif() + + # Using generators in custom command is only supported in CMake 3.20+ + if (CMAKE_CONFIGURATION_TYPES AND ${CMAKE_VERSION} VERSION_LESS "3.20.0") + foreach(CONFIG IN LISTS CMAKE_CONFIGURATION_TYPES) + add_custom_command( + OUTPUT + "${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}/${CARGOKIT_LIB_FULL_NAME}" + "${CMAKE_CURRENT_BINARY_DIR}/_phony_" + COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV} + "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}" build-cmake + VERBATIM + ) + endforeach() + else() + add_custom_command( + OUTPUT + ${OUTPUT_LIB} + "${CMAKE_CURRENT_BINARY_DIR}/_phony_" + COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV} + "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}" build-cmake + VERBATIM + ) + endif() + + + set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/_phony_" PROPERTIES SYMBOLIC TRUE) + + if (TARGET ${target}) + # If we have actual cmake target provided create target and make existing + # target depend on it + add_custom_target("${target}_cargokit" DEPENDS ${OUTPUT_LIB}) + add_dependencies("${target}" "${target}_cargokit") + target_link_libraries("${target}" PRIVATE "${OUTPUT_LIB}${IMPORT_LIB_EXTENSION}") + if(WIN32) + target_link_options(${target} PRIVATE "/INCLUDE:${any_symbol_name}") + endif() + else() + # Otherwise (FFI) just use ALL to force building always + add_custom_target("${target}_cargokit" ALL DEPENDS ${OUTPUT_LIB}) + endif() + + # Allow adding the output library to plugin bundled libraries + set("${target}_cargokit_lib" ${OUTPUT_LIB} PARENT_SCOPE) + +endfunction() diff --git a/rust_builder/cargokit/cmake/resolve_symlinks.ps1 b/rust_builder/cargokit/cmake/resolve_symlinks.ps1 new file mode 100644 index 00000000..2ac593a1 --- /dev/null +++ b/rust_builder/cargokit/cmake/resolve_symlinks.ps1 @@ -0,0 +1,34 @@ +function Resolve-Symlinks { + [CmdletBinding()] + [OutputType([string])] + param( + [Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] + [string] $Path + ) + + [string] $separator = '/' + [string[]] $parts = $Path.Split($separator) + + [string] $realPath = '' + foreach ($part in $parts) { + if ($realPath -and !$realPath.EndsWith($separator)) { + $realPath += $separator + } + + $realPath += $part.Replace('\', '/') + + # The slash is important when using Get-Item on Drive letters in pwsh. + if (-not($realPath.Contains($separator)) -and $realPath.EndsWith(':')) { + $realPath += '/' + } + + $item = Get-Item $realPath + if ($item.LinkTarget) { + $realPath = $item.LinkTarget.Replace('\', '/') + } + } + $realPath +} + +$path = Resolve-Symlinks -Path $args[0] +Write-Host $path diff --git a/rust_builder/cargokit/gradle/plugin.gradle b/rust_builder/cargokit/gradle/plugin.gradle new file mode 100644 index 00000000..68ff6499 --- /dev/null +++ b/rust_builder/cargokit/gradle/plugin.gradle @@ -0,0 +1,184 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import java.nio.file.Paths +import org.apache.tools.ant.taskdefs.condition.Os + +CargoKitPlugin.file = buildscript.sourceFile + +apply plugin: CargoKitPlugin + +class CargoKitExtension { + String manifestDir; // Relative path to folder containing Cargo.toml + String libname; // Library name within Cargo.toml. Must be a cdylib +} + +abstract class CargoKitBuildTask extends DefaultTask { + + @Input + String buildMode + + @Input + String buildDir + + @Input + String outputDir + + @Input + String ndkVersion + + @Input + String sdkDirectory + + @Input + int compileSdkVersion; + + @Input + int minSdkVersion; + + @Input + String pluginFile + + @Input + List targetPlatforms + + @TaskAction + def build() { + if (project.cargokit.manifestDir == null) { + throw new GradleException("Property 'manifestDir' must be set on cargokit extension"); + } + + if (project.cargokit.libname == null) { + throw new GradleException("Property 'libname' must be set on cargokit extension"); + } + + def executableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "run_build_tool.cmd" : "run_build_tool.sh" + def path = Paths.get(new File(pluginFile).parent, "..", executableName); + + def manifestDir = Paths.get(project.buildscript.sourceFile.parent, project.cargokit.manifestDir) + + def rootProjectDir = project.rootProject.projectDir + + if (!Os.isFamily(Os.FAMILY_WINDOWS)) { + project.exec { + commandLine 'chmod', '+x', path + } + } + + project.exec { + executable path + args "build-gradle" + environment "CARGOKIT_ROOT_PROJECT_DIR", rootProjectDir + environment "CARGOKIT_TOOL_TEMP_DIR", "${buildDir}/build_tool" + environment "CARGOKIT_MANIFEST_DIR", manifestDir + environment "CARGOKIT_CONFIGURATION", buildMode + environment "CARGOKIT_TARGET_TEMP_DIR", buildDir + environment "CARGOKIT_OUTPUT_DIR", outputDir + environment "CARGOKIT_NDK_VERSION", ndkVersion + environment "CARGOKIT_SDK_DIR", sdkDirectory + environment "CARGOKIT_COMPILE_SDK_VERSION", compileSdkVersion + environment "CARGOKIT_MIN_SDK_VERSION", minSdkVersion + environment "CARGOKIT_TARGET_PLATFORMS", targetPlatforms.join(",") + environment "CARGOKIT_JAVA_HOME", System.properties['java.home'] + } + } +} + +class CargoKitPlugin implements Plugin { + + static String file; + + private Plugin findFlutterPlugin(Project rootProject) { + _findFlutterPlugin(rootProject.childProjects) + } + + private Plugin _findFlutterPlugin(Map projects) { + for (project in projects) { + for (plugin in project.value.getPlugins()) { + if (plugin.class.name == "com.flutter.gradle.FlutterPlugin" || plugin.class.name == "FlutterPlugin") { + return plugin; + } + } + def plugin = _findFlutterPlugin(project.value.childProjects); + if (plugin != null) { + return plugin; + } + } + return null; + } + + @Override + void apply(Project project) { + def plugin = findFlutterPlugin(project.rootProject); + + project.extensions.create("cargokit", CargoKitExtension) + + if (plugin == null) { + print("Flutter plugin not found, CargoKit plugin will not be applied.") + return; + } + + def cargoBuildDir = "${project.buildDir}/build" + + // Determine if the project is an application or library + def isApplication = plugin.project.plugins.hasPlugin('com.android.application') + def variants = isApplication ? plugin.project.android.applicationVariants : plugin.project.android.libraryVariants + + variants.all { variant -> + + final buildType = variant.buildType.name + + def cargoOutputDir = "${project.buildDir}/jniLibs/${buildType}"; + def jniLibs = project.android.sourceSets.maybeCreate(buildType).jniLibs; + jniLibs.srcDir(new File(cargoOutputDir)) + + def List platforms + try { + platforms = com.flutter.gradle.FlutterPluginUtils.getTargetPlatforms(project).collect() + } catch (Exception ignored) { + platforms = plugin.getTargetPlatforms().collect() + } + + // Same thing addFlutterDependencies does in flutter.gradle + if (buildType == "debug") { + platforms.add("android-x86") + platforms.add("android-x64") + } + + // The task name depends on plugin properties, which are not available + // at this point + project.getGradle().afterProject { + def taskName = "cargokitCargoBuild${project.cargokit.libname.capitalize()}${buildType.capitalize()}"; + + if (project.tasks.findByName(taskName)) { + return + } + + if (plugin.project.android.ndkVersion == null) { + throw new GradleException("Please set 'android.ndkVersion' in 'app/build.gradle'.") + } + + def task = project.tasks.create(taskName, CargoKitBuildTask.class) { + buildMode = variant.buildType.name + buildDir = cargoBuildDir + outputDir = cargoOutputDir + ndkVersion = plugin.project.android.ndkVersion + sdkDirectory = plugin.project.android.sdkDirectory + minSdkVersion = plugin.project.android.defaultConfig.minSdkVersion.apiLevel as int + compileSdkVersion = plugin.project.android.compileSdkVersion.substring(8) as int + targetPlatforms = platforms + pluginFile = CargoKitPlugin.file + } + def onTask = { newTask -> + if (newTask.name == "merge${buildType.capitalize()}NativeLibs") { + newTask.dependsOn task + // Fix gradle 7.4.2 not picking up JNI library changes + newTask.outputs.upToDateWhen { false } + } + } + project.tasks.each onTask + project.tasks.whenTaskAdded onTask + } + } + } +} diff --git a/rust_builder/cargokit/run_build_tool.cmd b/rust_builder/cargokit/run_build_tool.cmd new file mode 100755 index 00000000..c45d0aa8 --- /dev/null +++ b/rust_builder/cargokit/run_build_tool.cmd @@ -0,0 +1,91 @@ +@echo off +setlocal + +setlocal ENABLEDELAYEDEXPANSION + +SET BASEDIR=%~dp0 + +if not exist "%CARGOKIT_TOOL_TEMP_DIR%" ( + mkdir "%CARGOKIT_TOOL_TEMP_DIR%" +) +cd /D "%CARGOKIT_TOOL_TEMP_DIR%" + +SET BUILD_TOOL_PKG_DIR=%BASEDIR%build_tool +SET DART=%FLUTTER_ROOT%\bin\cache\dart-sdk\bin\dart + +set BUILD_TOOL_PKG_DIR_POSIX=%BUILD_TOOL_PKG_DIR:\=/% + +( + echo name: build_tool_runner + echo version: 1.0.0 + echo publish_to: none + echo. + echo environment: + echo sdk: '^>=3.0.0 ^<4.0.0' + echo. + echo dependencies: + echo build_tool: + echo path: %BUILD_TOOL_PKG_DIR_POSIX% +) >pubspec.yaml + +if not exist bin ( + mkdir bin +) + +( + echo import 'package:build_tool/build_tool.dart' as build_tool; + echo void main^(List^ args^) ^{ + echo build_tool.runMain^(args^); + echo ^} +) >bin\build_tool_runner.dart + +SET PRECOMPILED=bin\build_tool_runner.dill + +REM To detect changes in package we compare output of DIR /s (recursive) +set PREV_PACKAGE_INFO=.dart_tool\package_info.prev +set CUR_PACKAGE_INFO=.dart_tool\package_info.cur + +DIR "%BUILD_TOOL_PKG_DIR%" /s > "%CUR_PACKAGE_INFO%_orig" + +REM Last line in dir output is free space on harddrive. That is bound to +REM change between invocation so we need to remove it +( + Set "Line=" + For /F "UseBackQ Delims=" %%A In ("%CUR_PACKAGE_INFO%_orig") Do ( + SetLocal EnableDelayedExpansion + If Defined Line Echo !Line! + EndLocal + Set "Line=%%A") +) >"%CUR_PACKAGE_INFO%" +DEL "%CUR_PACKAGE_INFO%_orig" + +REM Compare current directory listing with previous +FC /B "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%" > nul 2>&1 + +If %ERRORLEVEL% neq 0 ( + REM Changed - copy current to previous and remove precompiled kernel + if exist "%PREV_PACKAGE_INFO%" ( + DEL "%PREV_PACKAGE_INFO%" + ) + MOVE /Y "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%" + if exist "%PRECOMPILED%" ( + DEL "%PRECOMPILED%" + ) +) + +REM There is no CUR_PACKAGE_INFO it was renamed in previous step to %PREV_PACKAGE_INFO% +REM which means we need to do pub get and precompile +if not exist "%PRECOMPILED%" ( + echo Running pub get in "%cd%" + "%DART%" pub get --no-precompile + "%DART%" compile kernel bin/build_tool_runner.dart +) + +"%DART%" "%PRECOMPILED%" %* + +REM 253 means invalid snapshot version. +If %ERRORLEVEL% equ 253 ( + "%DART%" pub get --no-precompile + "%DART%" compile kernel bin/build_tool_runner.dart + "%DART%" "%PRECOMPILED%" %* +) diff --git a/rust_builder/cargokit/run_build_tool.sh b/rust_builder/cargokit/run_build_tool.sh new file mode 100755 index 00000000..24b0ed89 --- /dev/null +++ b/rust_builder/cargokit/run_build_tool.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash + +set -e + +BASEDIR=$(dirname "$0") + +mkdir -p "$CARGOKIT_TOOL_TEMP_DIR" + +cd "$CARGOKIT_TOOL_TEMP_DIR" + +# Write a very simple bin package in temp folder that depends on build_tool package +# from Cargokit. This is done to ensure that we don't pollute Cargokit folder +# with .dart_tool contents. + +BUILD_TOOL_PKG_DIR="$BASEDIR/build_tool" + +if [[ -z $FLUTTER_ROOT ]]; then # not defined + DART=dart +else + DART="$FLUTTER_ROOT/bin/cache/dart-sdk/bin/dart" +fi + +cat << EOF > "pubspec.yaml" +name: build_tool_runner +version: 1.0.0 +publish_to: none + +environment: + sdk: '>=3.0.0 <4.0.0' + +dependencies: + build_tool: + path: "$BUILD_TOOL_PKG_DIR" +EOF + +mkdir -p "bin" + +cat << EOF > "bin/build_tool_runner.dart" +import 'package:build_tool/build_tool.dart' as build_tool; +void main(List args) { + build_tool.runMain(args); +} +EOF + +# Create alias for `shasum` if it does not exist and `sha1sum` exists +if ! [ -x "$(command -v shasum)" ] && [ -x "$(command -v sha1sum)" ]; then + shopt -s expand_aliases + alias shasum="sha1sum" +fi + +# Dart run will not cache any package that has a path dependency, which +# is the case for our build_tool_runner. So instead we precompile the package +# ourselves. +# To invalidate the cached kernel we use the hash of ls -LR of the build_tool +# package directory. This should be good enough, as the build_tool package +# itself is not meant to have any path dependencies. + +if [[ "$OSTYPE" == "darwin"* ]]; then + PACKAGE_HASH=$(ls -lTR "$BUILD_TOOL_PKG_DIR" | shasum) +else + PACKAGE_HASH=$(ls -lR --full-time "$BUILD_TOOL_PKG_DIR" | shasum) +fi + +PACKAGE_HASH_FILE=".package_hash" + +if [ -f "$PACKAGE_HASH_FILE" ]; then + EXISTING_HASH=$(cat "$PACKAGE_HASH_FILE") + if [ "$PACKAGE_HASH" != "$EXISTING_HASH" ]; then + rm "$PACKAGE_HASH_FILE" + fi +fi + +# Run pub get if needed. +if [ ! -f "$PACKAGE_HASH_FILE" ]; then + "$DART" pub get --no-precompile + "$DART" compile kernel bin/build_tool_runner.dart + echo "$PACKAGE_HASH" > "$PACKAGE_HASH_FILE" +fi + +# Rebuild the tool if it was deleted by Android Studio +if [ ! -f "bin/build_tool_runner.dill" ]; then + "$DART" compile kernel bin/build_tool_runner.dart +fi + +set +e + +"$DART" bin/build_tool_runner.dill "$@" + +exit_code=$? + +# 253 means invalid snapshot version. +if [ $exit_code == 253 ]; then + "$DART" pub get --no-precompile + "$DART" compile kernel bin/build_tool_runner.dart + "$DART" bin/build_tool_runner.dill "$@" + exit_code=$? +fi + +exit $exit_code diff --git a/rust_builder/ios/Classes/dummy_file.c b/rust_builder/ios/Classes/dummy_file.c new file mode 100644 index 00000000..e06dab99 --- /dev/null +++ b/rust_builder/ios/Classes/dummy_file.c @@ -0,0 +1 @@ +// This is an empty file to force CocoaPods to create a framework. diff --git a/rust_builder/ios/rust_lib_twonly.podspec b/rust_builder/ios/rust_lib_twonly.podspec new file mode 100644 index 00000000..50e8f7ce --- /dev/null +++ b/rust_builder/ios/rust_lib_twonly.podspec @@ -0,0 +1,45 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint rust_lib_twonly.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'rust_lib_twonly' + s.version = '0.0.1' + s.summary = 'A new Flutter FFI plugin project.' + s.description = <<-DESC +A new Flutter FFI plugin project. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + + # This will ensure the source files in Classes/ are included in the native + # builds of apps using this FFI plugin. Podspec does not support relative + # paths, so Classes contains a forwarder C file that relatively imports + # `../src/*` so that the C sources can be shared among all target platforms. + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'Flutter' + s.platform = :ios, '11.0' + + # Flutter.framework does not contain a i386 slice. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } + s.swift_version = '5.0' + + s.script_phase = { + :name => 'Build Rust library', + # First argument is relative path to the `rust` folder, second is name of rust library + :script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../rust rust_lib_twonly', + :execution_position => :before_compile, + :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'], + # Let XCode know that the static library referenced in -force_load below is + # created by this build step. + :output_files => ["${BUILT_PRODUCTS_DIR}/librust_lib_twonly.a"], + } + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + # Flutter.framework does not contain a i386 slice. + 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', + 'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib_twonly.a', + } +end \ No newline at end of file diff --git a/rust_builder/linux/CMakeLists.txt b/rust_builder/linux/CMakeLists.txt new file mode 100644 index 00000000..4fd90d2a --- /dev/null +++ b/rust_builder/linux/CMakeLists.txt @@ -0,0 +1,19 @@ +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +# Project-level configuration. +set(PROJECT_NAME "rust_lib_twonly") +project(${PROJECT_NAME} LANGUAGES CXX) + +include("../cargokit/cmake/cargokit.cmake") +apply_cargokit(${PROJECT_NAME} ../../rust rust_lib_twonly "") + +# List of absolute paths to libraries that should be bundled with the plugin. +# This list could contain prebuilt libraries, or libraries created by an +# external build triggered from this build file. +set(rust_lib_twonly_bundled_libraries + "${${PROJECT_NAME}_cargokit_lib}" + PARENT_SCOPE +) diff --git a/rust_builder/macos/Classes/dummy_file.c b/rust_builder/macos/Classes/dummy_file.c new file mode 100644 index 00000000..e06dab99 --- /dev/null +++ b/rust_builder/macos/Classes/dummy_file.c @@ -0,0 +1 @@ +// This is an empty file to force CocoaPods to create a framework. diff --git a/rust_builder/macos/rust_lib_twonly.podspec b/rust_builder/macos/rust_lib_twonly.podspec new file mode 100644 index 00000000..d2e23871 --- /dev/null +++ b/rust_builder/macos/rust_lib_twonly.podspec @@ -0,0 +1,44 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint rust_lib_twonly.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'rust_lib_twonly' + s.version = '0.0.1' + s.summary = 'A new Flutter FFI plugin project.' + s.description = <<-DESC +A new Flutter FFI plugin project. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + + # This will ensure the source files in Classes/ are included in the native + # builds of apps using this FFI plugin. Podspec does not support relative + # paths, so Classes contains a forwarder C file that relatively imports + # `../src/*` so that the C sources can be shared among all target platforms. + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'FlutterMacOS' + + s.platform = :osx, '10.11' + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + s.swift_version = '5.0' + + s.script_phase = { + :name => 'Build Rust library', + # First argument is relative path to the `rust` folder, second is name of rust library + :script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../rust rust_lib_twonly', + :execution_position => :before_compile, + :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'], + # Let XCode know that the static library referenced in -force_load below is + # created by this build step. + :output_files => ["${BUILT_PRODUCTS_DIR}/librust_lib_twonly.a"], + } + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + # Flutter.framework does not contain a i386 slice. + 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', + 'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib_twonly.a', + } +end \ No newline at end of file diff --git a/rust_builder/pubspec.yaml b/rust_builder/pubspec.yaml new file mode 100644 index 00000000..6da7e8bc --- /dev/null +++ b/rust_builder/pubspec.yaml @@ -0,0 +1,34 @@ +name: rust_lib_twonly +description: "Utility to build Rust code" +version: 0.0.1 +publish_to: none + +environment: + sdk: '>=3.3.0 <4.0.0' + flutter: '>=3.3.0' + +dependencies: + flutter: + sdk: flutter + plugin_platform_interface: ^2.0.2 + +dev_dependencies: + ffi: ^2.0.2 + ffigen: ^11.0.0 + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + +flutter: + plugin: + platforms: + android: + ffiPlugin: true + ios: + ffiPlugin: true + linux: + ffiPlugin: true + macos: + ffiPlugin: true + windows: + ffiPlugin: true diff --git a/rust_builder/windows/.gitignore b/rust_builder/windows/.gitignore new file mode 100644 index 00000000..b3eb2be1 --- /dev/null +++ b/rust_builder/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/rust_builder/windows/CMakeLists.txt b/rust_builder/windows/CMakeLists.txt new file mode 100644 index 00000000..17c8f52d --- /dev/null +++ b/rust_builder/windows/CMakeLists.txt @@ -0,0 +1,20 @@ +# The Flutter tooling requires that developers have a version of Visual Studio +# installed that includes CMake 3.14 or later. You should not increase this +# version, as doing so will cause the plugin to fail to compile for some +# customers of the plugin. +cmake_minimum_required(VERSION 3.14) + +# Project-level configuration. +set(PROJECT_NAME "rust_lib_twonly") +project(${PROJECT_NAME} LANGUAGES CXX) + +include("../cargokit/cmake/cargokit.cmake") +apply_cargokit(${PROJECT_NAME} ../../../../../../rust rust_lib_twonly "") + +# List of absolute paths to libraries that should be bundled with the plugin. +# This list could contain prebuilt libraries, or libraries created by an +# external build triggered from this build file. +set(rust_lib_twonly_bundled_libraries + "${${PROJECT_NAME}_cargokit_lib}" + PARENT_SCOPE +) diff --git a/test/drift/twonly_db/migration_test.dart b/test/drift/twonly_db/migration_test.dart index 3aa5929e..91310457 100644 --- a/test/drift/twonly_db/migration_test.dart +++ b/test/drift/twonly_db/migration_test.dart @@ -120,52 +120,92 @@ void main() { batch.insertAll(oldDb.receipts, oldReceiptsData); batch.insertAll(oldDb.receivedReceipts, oldReceivedReceiptsData); batch.insertAll( - oldDb.signalIdentityKeyStores, oldSignalIdentityKeyStoresData); + oldDb.signalIdentityKeyStores, + oldSignalIdentityKeyStoresData, + ); batch.insertAll(oldDb.signalPreKeyStores, oldSignalPreKeyStoresData); batch.insertAll( - oldDb.signalSenderKeyStores, oldSignalSenderKeyStoresData); + oldDb.signalSenderKeyStores, + oldSignalSenderKeyStoresData, + ); batch.insertAll(oldDb.signalSessionStores, oldSignalSessionStoresData); batch.insertAll( - oldDb.signalContactPreKeys, oldSignalContactPreKeysData); - batch.insertAll(oldDb.signalContactSignedPreKeys, - oldSignalContactSignedPreKeysData); + oldDb.signalContactPreKeys, + oldSignalContactPreKeysData, + ); + batch.insertAll( + oldDb.signalContactSignedPreKeys, + oldSignalContactSignedPreKeysData, + ); batch.insertAll(oldDb.messageActions, oldMessageActionsData); batch.insertAll(oldDb.groupHistories, oldGroupHistoriesData); }, validateItems: (newDb) async { expect( - expectedNewContactsData, await newDb.select(newDb.contacts).get()); + expectedNewContactsData, + await newDb.select(newDb.contacts).get(), + ); expect(expectedNewGroupsData, await newDb.select(newDb.groups).get()); - expect(expectedNewMediaFilesData, - await newDb.select(newDb.mediaFiles).get()); expect( - expectedNewMessagesData, await newDb.select(newDb.messages).get()); - expect(expectedNewMessageHistoriesData, - await newDb.select(newDb.messageHistories).get()); - expect(expectedNewReactionsData, - await newDb.select(newDb.reactions).get()); - expect(expectedNewGroupMembersData, - await newDb.select(newDb.groupMembers).get()); + expectedNewMediaFilesData, + await newDb.select(newDb.mediaFiles).get(), + ); expect( - expectedNewReceiptsData, await newDb.select(newDb.receipts).get()); - expect(expectedNewReceivedReceiptsData, - await newDb.select(newDb.receivedReceipts).get()); - expect(expectedNewSignalIdentityKeyStoresData, - await newDb.select(newDb.signalIdentityKeyStores).get()); - expect(expectedNewSignalPreKeyStoresData, - await newDb.select(newDb.signalPreKeyStores).get()); - expect(expectedNewSignalSenderKeyStoresData, - await newDb.select(newDb.signalSenderKeyStores).get()); - expect(expectedNewSignalSessionStoresData, - await newDb.select(newDb.signalSessionStores).get()); - expect(expectedNewSignalContactPreKeysData, - await newDb.select(newDb.signalContactPreKeys).get()); - expect(expectedNewSignalContactSignedPreKeysData, - await newDb.select(newDb.signalContactSignedPreKeys).get()); - expect(expectedNewMessageActionsData, - await newDb.select(newDb.messageActions).get()); - expect(expectedNewGroupHistoriesData, - await newDb.select(newDb.groupHistories).get()); + expectedNewMessagesData, + await newDb.select(newDb.messages).get(), + ); + expect( + expectedNewMessageHistoriesData, + await newDb.select(newDb.messageHistories).get(), + ); + expect( + expectedNewReactionsData, + await newDb.select(newDb.reactions).get(), + ); + expect( + expectedNewGroupMembersData, + await newDb.select(newDb.groupMembers).get(), + ); + expect( + expectedNewReceiptsData, + await newDb.select(newDb.receipts).get(), + ); + expect( + expectedNewReceivedReceiptsData, + await newDb.select(newDb.receivedReceipts).get(), + ); + expect( + expectedNewSignalIdentityKeyStoresData, + await newDb.select(newDb.signalIdentityKeyStores).get(), + ); + expect( + expectedNewSignalPreKeyStoresData, + await newDb.select(newDb.signalPreKeyStores).get(), + ); + expect( + expectedNewSignalSenderKeyStoresData, + await newDb.select(newDb.signalSenderKeyStores).get(), + ); + expect( + expectedNewSignalSessionStoresData, + await newDb.select(newDb.signalSessionStores).get(), + ); + expect( + expectedNewSignalContactPreKeysData, + await newDb.select(newDb.signalContactPreKeys).get(), + ); + expect( + expectedNewSignalContactSignedPreKeysData, + await newDb.select(newDb.signalContactSignedPreKeys).get(), + ); + expect( + expectedNewMessageActionsData, + await newDb.select(newDb.messageActions).get(), + ); + expect( + expectedNewGroupHistoriesData, + await newDb.select(newDb.groupHistories).get(), + ); }, ); }); diff --git a/test_driver/integration_test.dart b/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); From 87ba1c23e5b2a34e57bb9510eb10de76dca3f78d Mon Sep 17 00:00:00 2001 From: otsmr Date: Mon, 13 Apr 2026 02:28:41 +0200 Subject: [PATCH 02/86] started with ud --- rust/.gitignore | 2 + rust/Cargo.lock | 560 +++++++++++++++++- rust/Cargo.toml | 11 +- rust/build.rs | 5 + .../{user_discovery/memory.rs => sss/sss.rs} | 0 rust/src/twonly/database/contact.rs | 30 +- rust/src/twonly/mod.rs | 36 ++ rust/src/user_discovery/README.md | 10 + rust/src/user_discovery/error.rs | 28 + rust/src/user_discovery/mod.rs | 471 +++++++++++++++ .../user_discovery/stores/in_memory_store.rs | 102 ++++ rust/src/user_discovery/stores/mod.rs | 2 + rust/src/user_discovery/traits.rs | 50 ++ rust/src/user_discovery/types.proto | 52 ++ rust/tests/testing.db | Bin 0 -> 131072 bytes test/rust/create_db_for_rust_testing.dart | 56 ++ 16 files changed, 1394 insertions(+), 21 deletions(-) create mode 100644 rust/build.rs rename rust/src/{user_discovery/memory.rs => sss/sss.rs} (100%) create mode 100644 rust/src/user_discovery/README.md create mode 100644 rust/src/user_discovery/error.rs create mode 100644 rust/src/user_discovery/stores/in_memory_store.rs create mode 100644 rust/src/user_discovery/stores/mod.rs create mode 100644 rust/src/user_discovery/traits.rs create mode 100644 rust/src/user_discovery/types.proto create mode 100644 rust/tests/testing.db create mode 100644 test/rust/create_db_for_rust_testing.dart diff --git a/rust/.gitignore b/rust/.gitignore index ea8c4bf7..dfb400ce 100644 --- a/rust/.gitignore +++ b/rust/.gitignore @@ -1 +1,3 @@ /target + +tests/tmp_testing.db* \ No newline at end of file diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 5276fa8d..12b01045 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -71,9 +71,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "atoi" @@ -90,6 +90,15 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -132,6 +141,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "blahaj" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5106bf2680d585dc5f29711b8aa5dde353180b8e14af89b7f0424f760c84e7ce" +dependencies = [ + "hashbrown 0.15.5", + "rand 0.8.5", + "zeroize", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -187,6 +207,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.0", +] + [[package]] name = "chrono" version = "0.4.44" @@ -198,6 +229,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -238,6 +278,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -253,6 +302,12 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -360,6 +415,18 @@ dependencies = [ "serde", ] +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "env_filter" version = "0.1.4" @@ -408,12 +475,24 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flume" version = "0.11.1" @@ -609,12 +688,35 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core 0.10.0", + "wasip2", + "wasip3", +] + [[package]] name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -627,6 +729,8 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ + "allocator-api2", + "equivalent", "foldhash 0.1.5", ] @@ -656,6 +760,20 @@ dependencies = [ "hashbrown 0.15.5", ] +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin 0.9.8", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.5.0" @@ -807,6 +925,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "idna" version = "1.1.0" @@ -836,6 +960,17 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown 0.17.0", + "serde", + "serde_core", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", ] [[package]] @@ -862,6 +997,12 @@ dependencies = [ "spin 0.5.2", ] +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" version = "0.2.184" @@ -897,6 +1038,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + [[package]] name = "litemap" version = "0.8.2" @@ -954,6 +1101,21 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "num-bigint-dig" version = "0.8.6" @@ -965,7 +1127,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.5", "smallvec", "zeroize", ] @@ -1080,6 +1242,17 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -1131,6 +1304,19 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "heapless", + "serde", +] + [[package]] name = "potential_utf" version = "0.1.5" @@ -1149,6 +1335,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -1158,6 +1354,57 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" +dependencies = [ + "heck", + "itertools", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +dependencies = [ + "prost", +] + [[package]] name = "quote" version = "1.0.45" @@ -1167,6 +1414,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.8.5" @@ -1175,7 +1428,18 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.0", ] [[package]] @@ -1185,7 +1449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1194,9 +1458,15 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + [[package]] name = "redox_syscall" version = "0.5.18" @@ -1257,7 +1527,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "signature", "spki", "subtle", @@ -1268,11 +1538,18 @@ dependencies = [ name = "rust_lib_twonly" version = "0.1.0" dependencies = [ + "blahaj", "flutter_rust_bridge", + "postcard", + "prost", + "prost-build", + "rand 0.10.1", + "serde", "sqlx", "thiserror", "tokio", "tracing", + "tracing-subscriber", ] [[package]] @@ -1281,6 +1558,28 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + [[package]] name = "ryu" version = "1.0.23" @@ -1293,6 +1592,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -1355,7 +1660,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] @@ -1366,10 +1671,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1393,7 +1707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1565,7 +1879,7 @@ dependencies = [ "md-5", "memchr", "percent-encoding", - "rand", + "rand 0.8.5", "rsa", "serde", "sha1", @@ -1603,7 +1917,7 @@ dependencies = [ "log", "md-5", "memchr", - "rand", + "rand 0.8.5", "serde", "serde_json", "sha2", @@ -1685,6 +1999,18 @@ dependencies = [ "syn", ] +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + [[package]] name = "thiserror" version = "2.0.18" @@ -1705,6 +2031,15 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "threadpool" version = "1.8.1" @@ -1808,6 +2143,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] @@ -1843,6 +2204,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "url" version = "2.5.8" @@ -1861,6 +2228,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcpkg" version = "0.2.15" @@ -1879,6 +2252,24 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasite" version = "0.1.0" @@ -1951,6 +2342,40 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "web-sys" version = "0.3.66" @@ -2030,6 +2455,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -2112,6 +2546,94 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "writeable" version = "0.6.3" @@ -2187,6 +2709,20 @@ name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "zerotrie" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 528bd713..1ee66891 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -20,6 +20,13 @@ sqlx = { version = "0.9.0-alpha.1", default-features = false, features = [ ] } tokio = { version = "1.44", features = ["full"] } tracing = "0.1.44" +serde = "1.0.228" +prost = "0.14.1" +rand = "0.10.1" +tracing-subscriber = "0.3.23" +blahaj = "0.6.0" +postcard = { version = "1.1.3", features = ["alloc"] } -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(frb_expand)'] } + +[build-dependencies] +prost-build = "0.14.1" diff --git a/rust/build.rs b/rust/build.rs new file mode 100644 index 00000000..135361e9 --- /dev/null +++ b/rust/build.rs @@ -0,0 +1,5 @@ +use std::io::Result; +fn main() -> Result<()> { + prost_build::compile_protos(&["src/user_discovery/types.proto"], &["src/"])?; + Ok(()) +} diff --git a/rust/src/user_discovery/memory.rs b/rust/src/sss/sss.rs similarity index 100% rename from rust/src/user_discovery/memory.rs rename to rust/src/sss/sss.rs diff --git a/rust/src/twonly/database/contact.rs b/rust/src/twonly/database/contact.rs index 9d48df43..084d3e09 100644 --- a/rust/src/twonly/database/contact.rs +++ b/rust/src/twonly/database/contact.rs @@ -1,9 +1,5 @@ -// Table is defined in contacts.table.dart - -use sqlx::{ - types::chrono::{DateTime, Utc}, - FromRow, -}; +// use sqlx::types::chrono::{DateTime, Utc}; +use sqlx::FromRow; use crate::twonly::{database::Database, error::Result}; @@ -11,7 +7,7 @@ use crate::twonly::{database::Database, error::Result}; struct ContactRow { pub(crate) user_id: i64, pub(crate) username: String, - pub(crate) created_at: DateTime, + // pub(crate) created_at: DateTime, } pub struct Contact { @@ -38,3 +34,23 @@ impl Contact { Ok(rows.into_iter().map(Into::into).collect()) } } + +#[cfg(test)] +mod tests { + use crate::twonly::{database::contact::Contact, tests::initialize_twonly_for_testing}; + + #[tokio::test] + async fn test_get_all_contacts() { + let twonly = initialize_twonly_for_testing().await.unwrap(); + + let contacts = Contact::get_all_contacts(&twonly.database).await.unwrap(); + + let users = vec!["alice", "bob", "charlie", "diana", "eve", "frank", "grace"]; + + assert_eq!(contacts.len(), users.len()); + + for contact in contacts { + assert_eq!(users[contact.user_id as usize], &contact.username); + } + } +} diff --git a/rust/src/twonly/mod.rs b/rust/src/twonly/mod.rs index 9186868e..bf4e0f95 100644 --- a/rust/src/twonly/mod.rs +++ b/rust/src/twonly/mod.rs @@ -11,6 +11,7 @@ pub struct TwonlyConfig { } struct Twonly { + #[allow(dead_code)] pub(crate) config: TwonlyConfig, database: Arc, } @@ -39,3 +40,38 @@ pub async fn get_all_contacts() -> Result> { let twonly = get_instance()?; Contact::get_all_contacts(twonly.database.as_ref()).await } + +#[cfg(test)] +pub(crate) mod tests { + use super::error::Result; + use super::Twonly; + use std::path::PathBuf; + + use crate::twonly::{get_instance, initialize_twonly, TwonlyConfig}; + + pub(super) async fn initialize_twonly_for_testing() -> Result<&'static Twonly> { + let default_twonly_database = PathBuf::from("tests/testing.db"); + + if !default_twonly_database.is_file() { + panic!("{} not found!", default_twonly_database.display()) + } + + let copied_twonly_database = default_twonly_database + .parent() + .unwrap() + .join("tmp_testing.db"); + if copied_twonly_database.exists() { + std::fs::remove_file(&copied_twonly_database).unwrap(); + } + + std::fs::copy(default_twonly_database, &copied_twonly_database).unwrap(); + + initialize_twonly(TwonlyConfig { + database_path: copied_twonly_database.display().to_string(), + }) + .await + .unwrap(); + + get_instance() + } +} diff --git a/rust/src/user_discovery/README.md b/rust/src/user_discovery/README.md new file mode 100644 index 00000000..1a5368ba --- /dev/null +++ b/rust/src/user_discovery/README.md @@ -0,0 +1,10 @@ + + + + // **Store** promotions: + // version_id, contact_id, Option + // -> In case a contact_id deleted his account deleted or was removed + // - Remove the previous row (version_id must be increased...) + // - Create a new entry with User Discovery Recall + // -> Otherwise this promotion contains the Promotion + // \ No newline at end of file diff --git a/rust/src/user_discovery/error.rs b/rust/src/user_discovery/error.rs new file mode 100644 index 00000000..0c0246ea --- /dev/null +++ b/rust/src/user_discovery/error.rs @@ -0,0 +1,28 @@ +use prost::DecodeError; +use thiserror::Error; + +pub type Result = core::result::Result; + +#[derive(Error, Debug)] +pub enum UserDiscoveryError { + #[error("The encrypted announcement data contains malicious data: `{0}`")] + MaliciousAnnouncementData(String), + + #[error("no shares left.")] + NoSharesLeft, + + #[error("User discovery contains no configuration.")] + NotInitialized, + + #[error("`{0}`")] + PostcardError(#[from] postcard::Error), + + #[error("error while calculating shamirs secret shares: `{0}`")] + ShamirsSecret(String), + + #[error("tried to push a invalid version")] + PushedInvalidVersion, + + #[error("`{0}`")] + Prost(#[from] DecodeError), +} diff --git a/rust/src/user_discovery/mod.rs b/rust/src/user_discovery/mod.rs index e69de29b..6701a673 100644 --- a/rust/src/user_discovery/mod.rs +++ b/rust/src/user_discovery/mod.rs @@ -0,0 +1,471 @@ +mod error; +pub mod stores; +mod traits; + +use blahaj::{Share, Sharks}; +use postcard::{from_bytes, to_allocvec}; +use prost::Message; +use serde::{Deserialize, Serialize}; +use crate::user_discovery::error::{Result, UserDiscoveryError}; +use crate::user_discovery::traits::UserDiscoveryUtils; +use crate::user_discovery::user_discovery_message::{UserDiscoveryAnnouncement, UserDiscoveryPromotion}; +use crate::user_discovery::user_discovery_message::user_discovery_promotion::AnnouncementShareDecrypted; +use crate::user_discovery::user_discovery_message::user_discovery_promotion::announcement_share_decrypted::SignedData; +pub use traits::UserDiscoveryStore; + +pub type UserID = i64; + +include!(concat!(env!("OUT_DIR"), "/_.rs")); + +#[derive(Serialize, Deserialize, Clone, Debug)] +struct UserDiscoveryConfig { + /// The number of required shares to get the secret + threshold: u8, + /// Currently limited to <= 255 as GF 256 is used + total_number_of_shares: usize, + /// Version of announcements + announcement_version: u32, + /// Version of promotions + promotion_version: u32, + /// This is a random public_id associated with a single announcement. + public_id: u64, + /// Verification shares + verification_shares: Vec>, +} + +impl Default for UserDiscoveryConfig { + fn default() -> Self { + Self { + threshold: 2, + total_number_of_shares: 255, + announcement_version: 0, + promotion_version: 0, + verification_shares: vec![], + public_id: 0, + } + } +} + +pub struct UserDiscovery +where + Store: UserDiscoveryStore, + Utils: UserDiscoveryUtils, +{ + store: Store, + utils: Utils, +} + +impl UserDiscovery { + pub fn new(store: Store, utils: Utils) -> Result { + Ok(Self { store, utils }) + } + + pub fn initialize_or_update( + &self, + threshold: u8, + user_id: UserID, + public_key: Vec, + ) -> Result<()> { + let mut config = match self.store.get_config() { + Ok(config) => { + let mut config: UserDiscoveryConfig = from_bytes(&config)?; + config.threshold = threshold; + config + } + Err(_) => UserDiscoveryConfig { + threshold, + ..Default::default() + }, + }; + + let public_id = rand::random(); + + let signed_data = SignedData { + public_id, + user_id, + public_key, + }; + + let signature = self.utils.sign_data(signed_data.encode_to_vec())?; + + let verification_shares = self.setup_announcements(&config, signed_data, signature)?; + + config.public_id = public_id; + config.announcement_version += 1; + config.verification_shares = verification_shares; + + self.store.update_config(to_allocvec(&config)?)?; + + Ok(()) + } + + fn setup_announcements( + &self, + config: &UserDiscoveryConfig, + signed_data: SignedData, + signature: Vec, + ) -> Result>> { + tracing::debug!( + "Initializing user discovery with {} total shares and with a threshold of {}", + config.total_number_of_shares, + config.threshold + ); + + let encrypted_announcement = AnnouncementShareDecrypted { + signed_data: Some(signed_data), + signature, + } + .encode_to_vec(); + + let sharks = Sharks(config.threshold as u8); + let dealer = sharks.dealer(&encrypted_announcement); + + let mut shares: Vec> = dealer + .take(config.total_number_of_shares) + .map(|x| Vec::from(&x)) + .collect(); + + if shares.len() != config.total_number_of_shares as usize + || shares.is_empty() + || shares.len() <= (config.threshold as usize * 2) + { + return Err(UserDiscoveryError::ShamirsSecret( + "Invalid length of shares where generated".to_string(), + )); + } + + tracing::debug!( + "Generated {} shares each with a size of: {}", + shares.len(), + shares[0].len() + ); + + let mut verification_shares = vec![]; + + let split_index = shares.len() - (config.threshold - 1) as usize; + verification_shares.extend(shares.drain(split_index..)); + + self.store.set_shares(shares)?; + + Ok(verification_shares) + } + + fn get_config(&self) -> Result { + Ok(from_bytes(&self.store.get_config()?)?) + } + + /// Returns the current version of the user discovery. + pub fn get_current_version(&self) -> Result> { + let config = self.get_config()?; + Ok(UserDiscoveryVersion { + announcement: config.announcement_version, + promotion: config.promotion_version, + } + .encode_to_vec()) + } + + /// Returns all new user discovery messages for the provided contact + pub fn get_new_messages( + &self, + contact_id: UserID, + received_version: &[u8], + ) -> Result>> { + let mut messages = vec![]; + let received_version = UserDiscoveryVersion::decode(received_version)?; + + let config = self.get_config()?; + let version = Some(UserDiscoveryVersion { + announcement: config.announcement_version, + promotion: config.promotion_version, + }); + + if received_version.announcement < config.announcement_version { + tracing::info!("New announcement message available for {}", contact_id); + + let announcement_share = self.store.get_share_for_contact(contact_id)?; + + let user_discovery_announcement = Some(UserDiscoveryAnnouncement { + public_id: config.public_id, + threshold: config.threshold as u32, + announcement_share, + verification_shares: config.verification_shares, + }); + + messages.push( + UserDiscoveryMessage { + user_discovery_announcement, + version, + ..Default::default() + } + .encode_to_vec(), + ); + + // messages.push(value); + } + if received_version.promotion < config.promotion_version { + tracing::info!("New promotion message available for user {}", contact_id); + let promoting_messages = self + .store + .get_promotions_after_version(received_version.promotion)?; + messages.extend_from_slice(&promoting_messages); + } + Ok(messages) + } + + /// Checks if the provided user has new announcements. + /// In this case the user should be requested to send there updates. + pub fn should_request_new_messages(&self, contact_id: UserID, version: &[u8]) -> Result { + let received_version = UserDiscoveryVersion::decode(version)?; + let stored_version = match self.store.get_contact_version(contact_id)? { + Some(buf) => UserDiscoveryVersion::decode(buf.as_slice())?, + None => UserDiscoveryVersion { + announcement: 0, + promotion: 0, + }, + }; + Ok(received_version.announcement > stored_version.announcement + || received_version.promotion < received_version.promotion) + } + + pub(crate) fn get_contact_version(&self, contact_id: UserID) -> Result>> { + self.store.get_contact_version(contact_id) + } + + /// Returns the latest version for this discovery. + /// Before calling this function the application must sure that contact_id is qualified to be announced. + pub fn handle_user_discovery_messages( + &self, + contact_id: UserID, + messages: Vec>, + ) -> Result<()> { + for message in messages { + let message = UserDiscoveryMessage::decode(message.as_slice())?; + let Some(version) = message.version else { + continue; + }; + + if let Some(uda) = message.user_discovery_announcement { + self.handle_user_discovery_announcement(contact_id, uda)?; + } + if let Some(udp) = message.user_discovery_promotion { + self.handle + tracing::info!("Got UDP from {contact_id}"); + } + + self.store + .set_contact_version(contact_id, version.encode_to_vec())?; + } + + Ok(()) + } + + fn handle_user_discovery_announcement( + &self, + contact_id: UserID, + uda: UserDiscoveryAnnouncement, + ) -> Result<()> { + tracing::info!("Got a user discovery announcement from {contact_id}."); + + if uda.threshold as usize != uda.verification_shares.len() + 1 { + tracing::error!( + "UDA contains to few shares to verify: {} != {} + 1.", + uda.threshold, + uda.verification_shares.len(), + ); + return Ok(()); + } + + let sharks = Sharks(uda.threshold as u8); + + let mut all_shares = uda.verification_shares.clone(); + all_shares.push(uda.announcement_share.clone()); + let shares: Vec<_> = all_shares + .iter() + .filter_map(|x| Share::try_from(x.as_slice()).ok()) + .collect(); + + match sharks.recover(&shares) { + Ok(secret) => { + let asd = AnnouncementShareDecrypted::decode(secret.as_slice())?; + + let Some(signed_data) = asd.signed_data else { + return Err(UserDiscoveryError::MaliciousAnnouncementData( + "missing signed data".into(), + )); + }; + + if contact_id != signed_data.user_id { + return Err(UserDiscoveryError::MaliciousAnnouncementData(format!( + "contact_id ({contact_id}) != signed_data.user_id ({})", + signed_data.user_id + ))); + } + + if !self.utils.verify_pubkey_and_signature_from( + contact_id, + signed_data.encode_to_vec(), + signed_data.public_key, + asd.signature, + )? { + return Err(UserDiscoveryError::MaliciousAnnouncementData(format!( + "signature invalid or public key does not match with stored one", + ))); + } + + let mut config = self.get_config()?; + config.promotion_version += 1; + self.store.update_config(to_allocvec(&config)?)?; + + let message = UserDiscoveryMessage { + version: Some(UserDiscoveryVersion { + announcement: config.announcement_version, + promotion: config.promotion_version, + }), + user_discovery_promotion: Some(UserDiscoveryPromotion { + promotion_id: rand::random(), + public_id: signed_data.public_id, + threshold: uda.threshold, + announcement_share: uda.announcement_share, + verification_state: None, + }), + ..Default::default() + }; + + self.store + .push_promotion(config.promotion_version, message.encode_to_vec())?; + + Ok(()) + } + Err(err) => { + return Err(UserDiscoveryError::ShamirsSecret(err.to_string())); + } + } + } + + fn handle_user_discovery_promotion( + &self, + contact_id: UserID, + uda: UserDiscoveryPromotion, + ) { + + // contact_id + // uda.promotion_id + // uda.public_id + // uda.threshold + // uda.announcement_share + // uda.verification_state + + // store this into the received_promotion_table + // check if the threshold is reached + // in case thr threshold is reached -> CALL STORE -> NEW USER + // otherwise do nothing + + } + +} + +#[cfg(test)] +mod tests { + + use crate::user_discovery::stores::InMemoryStore; + use crate::user_discovery::traits::tests::TestingUtils; + use crate::user_discovery::{UserDiscovery, UserDiscoveryVersion, UserID}; + use prost::Message; + + fn get_version_bytes(announcement: u32, promotion: u32) -> Vec { + UserDiscoveryVersion { + announcement, + promotion, + } + .encode_to_vec() + } + + fn zero() -> Vec { + get_version_bytes(0, 0) + } + + fn get_ud(user_id: UserID, friends: &[UserID]) -> UserDiscovery { + let store = InMemoryStore::default(); + store.set_friends(friends.iter().copied().collect()); + let ud = UserDiscovery::new(store.to_owned(), TestingUtils::default()).unwrap(); + + ud.initialize_or_update(3, user_id, vec![user_id as u8; 32]) + .unwrap(); + + let version = ud.get_current_version().unwrap(); + + assert_eq!(version, get_version_bytes(1, 0)); + ud + } + + fn init() { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::DEBUG) + .init(); + } + + fn request_and_handle_messages( + from: (UserID, &UserDiscovery), + to: (UserID, &UserDiscovery), + messages_count: usize, + ) { + // From sends a message with his current version to To + let to_received_version = &from.1.get_current_version().unwrap(); + assert_eq!( + to.1.should_request_new_messages(from.0, to_received_version) + .unwrap(), + true + ); + + // As To has a older version stored he sends a request to From: Give me all messages since version. + let from_request_version_from_to = + to.1.get_contact_version(from.0).unwrap().unwrap_or(zero()); + + let new_messages = from + .1 + .get_new_messages(to.0, &from_request_version_from_to) + .unwrap(); + + assert_eq!(new_messages.len(), messages_count); + + to.1.handle_user_discovery_messages(from.0, new_messages) + .unwrap(); + + assert_eq!( + to.1.should_request_new_messages(from.0, &from.1.get_current_version().unwrap()) + .unwrap(), + false + ); + } + + #[tokio::test] + async fn test_initialize_user_discovery() { + init(); + + const ALICE: UserID = 0; + const BOB: UserID = 1; + const CHARLIE: UserID = 2; + const DAVID: UserID = 3; + const FRANK: UserID = 4; + + let alice_ud = get_ud(ALICE, &[BOB, CHARLIE]); + let bob_ud = get_ud(BOB, &[ALICE, CHARLIE, DAVID]); + let charlie_ud = get_ud(CHARLIE, &[ALICE, BOB, DAVID, FRANK]); + let david_ud = get_ud(DAVID, &[BOB, CHARLIE]); + let frank_ud = get_ud(FRANK, &[CHARLIE]); + + { + // Alice send UDA to Bob and Charlie + request_and_handle_messages((ALICE, &alice_ud), (BOB, &bob_ud), 1); + request_and_handle_messages((ALICE, &alice_ud), (CHARLIE, &charlie_ud), 1); + } + + { + // This now contains Bob's own announcement in addition this now also contains the promotion from Alice + request_and_handle_messages((BOB, &bob_ud), (DAVID, &david_ud), 2); + request_and_handle_messages((BOB, &bob_ud), (CHARLIE, &charlie_ud), 2); + } + + todo!(); + } +} diff --git a/rust/src/user_discovery/stores/in_memory_store.rs b/rust/src/user_discovery/stores/in_memory_store.rs new file mode 100644 index 00000000..2b7ec34a --- /dev/null +++ b/rust/src/user_discovery/stores/in_memory_store.rs @@ -0,0 +1,102 @@ +use crate::user_discovery::error::UserDiscoveryError; +use crate::user_discovery::traits::UserDiscoveryStore; +use crate::user_discovery::UserID; +use std::collections::{HashMap, HashSet}; +use std::sync::{Arc, Mutex}; + +#[derive(Default)] +pub(crate) struct Storage { + config: Option>, + unused_shares: Vec>, + used_shares: HashMap>, + contact_versions: HashMap>, + friends: HashSet, + promotions: Vec>, +} + +#[derive(Default, Clone)] +pub struct InMemoryStore { + pub(crate) storage: Arc>, +} + +impl InMemoryStore { + fn storage(&self) -> std::sync::MutexGuard<'_, Storage> { + self.storage.lock().unwrap() + } + pub fn set_friends(&self, friends: HashSet) { + self.storage().friends = friends; + } +} + +impl UserDiscoveryStore for InMemoryStore { + fn get_config(&self) -> crate::user_discovery::error::Result> { + if let Some(storage) = self.storage().config.clone() { + return Ok(storage); + } + Err(UserDiscoveryError::NotInitialized) + } + + fn update_config(&self, update: Vec) -> crate::user_discovery::error::Result<()> { + self.storage().config = Some(update); + Ok(()) + } + + fn set_shares(&self, shares: Vec>) -> crate::user_discovery::error::Result<()> { + self.storage().unused_shares = shares; + Ok(()) + } + + fn get_share_for_contact( + &self, + contact_id: UserID, + ) -> crate::user_discovery::error::Result> { + let mut storage = self.storage(); + if let Some(share) = storage.used_shares.get(&contact_id) { + return Ok(share.to_vec()); + } + if let Some(new_share) = storage.unused_shares.pop() { + storage.used_shares.insert(contact_id, new_share.clone()); + return Ok(new_share); + } + Err(UserDiscoveryError::NoSharesLeft) + } + + fn get_contact_version( + &self, + contact_id: UserID, + ) -> crate::user_discovery::error::Result>> { + Ok(self.storage().contact_versions.get(&contact_id).cloned()) + } + + fn set_contact_version( + &self, + contact_id: UserID, + update: Vec, + ) -> crate::user_discovery::error::Result<()> { + self.storage().contact_versions.insert(contact_id, update); + Ok(()) + } + + fn push_promotion( + &self, + version: u32, + promotion: Vec, + ) -> crate::user_discovery::error::Result<()> { + let mut storage = self.storage(); + // println!("{} != {}", version, storage.promotions.len()); + if version as usize != storage.promotions.len() + 1 { + return Err(UserDiscoveryError::PushedInvalidVersion); + } + storage.promotions.push(promotion); + Ok(()) + } + + fn get_promotions_after_version( + &self, + version: u32, + ) -> crate::user_discovery::error::Result>> { + let storage = self.storage(); + let elements = storage.promotions[(version as usize)..].to_vec(); + Ok(elements) + } +} diff --git a/rust/src/user_discovery/stores/mod.rs b/rust/src/user_discovery/stores/mod.rs new file mode 100644 index 00000000..c22f0a9e --- /dev/null +++ b/rust/src/user_discovery/stores/mod.rs @@ -0,0 +1,2 @@ +mod in_memory_store; +pub use in_memory_store::InMemoryStore; diff --git a/rust/src/user_discovery/traits.rs b/rust/src/user_discovery/traits.rs new file mode 100644 index 00000000..67dca8cb --- /dev/null +++ b/rust/src/user_discovery/traits.rs @@ -0,0 +1,50 @@ +use crate::user_discovery::error::Result; +use crate::user_discovery::UserID; + +pub trait UserDiscoveryStore { + fn get_config(&self) -> Result>; + fn update_config(&self, update: Vec) -> Result<()>; + fn set_shares(&self, shares: Vec>) -> Result<()>; + + fn get_share_for_contact(&self, contact_id: UserID) -> Result>; + + fn push_promotion(&self, version: u32, promotion: Vec) -> Result<()>; + fn get_promotions_after_version(&self, version: u32) -> Result>>; + + fn get_contact_version(&self, contact_id: UserID) -> Result>>; + fn set_contact_version(&self, contact_id: UserID, update: Vec) -> Result<()>; +} + +pub trait UserDiscoveryUtils { + fn sign_data(&self, input_data: Vec) -> Result>; + fn verify_pubkey_and_signature_from( + &self, + from_contact_id: UserID, + data: Vec, + pubkey: Vec, + signature: Vec, + ) -> Result; +} + +#[cfg(test)] +pub(crate) mod tests { + use crate::user_discovery::traits::UserDiscoveryUtils; + + #[derive(Default)] + pub(crate) struct TestingUtils {} + impl UserDiscoveryUtils for TestingUtils { + fn sign_data(&self, _input_data: Vec) -> crate::user_discovery::error::Result> { + Ok(vec![0; 64]) + } + + fn verify_pubkey_and_signature_from( + &self, + from_contact_id: crate::user_discovery::UserID, + data: Vec, + pubkey: Vec, + signature: Vec, + ) -> crate::user_discovery::error::Result { + Ok(true) + } + } +} diff --git a/rust/src/user_discovery/types.proto b/rust/src/user_discovery/types.proto new file mode 100644 index 00000000..f719ecec --- /dev/null +++ b/rust/src/user_discovery/types.proto @@ -0,0 +1,52 @@ +syntax = "proto3"; + +message UserDiscoveryVersion { + uint32 announcement = 1; + uint32 promotion = 2; +} + +message UserDiscoveryMessage { + + UserDiscoveryVersion version = 1; + + optional UserDiscoveryAnnouncement user_discovery_announcement = 2; + optional UserDiscoveryPromotion user_discovery_promotion = 3; + optional UserDiscoveryRecall user_discovery_recall = 4; + + message UserDiscoveryAnnouncement { + uint64 public_id = 1; + uint32 threshold = 2; + bytes announcement_share = 4; + repeated bytes verification_shares = 5; + } + + message UserDiscoveryPromotion { + uint32 promotion_id = 1; + uint64 public_id = 2; + uint32 threshold = 3; + bytes announcement_share = 5; + + optional VerificationState verification_state = 6; + + message AnnouncementShareDecrypted { + message SignedData { + uint64 public_id = 1; + int64 user_id = 2; + bytes public_key = 3; + } + SignedData signed_data = 1; + bytes signature = 2; + } + + message VerificationState { + int64 timestamp = 1; + bytes signature = 2; + } + + } + + message UserDiscoveryRecall { + int64 promotion_id = 1; + } + +} diff --git a/rust/tests/testing.db b/rust/tests/testing.db new file mode 100644 index 0000000000000000000000000000000000000000..df0d8a5baf3e0f4458a74ca7baa6b4a04e138e4c GIT binary patch literal 131072 zcmeI*Pi))P9S3m9b|fc}Hh{F(lX;11Rwwb2tWV=5P$##AOHafKmY=V zEO4qo1)iLkqW|WnH!{=znEuQ3@1{SQzCUfzSNuQ#0uX=z1Rwwb2tWV=5P$##ATU@! z%AN7wolgco6WfknXXfAk`nhx>p3rdg)-F#tKXE2=jtY&=VEaM-@pyj2)LS~wKQneF z^Ma7SzN0&q>7R2x8!u|h-tsS6=-|EHJ!_<;ZfAOHafKmY;|fB*y_009U< z;0YEu#oLDc{}bH9Xc`0{009U<00Izz00bZa0SG`KlfnCcL;(aK009U<00Izz00bZa z0SG|g$rr%;|0lnX(LxA700Izz00bZa0SG_<0uX=z-v1*8AOHafKmY;|fB*y_009U< z00K|G0N(#U`F)HQLI45~fB*y_009U<00Izz00gEAzsXFDf0QYFk^5)iv+<9{-yDBs z{1v!B00NIq;JuBBy!6sb*$ug^wpHRkd7Gr}%5=gOsv3-XepP;Fh$b{Mr{ zhyuG=h4W2UGaS9)X}-@;+x&B#J_-c~Y7PrUc{7>oF+kB)-)~4bXnbQ8EFMJ?R`ejhH1yICWywf2-WU%qG#_i>Ypns z>sO+HV6D1y(B}Q7?J}xkpR}f4@0-@LTXhN>@ywt%{HWD-bayA7T6Y))nxW~Q(3UVp zJF!x#ls9T6*K-=4*<_`;m)*Gqxw2WUs%tf^w!Ert)XJ+j6uG<+g$ECr8`b62a`mQs zUA-xe14a4Z@>pJ)naO^<>5r;y$KGqZ!GFi&V<|YuhmrqDOB+TMB|)NYG|k~6K6#4J zLpGCx&GZc`d!!nX9|=doXvJ3 zTQq-Z4aa1yfo=LTI~r7vev@DCoba7*fAb>$A;^a~hZHTHnjF?p zbK?yUEMqxn+_Ij*BIIgV)KL*QAKoqAF`XbupMo?dt!1A4vA+BDG( z%GMpRLgvIs)X&!QCYFE+Li|-B#pM zIPmz+HmGjejyt$$dvA;WkzZ{@{yh&42`FgTKr6i%tr%~uSZX!jdD9el{+URliNq{?i+*a(?u(H?!8 ze19S5FWY}UFZN&5ZEilbxA=tJ?}?2#xQ3nH`*vS!2*fsO;$@O!n9fUo`pUEV4n4gUB~%+Y#Sp1Z8xeqCW5mZtn@g zN;XJxSmG9y*s65)AjwmN@&-M>ytQY0^awiHTR~Lwr)1$XAHJ*gck@H;W%{2gR4r&? z{7GhT(QR4x5n`;guuAO#u7<oS65P$##AOHaf zKmY;|fB*y_0Dh1T8P0$J1Rwwb z2tWV=5P$##AOHaf95(^H|37X$hWbJP0uX=z1Rwwb2tWV=5P$##Mi;>Q|Iy8G1_U4g z0SG_<0uX=z1Rwwb2teSt3E=(zaqBVE7XlD~00bZa0SG_<0uX=z1RyZF0N($PZiX`; z009U<00Izz00bZa0SG_<0>@1N@BfcmkD|l^%gpqj3coM>^z^S!zj^Ay$v;p2G5^WrR_;Rn^@-|*G)McoMVxKv(n1=CRE^)>mbx}ws>E9H$!`Kn4q)$Nw2 z*FFC-%WF0DRkiA0MJy}Kla(N@Vra}fcs>`e8>P`8& zdNZxt6y@@ZIqCKJY{qOE?2dcOGO0oOo@e{t!`64=L|f{K1^M3T89%P>uljKnQfNVg z+@7zq@wn?bSZo9ZND>JbGxNmnoHr$qm$1S{A0?&7vde8num9BMix1@P zC=dr=_h@u^henh`6U~*C^(*2;Q+Jro$M{1ZJl)C@xL;RAS$-}j{p3==(Ua<+Eu|iQ z@tw-~yma|;_U=p^pT?!5?XrVj|DNMBeY&708}9{|bq@9;k1`~<g}FgXEI zd}Q$_R8Ubi&gG=-@&lYrgS9-xS&XfQTt9+XlnRI8SC1w;)$yuwjbX<}v zuc?*m6bjKoIQ?|Fba6pm;>*UOpJ9tp;T~-e3~lRxmbr$hYkO_W)>Ed)&c!ZvE;d9N z!WEmkv#T|1$G_x((3)T^9#0OJ+Iqdt+H~_z009U<00Izz z00bZa0SG_<0*4`hzyE(2iYNmD5P$##AOHafKmY;|fB*y_aI^*R{{LwA4{8Si2tWV= z5P$##AOHafKmY;|I1B;2|33^xlmP(z{}fB*y_009U<00Izz00a(00Pp_~LlI>_00Izz00bZa0SG_<0uX=z1dg`A{{UKs BjdB10 literal 0 HcmV?d00001 diff --git a/test/rust/create_db_for_rust_testing.dart b/test/rust/create_db_for_rust_testing.dart new file mode 100644 index 00000000..a9c308f6 --- /dev/null +++ b/test/rust/create_db_for_rust_testing.dart @@ -0,0 +1,56 @@ +import 'dart:io'; +import 'package:drift/drift.dart' show Value; +import 'package:drift/native.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:twonly/src/database/twonly.db.dart'; + +void main() { + if (!Platform.isMacOS) return; + late TwonlyDB database; + late File dbFile; + + setUp(() { + dbFile = File('rust/tests/testing.db'); + if (dbFile.existsSync()) { + dbFile.deleteSync(); + } + database = TwonlyDB(NativeDatabase(dbFile)); + }); + + tearDown(() async { + await database.close(); + }); + + test('Database successfully writes to the physical file system', () async { + final users = [ + 'alice', + 'bob', + 'charlie', + 'david', + 'frank', + ]; + + for (var i = 0; i < users.length; i++) { + await database.contactsDao.insertContact( + ContactsCompanion(userId: Value(i), username: Value(users[i])), + ); + } + + expect( + dbFile.existsSync(), + isTrue, + reason: 'The SQLite file was not created on disk.', + ); + + expect( + dbFile.lengthSync(), + greaterThan(0), + reason: 'The SQLite file is completely empty.', + ); + + if (kDebugMode) { + print('Test passed! Database written to: ${dbFile.absolute.path}'); + } + }); +} From 51f51f768bc330ef2a4e15f68d44d71ceda7dcd5 Mon Sep 17 00:00:00 2001 From: otsmr Date: Mon, 13 Apr 2026 16:38:59 +0200 Subject: [PATCH 03/86] working tests --- rust/Cargo.lock | 127 ++--- rust/Cargo.toml | 4 +- rust/src/sss/sss.rs | 0 rust/src/user_discovery/mod.rs | 455 +++++++++++++++--- .../user_discovery/stores/in_memory_store.rs | 101 ++-- rust/src/user_discovery/traits.rs | 74 ++- rust/src/user_discovery/types.proto | 9 +- 7 files changed, 576 insertions(+), 194 deletions(-) delete mode 100644 rust/src/sss/sss.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 12b01045..07f9c799 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -437,6 +437,19 @@ dependencies = [ "regex", ] +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -786,6 +799,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "hex" version = "0.4.3" @@ -819,6 +838,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -964,6 +989,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi 0.5.2", + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "itertools" version = "0.14.0" @@ -1107,15 +1143,6 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "num-bigint-dig" version = "0.8.6" @@ -1168,7 +1195,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.3", "libc", ] @@ -1335,6 +1362,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -1541,6 +1578,7 @@ dependencies = [ "blahaj", "flutter_rust_bridge", "postcard", + "pretty_env_logger", "prost", "prost-build", "rand 0.10.1", @@ -1549,7 +1587,6 @@ dependencies = [ "thiserror", "tokio", "tracing", - "tracing-subscriber", ] [[package]] @@ -1675,15 +1712,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "shlex" version = "1.3.0" @@ -2011,6 +2039,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "2.0.18" @@ -2031,15 +2068,6 @@ dependencies = [ "syn", ] -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - [[package]] name = "threadpool" version = "1.8.1" @@ -2143,32 +2171,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", ] [[package]] @@ -2228,12 +2230,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - [[package]] name = "vcpkg" version = "0.2.15" @@ -2396,6 +2392,15 @@ dependencies = [ "wasite", ] +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "windows-core" version = "0.62.2" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 1ee66891..eaf86a76 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -23,10 +23,12 @@ tracing = "0.1.44" serde = "1.0.228" prost = "0.14.1" rand = "0.10.1" -tracing-subscriber = "0.3.23" blahaj = "0.6.0" postcard = { version = "1.1.3", features = ["alloc"] } +[dev-dependencies] +pretty_env_logger = "0.5.0" + [build-dependencies] prost-build = "0.14.1" diff --git a/rust/src/sss/sss.rs b/rust/src/sss/sss.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/rust/src/user_discovery/mod.rs b/rust/src/user_discovery/mod.rs index 6701a673..55ee1b49 100644 --- a/rust/src/user_discovery/mod.rs +++ b/rust/src/user_discovery/mod.rs @@ -2,17 +2,23 @@ mod error; pub mod stores; mod traits; +use std::collections::HashMap; + use blahaj::{Share, Sharks}; use postcard::{from_bytes, to_allocvec}; use prost::Message; use serde::{Deserialize, Serialize}; use crate::user_discovery::error::{Result, UserDiscoveryError}; -use crate::user_discovery::traits::UserDiscoveryUtils; +use crate::user_discovery::traits::{AnnouncedUser, OtherPromotion, UserDiscoveryUtils}; use crate::user_discovery::user_discovery_message::{UserDiscoveryAnnouncement, UserDiscoveryPromotion}; use crate::user_discovery::user_discovery_message::user_discovery_promotion::AnnouncementShareDecrypted; use crate::user_discovery::user_discovery_message::user_discovery_promotion::announcement_share_decrypted::SignedData; pub use traits::UserDiscoveryStore; +#[cfg(test)] +static TRANSMITTED_NETWORK_BYTES: std::sync::OnceLock> = + std::sync::OnceLock::new(); + pub type UserID = i64; include!(concat!(env!("OUT_DIR"), "/_.rs")); @@ -31,6 +37,8 @@ struct UserDiscoveryConfig { public_id: u64, /// Verification shares verification_shares: Vec>, + // The users' id: + user_id: UserID, } impl Default for UserDiscoveryConfig { @@ -42,6 +50,7 @@ impl Default for UserDiscoveryConfig { promotion_version: 0, verification_shares: vec![], public_id: 0, + user_id: 0, } } } @@ -74,6 +83,7 @@ impl UserDiscovery UserDiscoveryConfig { threshold, + user_id, ..Default::default() }, }; @@ -86,7 +96,7 @@ impl UserDiscovery UserDiscovery Result)>>> { + self.store.get_all_announced_users() + } + /// Returns all new user discovery messages for the provided contact pub fn get_new_messages( &self, @@ -206,9 +223,17 @@ impl UserDiscovery = std::sync::OnceLock::new(); Ok(messages) } @@ -223,8 +248,9 @@ impl UserDiscovery {stored_version:?}"); Ok(received_version.announcement > stored_version.announcement - || received_version.promotion < received_version.promotion) + || received_version.promotion > stored_version.promotion) } pub(crate) fn get_contact_version(&self, contact_id: UserID) -> Result>> { @@ -246,10 +272,11 @@ impl UserDiscovery UserDiscovery UserDiscovery { - return Err(UserDiscoveryError::ShamirsSecret(err.to_string())); - } + Err(err) => Err(UserDiscoveryError::ShamirsSecret(err.to_string())), } } fn handle_user_discovery_promotion( &self, - contact_id: UserID, - uda: UserDiscoveryPromotion, - ) { + from_contact_id: UserID, + udp: UserDiscoveryPromotion, + ) -> Result<()> { + tracing::debug!("Received a new UDP with public_id = {}.", &udp.public_id); - // contact_id - // uda.promotion_id - // uda.public_id - // uda.threshold - // uda.announcement_share - // uda.verification_state + self.store.store_other_promotion(OtherPromotion { + from_contact_id, + promotion_id: udp.promotion_id, + threshold: udp.threshold as u8, + public_id: udp.public_id, + announcement_share: udp.announcement_share, + public_key_verified_timestamp: udp.public_key_verified_timestamp, + })?; - // store this into the received_promotion_table - // check if the threshold is reached - // in case thr threshold is reached -> CALL STORE -> NEW USER - // otherwise do nothing + if let Some(contact) = self.store.get_announced_user_by_public_id(udp.public_id)? { + tracing::debug!( + "NEW PROMOTION 2: {} knows {}", + from_contact_id, + contact.user_id + ); + // The user is already known, just propagate the relation ship + self.store.push_new_user_relation( + from_contact_id, + contact, + udp.public_key_verified_timestamp, + )?; + return Ok(()); + } + let promotions = self.store.get_other_promotions_by_public_id(udp.public_id); + + if promotions.len() < udp.threshold as usize { + tracing::debug!( + "Not enough shares ({} < {}) to decrypt announcement. Waiting for next share.", + promotions.len(), + udp.threshold + ); + return Ok(()); + } + + tracing::debug!("Enough shares decrypting announcement."); + + let shares: Vec<_> = promotions + .iter() + .map(|x| x.announcement_share.to_owned()) + .filter_map(|x| Share::try_from(x.as_slice()).ok()) + .collect(); + + match Sharks(udp.threshold as u8).recover(&shares) { + Ok(secret) => { + tracing::debug!("Could decrypt announcement."); + let asd = AnnouncementShareDecrypted::decode(secret.as_slice())?; + if let Some(signed_data) = asd.signed_data { + if udp.public_id != signed_data.public_id { + tracing::error!( + "Mismatch of the announced public id and the signed public id " + ); + return Ok(()); + } + + if !self.utils.verify_signature( + &signed_data.encode_to_vec(), + &signed_data.public_key, + &asd.signature, + )? { + return Err(UserDiscoveryError::MaliciousAnnouncementData(format!( + "signature is invalid", + ))); + } + + tracing::debug!("Announcement valid."); + + let announced_user = AnnouncedUser { + user_id: signed_data.user_id, + public_key: signed_data.public_key, + public_id: udp.public_id, + }; + + let user_id = self.get_config()?.user_id; + for promotion in promotions { + // Do not store the announcement of the users itself. + // Or in case the promotion promotes myself + if promotion.from_contact_id == announced_user.user_id + || announced_user.user_id == user_id + { + continue; + } + tracing::debug!( + "NEW PROMOTION: {} knows {}", + promotion.from_contact_id, + announced_user.user_id + ); + self.store.push_new_user_relation( + promotion.from_contact_id, + announced_user.clone(), + promotion.public_key_verified_timestamp, + )?; + } + } + Ok(()) + } + Err(err) => Err(UserDiscoveryError::ShamirsSecret(err.to_string())), + } } - } #[cfg(test)] mod tests { + use std::collections::{HashMap, HashSet}; + use std::vec; + use crate::user_discovery::stores::InMemoryStore; use crate::user_discovery::traits::tests::TestingUtils; - use crate::user_discovery::{UserDiscovery, UserDiscoveryVersion, UserID}; + use crate::user_discovery::{ + UserDiscovery, UserDiscoveryVersion, UserID, TRANSMITTED_NETWORK_BYTES, + }; use prost::Message; fn get_version_bytes(announcement: u32, promotion: u32) -> Vec { @@ -380,16 +526,11 @@ mod tests { .encode_to_vec() } - fn zero() -> Vec { - get_version_bytes(0, 0) - } - - fn get_ud(user_id: UserID, friends: &[UserID]) -> UserDiscovery { + fn get_ud(user_id: usize) -> UserDiscovery { let store = InMemoryStore::default(); - store.set_friends(friends.iter().copied().collect()); let ud = UserDiscovery::new(store.to_owned(), TestingUtils::default()).unwrap(); - ud.initialize_or_update(3, user_id, vec![user_id as u8; 32]) + ud.initialize_or_update(2, user_id as UserID, vec![user_id as u8; 32]) .unwrap(); let version = ud.get_current_version().unwrap(); @@ -398,74 +539,236 @@ mod tests { ud } - fn init() { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::DEBUG) - .init(); + fn assert_new_messages( + from: (usize, &UserDiscovery), + to: (usize, &UserDiscovery), + has_new_messages: bool, + ) { + // From sends a message with his current version to To + let to_received_version = &from.1.get_current_version().unwrap(); + assert_eq!( + to.1.should_request_new_messages(from.0 as UserID, to_received_version) + .unwrap(), + has_new_messages + ); } fn request_and_handle_messages( - from: (UserID, &UserDiscovery), - to: (UserID, &UserDiscovery), + from: (usize, &UserDiscovery), + to: (usize, &UserDiscovery), messages_count: usize, ) { // From sends a message with his current version to To let to_received_version = &from.1.get_current_version().unwrap(); assert_eq!( - to.1.should_request_new_messages(from.0, to_received_version) + to.1.should_request_new_messages(from.0 as UserID, to_received_version) .unwrap(), true ); // As To has a older version stored he sends a request to From: Give me all messages since version. let from_request_version_from_to = - to.1.get_contact_version(from.0).unwrap().unwrap_or(zero()); + to.1.get_contact_version(from.0 as UserID) + .unwrap() + .unwrap_or(get_version_bytes(0, 0)); let new_messages = from .1 - .get_new_messages(to.0, &from_request_version_from_to) + .get_new_messages(to.0 as UserID, &from_request_version_from_to) .unwrap(); - assert_eq!(new_messages.len(), messages_count); + assert!(new_messages.len() <= messages_count); - to.1.handle_user_discovery_messages(from.0, new_messages) + to.1.handle_user_discovery_messages(from.0 as UserID, new_messages) .unwrap(); assert_eq!( - to.1.should_request_new_messages(from.0, &from.1.get_current_version().unwrap()) - .unwrap(), + to.1.should_request_new_messages( + from.0 as UserID, + &from.1.get_current_version().unwrap() + ) + .unwrap(), false ); } + const ALICE: usize = 0; + const BOB: usize = 1; + const CHARLIE: usize = 2; + const DAVID: usize = 3; + const FRANK: usize = 4; + const TEST_USER_COUNT: usize = 5; + struct TestUsers { + names: [&'static str; TEST_USER_COUNT], + friends: [Vec; TEST_USER_COUNT], + uds: Vec>, + } + + impl TestUsers { + fn get() -> Self { + let names = ["ALICE", "BOB", "CHARLIE", "DAVID", "FRANK"]; + let mut uds = vec![]; + for index in 0..names.len() { + uds.push(get_ud(index)); + } + let friends = [ + vec![BOB, CHARLIE], + vec![ALICE, CHARLIE, DAVID], + vec![ALICE, BOB, DAVID, FRANK], + vec![BOB, CHARLIE], + vec![CHARLIE], + ]; + Self { + names, + uds, + friends, + } + } + } + #[tokio::test] async fn test_initialize_user_discovery() { - init(); + pretty_env_logger::init(); + let counter = TRANSMITTED_NETWORK_BYTES.get_or_init(|| std::sync::Mutex::new(0)); - const ALICE: UserID = 0; - const BOB: UserID = 1; - const CHARLIE: UserID = 2; - const DAVID: UserID = 3; - const FRANK: UserID = 4; + let users = TestUsers::get(); - let alice_ud = get_ud(ALICE, &[BOB, CHARLIE]); - let bob_ud = get_ud(BOB, &[ALICE, CHARLIE, DAVID]); - let charlie_ud = get_ud(CHARLIE, &[ALICE, BOB, DAVID, FRANK]); - let david_ud = get_ud(DAVID, &[BOB, CHARLIE]); - let frank_ud = get_ud(FRANK, &[CHARLIE]); + fn to_all_friends(from: usize, message_count: usize, users: &TestUsers) { + for friend in &users.friends[from] { + tracing::debug!("From {} to {}", users.names[from], users.names[*friend]); - { - // Alice send UDA to Bob and Charlie - request_and_handle_messages((ALICE, &alice_ud), (BOB, &bob_ud), 1); - request_and_handle_messages((ALICE, &alice_ud), (CHARLIE, &charlie_ud), 1); + if message_count == 0 { + assert_new_messages( + (from, &users.uds[from]), + (*friend, &users.uds[*friend]), + false, + ); + } else { + request_and_handle_messages( + (from, &users.uds[from]), + (*friend, &users.uds[*friend]), + message_count, + ); + } + } } - { - // This now contains Bob's own announcement in addition this now also contains the promotion from Alice - request_and_handle_messages((BOB, &bob_ud), (DAVID, &david_ud), 2); - request_and_handle_messages((BOB, &bob_ud), (CHARLIE, &charlie_ud), 2); + let message_flows = [ + // ALICE: own announcement sending to BOB and CHARLIE + (ALICE, 1), + // BOB: own announcement + promotion for ALICE + (BOB, 2), + // BOBs version should not have any new messages for his friends + (BOB, 0), + // ALICE: promotion for BOB + (ALICE, 1), + // CHARLIE: own announcement + promotion for ALICE, BOB + (CHARLIE, 3), + // DAVID: own announcement + promotion for BOB, CHARLIE + (DAVID, 3), + // BOB: promotion for CHARLIE, DAVID + (BOB, 2), + // CHARLIE: promotion for DAVID + (CHARLIE, 1), + // FRANK: own announcement + promotion for CHARLIE + (FRANK, 2), + // CHARLIE: promotion for FRANK + (CHARLIE, 1), + // ALICE: promotion for CHARLIE + (ALICE, 1), + ]; + + for (i, (from, count)) in message_flows.into_iter().enumerate() { + tracing::debug!("MESSAGE FLOW: {i}"); + to_all_friends(from, count, &users); } - todo!(); + tracing::debug!("Now all users should have the newest version."); + + for from in 0..TEST_USER_COUNT { + for to in &users.friends[from] { + tracing::debug!( + "Does {} has open messages for {}?", + &users.names[from], + &users.names[*to] + ); + assert_new_messages((from, &users.uds[from]), (*to, &users.uds[*to]), false); + } + } + + tracing::debug!("Test if all exchanges where successful."); + + let announced_users_expected = [ + // ALICE should now know that BOB and CHARLIE, BOB and DAVID and CHARLIE and DAVID are friends. + // Alice should also have one protected share from Frank. + ( + ALICE, + vec![ + (BOB, vec![CHARLIE]), // ALICE knows Bob and that CHARLIE is connected with BOB + (CHARLIE, vec![BOB]), // ALICE knows CHARLIE and that BOB is connected with CHARLIE + (DAVID, vec![BOB, CHARLIE]), // ALICE knows DAVID and that BOB and CHARLIE are connected with DAVID + ], + ), + ( + BOB, + vec![ + (ALICE, vec![CHARLIE]), + (CHARLIE, vec![ALICE, DAVID]), + (DAVID, vec![CHARLIE]), + ], + ), + ( + CHARLIE, + vec![ + (ALICE, vec![BOB]), + (BOB, vec![ALICE, DAVID]), + (DAVID, vec![BOB]), + (FRANK, vec![]), + ], + ), + ( + DAVID, + vec![ + (ALICE, vec![BOB, CHARLIE]), + (BOB, vec![CHARLIE]), + (CHARLIE, vec![BOB]), + ], + ), + (FRANK, vec![(CHARLIE, vec![])]), + ]; + + for (user, announcements) in announced_users_expected { + let announced_users2 = users.uds[user].get_all_announced_users().unwrap(); + let mut announced_users = HashMap::new(); + for a in announced_users2 { + announced_users.insert(a.0.user_id, a.1.iter().map(|x| x.0).collect::>()); + } + tracing::debug!("{} knows now: {}", users.names[user], announced_users.len()); + assert_eq!(announced_users.len(), announcements.len()); + for (contact_id, announced_users_expected) in announcements { + let announced_users = announced_users.get(&(contact_id as i64)).unwrap(); + tracing::debug!( + "{} knows now that {} has the following friends: {}", + users.names[user], + users.names[contact_id], + announced_users + .iter() + .map(|x| users.names[*x as usize]) + .collect::>() + .join(", ") + ); + let announced_users: HashSet = announced_users.iter().cloned().collect(); + let announced_users_expected: HashSet = announced_users_expected + .iter() + .cloned() + .map(|x| x as i64) + .collect(); + assert_eq!(announced_users, announced_users_expected); + } + } + + let count = TRANSMITTED_NETWORK_BYTES.get().unwrap().lock().unwrap(); + + tracing::info!("Transmitted a total of {} bytes.", *count); } } diff --git a/rust/src/user_discovery/stores/in_memory_store.rs b/rust/src/user_discovery/stores/in_memory_store.rs index 2b7ec34a..4cf8d312 100644 --- a/rust/src/user_discovery/stores/in_memory_store.rs +++ b/rust/src/user_discovery/stores/in_memory_store.rs @@ -1,7 +1,7 @@ -use crate::user_discovery::error::UserDiscoveryError; -use crate::user_discovery::traits::UserDiscoveryStore; +use crate::user_discovery::error::{Result, UserDiscoveryError}; +use crate::user_discovery::traits::{AnnouncedUser, OtherPromotion, UserDiscoveryStore}; use crate::user_discovery::UserID; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::sync::{Arc, Mutex}; #[derive(Default)] @@ -10,8 +10,9 @@ pub(crate) struct Storage { unused_shares: Vec>, used_shares: HashMap>, contact_versions: HashMap>, - friends: HashSet, - promotions: Vec>, + other_promotions: Vec, + announced_users: HashMap)>>, + own_promotions: Vec<(UserID, Vec)>, } #[derive(Default, Clone)] @@ -23,33 +24,27 @@ impl InMemoryStore { fn storage(&self) -> std::sync::MutexGuard<'_, Storage> { self.storage.lock().unwrap() } - pub fn set_friends(&self, friends: HashSet) { - self.storage().friends = friends; - } } impl UserDiscoveryStore for InMemoryStore { - fn get_config(&self) -> crate::user_discovery::error::Result> { + fn get_config(&self) -> Result> { if let Some(storage) = self.storage().config.clone() { return Ok(storage); } Err(UserDiscoveryError::NotInitialized) } - fn update_config(&self, update: Vec) -> crate::user_discovery::error::Result<()> { + fn update_config(&self, update: Vec) -> Result<()> { self.storage().config = Some(update); Ok(()) } - fn set_shares(&self, shares: Vec>) -> crate::user_discovery::error::Result<()> { + fn set_shares(&self, shares: Vec>) -> Result<()> { self.storage().unused_shares = shares; Ok(()) } - fn get_share_for_contact( - &self, - contact_id: UserID, - ) -> crate::user_discovery::error::Result> { + fn get_share_for_contact(&self, contact_id: UserID) -> Result> { let mut storage = self.storage(); if let Some(share) = storage.used_shares.get(&contact_id) { return Ok(share.to_vec()); @@ -61,42 +56,82 @@ impl UserDiscoveryStore for InMemoryStore { Err(UserDiscoveryError::NoSharesLeft) } - fn get_contact_version( - &self, - contact_id: UserID, - ) -> crate::user_discovery::error::Result>> { + fn get_contact_version(&self, contact_id: UserID) -> Result>> { Ok(self.storage().contact_versions.get(&contact_id).cloned()) } - fn set_contact_version( - &self, - contact_id: UserID, - update: Vec, - ) -> crate::user_discovery::error::Result<()> { + fn set_contact_version(&self, contact_id: UserID, update: Vec) -> Result<()> { self.storage().contact_versions.insert(contact_id, update); Ok(()) } - fn push_promotion( + fn push_own_promotion( &self, + contact_id: UserID, version: u32, promotion: Vec, - ) -> crate::user_discovery::error::Result<()> { + ) -> Result<()> { let mut storage = self.storage(); // println!("{} != {}", version, storage.promotions.len()); - if version as usize != storage.promotions.len() + 1 { + if version as usize != storage.own_promotions.len() + 1 { return Err(UserDiscoveryError::PushedInvalidVersion); } - storage.promotions.push(promotion); + storage.own_promotions.push((contact_id, promotion)); Ok(()) } - fn get_promotions_after_version( - &self, - version: u32, - ) -> crate::user_discovery::error::Result>> { + fn get_own_promotions_after_version(&self, version: u32) -> Result>> { let storage = self.storage(); - let elements = storage.promotions[(version as usize)..].to_vec(); + let elements = storage.own_promotions[(version as usize)..] + .into_iter() + .map(|(_, promotion)| promotion.to_owned()) + .collect(); Ok(elements) } + + fn store_other_promotion(&self, promotion: OtherPromotion) -> Result<()> { + self.storage().other_promotions.push(promotion); + Ok(()) + } + + fn get_other_promotions_by_public_id(&self, public_id: u64) -> Vec { + self.storage() + .other_promotions + .iter() + .filter(|other| other.public_id == public_id) + .map(OtherPromotion::to_owned) + .collect() + } + + fn get_announced_user_by_public_id(&self, public_id: u64) -> Result> { + Ok(self + .storage() + .announced_users + .iter() + .find(|(u, _)| u.public_id == public_id) + .map(|u| u.0.to_owned())) + } + + fn get_all_announced_users( + &self, + ) -> Result)>>> { + Ok(self.storage().announced_users.clone()) + } + + fn push_new_user_relation( + &self, + from_contact_id: UserID, + announced_user: AnnouncedUser, + public_key_verified_timestamp: Option, + ) -> Result<()> { + let mut storage = self.storage(); + let entry = storage + .announced_users + .entry(announced_user.clone()) + .or_insert(vec![]); + if announced_user.user_id != from_contact_id { + entry.push((from_contact_id, public_key_verified_timestamp)); + } + Ok(()) + } } diff --git a/rust/src/user_discovery/traits.rs b/rust/src/user_discovery/traits.rs index 67dca8cb..8646d1f1 100644 --- a/rust/src/user_discovery/traits.rs +++ b/rust/src/user_discovery/traits.rs @@ -1,6 +1,25 @@ +use std::collections::HashMap; + use crate::user_discovery::error::Result; use crate::user_discovery::UserID; +#[derive(Clone)] +pub struct OtherPromotion { + pub promotion_id: u32, + pub public_id: u64, + pub from_contact_id: UserID, + pub threshold: u8, + pub announcement_share: Vec, + pub public_key_verified_timestamp: Option, +} + +#[derive(Clone, Hash, PartialEq, Eq)] +pub struct AnnouncedUser { + pub user_id: UserID, + pub public_key: Vec, + pub public_id: u64, +} + pub trait UserDiscoveryStore { fn get_config(&self) -> Result>; fn update_config(&self, update: Vec) -> Result<()>; @@ -8,22 +27,38 @@ pub trait UserDiscoveryStore { fn get_share_for_contact(&self, contact_id: UserID) -> Result>; - fn push_promotion(&self, version: u32, promotion: Vec) -> Result<()>; - fn get_promotions_after_version(&self, version: u32) -> Result>>; + fn push_own_promotion( + &self, + contact_id: UserID, + version: u32, + promotion: Vec, + ) -> Result<()>; + + fn get_own_promotions_after_version(&self, version: u32) -> Result>>; + + fn store_other_promotion(&self, promotion: OtherPromotion) -> Result<()>; + fn get_other_promotions_by_public_id(&self, public_id: u64) -> Vec; + + fn get_announced_user_by_public_id(&self, public_id: u64) -> Result>; + + fn push_new_user_relation( + &self, + from_contact_id: UserID, + announced_user: AnnouncedUser, + public_key_verified_timestamp: Option, + ) -> Result<()>; + + fn get_all_announced_users(&self) + -> Result)>>>; fn get_contact_version(&self, contact_id: UserID) -> Result>>; fn set_contact_version(&self, contact_id: UserID, update: Vec) -> Result<()>; } pub trait UserDiscoveryUtils { - fn sign_data(&self, input_data: Vec) -> Result>; - fn verify_pubkey_and_signature_from( - &self, - from_contact_id: UserID, - data: Vec, - pubkey: Vec, - signature: Vec, - ) -> Result; + fn sign_data(&self, input_data: &[u8]) -> Result>; + fn verify_signature(&self, input_data: &[u8], pubkey: &[u8], signature: &[u8]) -> Result; + fn verify_stored_pubkey(&self, from_contact_id: UserID, pubkey: &[u8]) -> Result; } #[cfg(test)] @@ -33,16 +68,23 @@ pub(crate) mod tests { #[derive(Default)] pub(crate) struct TestingUtils {} impl UserDiscoveryUtils for TestingUtils { - fn sign_data(&self, _input_data: Vec) -> crate::user_discovery::error::Result> { + fn sign_data(&self, _input_data: &[u8]) -> crate::user_discovery::error::Result> { Ok(vec![0; 64]) } - fn verify_pubkey_and_signature_from( + fn verify_signature( &self, - from_contact_id: crate::user_discovery::UserID, - data: Vec, - pubkey: Vec, - signature: Vec, + _data: &[u8], + _pubkey: &[u8], + _signature: &[u8], + ) -> crate::user_discovery::error::Result { + Ok(true) + } + + fn verify_stored_pubkey( + &self, + _from_contact_id: crate::user_discovery::UserID, + _pubkey: &[u8], ) -> crate::user_discovery::error::Result { Ok(true) } diff --git a/rust/src/user_discovery/types.proto b/rust/src/user_discovery/types.proto index f719ecec..9237586a 100644 --- a/rust/src/user_discovery/types.proto +++ b/rust/src/user_discovery/types.proto @@ -17,7 +17,7 @@ message UserDiscoveryMessage { uint64 public_id = 1; uint32 threshold = 2; bytes announcement_share = 4; - repeated bytes verification_shares = 5; + repeated bytes verification_shares = 6; } message UserDiscoveryPromotion { @@ -26,7 +26,7 @@ message UserDiscoveryMessage { uint32 threshold = 3; bytes announcement_share = 5; - optional VerificationState verification_state = 6; + optional int64 public_key_verified_timestamp = 6; message AnnouncementShareDecrypted { message SignedData { @@ -38,11 +38,6 @@ message UserDiscoveryMessage { bytes signature = 2; } - message VerificationState { - int64 timestamp = 1; - bytes signature = 2; - } - } message UserDiscoveryRecall { From fc73e313eabdd6e48cfa0e92b7add477f418dfc7 Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 14 Apr 2026 01:47:31 +0200 Subject: [PATCH 04/86] documentation and new modules --- rust/src/key_verification/mod.rs | 29 ++ rust/src/key_verification/traits.rs | 1 + rust/src/lib.rs | 2 + rust/src/passwordless_recovery/mod.rs | 1 + rust/src/passwordless_recovery/traits.rs | 0 rust/src/twonly/log/mod.rs | 2 +- rust/src/user_discovery/README.md | 78 +++++- rust/src/user_discovery/mod.rs | 337 +++++++++++++---------- 8 files changed, 304 insertions(+), 146 deletions(-) create mode 100644 rust/src/key_verification/mod.rs create mode 100644 rust/src/key_verification/traits.rs create mode 100644 rust/src/passwordless_recovery/mod.rs create mode 100644 rust/src/passwordless_recovery/traits.rs diff --git a/rust/src/key_verification/mod.rs b/rust/src/key_verification/mod.rs new file mode 100644 index 00000000..c347d674 --- /dev/null +++ b/rust/src/key_verification/mod.rs @@ -0,0 +1,29 @@ +use crate::key_verification::traits::KeyVerificationStore; + +pub mod traits; + +pub struct KeyVerificationConfig { + /// The link prefix for the qr code which should be registered as a deeplink on Android and a universal link on iOS + deeplink_prefix: String, +} + +struct KeyVerification { + store: Store, + config: KeyVerificationConfig, +} + +impl KeyVerification { + pub fn new(store: Store, config: KeyVerificationConfig) -> KeyVerification { + Self { store, config } + } + + /// Generates the a string which should be displayed in the UI so others can scan it. + pub fn generate_qr_code_data() -> String { + todo!(); + } + + /// Generates the a string which should be displayed in the UI so others can scan it. + pub fn handle_qr_code_data() -> String { + todo!(); + } +} diff --git a/rust/src/key_verification/traits.rs b/rust/src/key_verification/traits.rs new file mode 100644 index 00000000..1fc4c498 --- /dev/null +++ b/rust/src/key_verification/traits.rs @@ -0,0 +1 @@ +pub trait KeyVerificationStore {} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 71cb3dfe..0b278cda 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,3 +1,5 @@ mod frb_generated; +mod key_verification; +mod passwordless_recovery; mod twonly; mod user_discovery; diff --git a/rust/src/passwordless_recovery/mod.rs b/rust/src/passwordless_recovery/mod.rs new file mode 100644 index 00000000..3ecd1210 --- /dev/null +++ b/rust/src/passwordless_recovery/mod.rs @@ -0,0 +1 @@ +mod traits; diff --git a/rust/src/passwordless_recovery/traits.rs b/rust/src/passwordless_recovery/traits.rs new file mode 100644 index 00000000..e69de29b diff --git a/rust/src/twonly/log/mod.rs b/rust/src/twonly/log/mod.rs index dc1bdf26..528f989b 100644 --- a/rust/src/twonly/log/mod.rs +++ b/rust/src/twonly/log/mod.rs @@ -28,7 +28,7 @@ pub(crate) fn init_tracing(logs_dir: &std::path::Path) { fn build_writers(logs_dir: &std::path::Path) -> (NonBlocking, NonBlocking) { let file_appender = tracing_appender::rolling::RollingFileAppender::builder() .rotation(tracing_appender::rolling::Rotation::DAILY) - .filename_prefix("whitenoise") + .filename_prefix("twonly") .filename_suffix("log") .build(logs_dir) .expect("Failed to create file appender"); diff --git a/rust/src/user_discovery/README.md b/rust/src/user_discovery/README.md index 1a5368ba..af442b96 100644 --- a/rust/src/user_discovery/README.md +++ b/rust/src/user_discovery/README.md @@ -1,10 +1,74 @@ +# User Discovery + +User Discovery is a feature that allows users to discover other users in a decentralized system without any central authority. It uses Shamir's Secret Sharing to securely share and discover user information. + +## Getting started + +The User Discovery module is composed of the following components: + +- **UserDiscovery** - The main struct which initializes the user discovery and provides access to the user discovery functionality. + +- **UserDiscoveryStore** - A trait which has to be implemented. It is used to store and retrieve the user discovery data. +- **UserDiscoveryUtils** - A trait which has to be implemented. It is used to perform signature verification and signing. + +```rust +use crate::user_discovery::{UserDiscovery, UserID}; +use crate::user_discovery::stores::InMemoryStore; // Replace with your persistent store +use crate::user_discovery::traits::tests::TestingUtils; // Replace with your utils + +const THRESHOLD: u8 = 2; + +// Initialize user discovery for Alice +const ALICE_ID: UserID = 1; +let alice_ud = UserDiscovery::new(InMemoryStore::default(), TestingUtils::default()).unwrap(); + +// Set threshold, user ID, and the user's public key +alice_ud.initialize_or_update(THRESHOLD, ALICE_ID, vec![0; 32]).unwrap(); + +// Initialize user discovery for Bob +const BOB_ID: UserID = 2; +let bob_ud = UserDiscovery::new(InMemoryStore::default(), TestingUtils::default()).unwrap(); +bob_ud.initialize_or_update(THRESHOLD, BOB_ID, vec![0; 32]).unwrap(); + - // **Store** promotions: - // version_id, contact_id, Option - // -> In case a contact_id deleted his account deleted or was removed - // - Remove the previous row (version_id must be increased...) - // - Create a new entry with User Discovery Recall - // -> Otherwise this promotion contains the Promotion - // \ No newline at end of file +// Simulate network communication: Alice sends her current version to Bob +let bob_received_version_from_alice = alice_ud.get_current_version().unwrap(); + +// SEND FROM ALICE TO BOB: bob_received_version_from_alice + +// Bob checks if he should request new messages +if bob_ud.should_request_new_messages(ALICE_ID, &bob_received_version_from_alice).unwrap() { + + // Bob has a old version and must now request to get the new messages + + // Bob fetches his current known version and sends it via the network to Alice + let bob_stored_alice_version = bob_ud.get_contact_version(ALICE_ID) + .unwrap() + .unwrap_or_else(|| vec![0, 0]); // Note: In practice use actual default encoded version + + // SEND FROM BOB TO ALICE: bob_stored_alice_version + + // Alice loads the new messages for Bob. These only conclude changes since the provided version. + let new_messages = alice_ud.get_new_messages(BOB_ID, &bob_stored_alice_version).unwrap(); + + // SEND FROM ALICE TO BOB: new_messages + + // Bob processes the received user discovery messages + bob_ud.handle_user_discovery_messages(ALICE_ID, new_messages).unwrap(); + + // BOB is now able to promote ALICE to his other contacts +} + +// + +// 4. Retrieve all newly discovered users and relationships +// In this example now new users where discovered, to see a more comprehensive example +// see the test in the `mod.rs` fil. +let discovered_users = bob_ud.get_all_announced_users().unwrap(); +for (user, connections) in discovered_users { + println!("Discovered User: {} (Public ID: {})", user.user_id, user.public_id); +} +``` + diff --git a/rust/src/user_discovery/mod.rs b/rust/src/user_discovery/mod.rs index 55ee1b49..89372fa4 100644 --- a/rust/src/user_discovery/mod.rs +++ b/rust/src/user_discovery/mod.rs @@ -1,9 +1,8 @@ mod error; pub mod stores; -mod traits; +pub mod traits; use std::collections::HashMap; - use blahaj::{Share, Sharks}; use postcard::{from_bytes, to_allocvec}; use prost::Message; @@ -19,6 +18,8 @@ pub use traits::UserDiscoveryStore; static TRANSMITTED_NETWORK_BYTES: std::sync::OnceLock> = std::sync::OnceLock::new(); +/// Type of the user id, this must be consistent with the user id defined in +/// the types.proto pub type UserID = i64; include!(concat!(env!("OUT_DIR"), "/_.rs")); @@ -41,20 +42,11 @@ struct UserDiscoveryConfig { user_id: UserID, } -impl Default for UserDiscoveryConfig { - fn default() -> Self { - Self { - threshold: 2, - total_number_of_shares: 255, - announcement_version: 0, - promotion_version: 0, - verification_shares: vec![], - public_id: 0, - user_id: 0, - } - } -} - +/// +/// The main struct to access the user discovery functionality. +/// +/// As generic values it requires a UserDiscoveryStore and a UserDiscoveryUtils. +/// pub struct UserDiscovery where Store: UserDiscoveryStore, @@ -65,10 +57,26 @@ where } impl UserDiscovery { + /// Creates a new instance of the user discovery. pub fn new(store: Store, utils: Utils) -> Result { Ok(Self { store, utils }) } + /// Initializes or updates the user discovery. + /// + /// This function will generate new verification shares and update the config. + /// + /// # Arguments + /// + /// * `threshold` - The number of required shares to get the secret + /// * `user_id` - The owner's user id + /// * `public_key` - The owner's public key + /// + /// # Returns + /// + /// * `Ok(())` - If the user discovery was initialized or updated successfully + /// * `Err(UserDiscoveryError)` - If the user discovery was not initialized or updated successfully + /// pub fn initialize_or_update( &self, threshold: u8, @@ -109,6 +117,167 @@ impl UserDiscovery)` - The current version of the user discovery + /// * `Err(UserDiscoveryError)` - If there where errors in the store. + /// + pub fn get_current_version(&self) -> Result> { + let config = self.get_config()?; + Ok(UserDiscoveryVersion { + announcement: config.announcement_version, + promotion: config.promotion_version, + } + .encode_to_vec()) + } + + /// + /// Returns all users discovery though the user discovery and there relations + /// + /// # Returns + /// + /// * `Ok(HashMap)>>)` - All connections the user has discovered + /// * `Err(UserDiscoveryError)` - If there where erros in the store. + /// + pub fn get_all_announced_users( + &self, + ) -> Result)>>> { + self.store.get_all_announced_users() + } + + /// + /// Returns all new user discovery messages for the provided contact and his current version. + /// + /// # Arguments + /// + /// * `contact_id` - The contact id of the user + /// * `received_version` - The version of the user discovery the contact has received so far + /// + /// # Returns + /// + /// * `Ok(Vec>)` - The new user discovery messages + /// * `Err(UserDiscoveryError)` - If there where errors in the store or if the received version is invalid. + /// + pub fn get_new_messages( + &self, + contact_id: UserID, + received_version: &[u8], + ) -> Result>> { + let mut messages = vec![]; + let received_version = UserDiscoveryVersion::decode(received_version)?; + + let config = self.get_config()?; + let version = Some(UserDiscoveryVersion { + announcement: config.announcement_version, + promotion: config.promotion_version, + }); + + if received_version.announcement < config.announcement_version { + tracing::info!("New announcement message available for {}", contact_id); + + let announcement_share = self.store.get_share_for_contact(contact_id)?; + + let user_discovery_announcement = Some(UserDiscoveryAnnouncement { + public_id: config.public_id, + threshold: config.threshold as u32, + announcement_share, + verification_shares: config.verification_shares, + }); + + messages.push( + UserDiscoveryMessage { + user_discovery_announcement, + version, + ..Default::default() + } + .encode_to_vec(), + ); + } + if received_version.promotion < config.promotion_version { + tracing::info!("New promotion message available for user {}", contact_id); + let promoting_messages = self + .store + .get_own_promotions_after_version(received_version.promotion)?; + messages.extend_from_slice(&promoting_messages); + } + #[cfg(test)] + { + let mut count = TRANSMITTED_NETWORK_BYTES.get().unwrap().lock().unwrap(); + for message in &messages { + *count += message.len(); + } + } + Ok(messages) + } + + /// + /// Checks if the provided user has new announcements and a request of update should be send. + /// + /// # Arguments + /// + /// * `contact_id` - The contact id of the user + /// * `version` - The current version of the user discovery from the contact + /// + /// # Returns + /// + /// * `Ok(bool)` - True if the user has new announcements + /// * `Err(UserDiscoveryError)` - If there where errors in the store or if the received version is invalid. + /// + pub fn should_request_new_messages(&self, contact_id: UserID, version: &[u8]) -> Result { + let received_version = UserDiscoveryVersion::decode(version)?; + let stored_version = match self.store.get_contact_version(contact_id)? { + Some(buf) => UserDiscoveryVersion::decode(buf.as_slice())?, + None => UserDiscoveryVersion { + announcement: 0, + promotion: 0, + }, + }; + Ok(received_version.announcement > stored_version.announcement + || received_version.promotion > stored_version.promotion) + } + + pub(crate) fn get_contact_version(&self, contact_id: UserID) -> Result>> { + self.store.get_contact_version(contact_id) + } + + /// Returns the latest version for this discovery. + /// Before calling this function the application must sure that contact_id is qualified to be announced. + pub fn handle_user_discovery_messages( + &self, + contact_id: UserID, + messages: Vec>, + ) -> Result<()> { + for message in messages { + let message = UserDiscoveryMessage::decode(message.as_slice())?; + let Some(version) = message.version else { + continue; + }; + + if let Some(uda) = message.user_discovery_announcement { + self.handle_user_discovery_announcement(contact_id, uda)?; + } else if let Some(udp) = message.user_discovery_promotion { + self.handle_user_discovery_promotion(contact_id, udp)?; + } else { + tracing::warn!("Got unknown user discovery messaging. Ignoring it."); + continue; + } + + self.store + .set_contact_version(contact_id, version.encode_to_vec())?; + } + + Ok(()) + } + fn setup_announcements( &self, config: &UserDiscoveryConfig, @@ -164,128 +333,6 @@ impl UserDiscovery Result> { - let config = self.get_config()?; - Ok(UserDiscoveryVersion { - announcement: config.announcement_version, - promotion: config.promotion_version, - } - .encode_to_vec()) - } - - /// Returns all users discovery though the user discovery and there relations - pub fn get_all_announced_users( - &self, - ) -> Result)>>> { - self.store.get_all_announced_users() - } - - /// Returns all new user discovery messages for the provided contact - pub fn get_new_messages( - &self, - contact_id: UserID, - received_version: &[u8], - ) -> Result>> { - let mut messages = vec![]; - let received_version = UserDiscoveryVersion::decode(received_version)?; - - let config = self.get_config()?; - let version = Some(UserDiscoveryVersion { - announcement: config.announcement_version, - promotion: config.promotion_version, - }); - - if received_version.announcement < config.announcement_version { - tracing::info!("New announcement message available for {}", contact_id); - - let announcement_share = self.store.get_share_for_contact(contact_id)?; - - let user_discovery_announcement = Some(UserDiscoveryAnnouncement { - public_id: config.public_id, - threshold: config.threshold as u32, - announcement_share, - verification_shares: config.verification_shares, - }); - - messages.push( - UserDiscoveryMessage { - user_discovery_announcement, - version, - ..Default::default() - } - .encode_to_vec(), - ); - - // messages.push(value); - } - if received_version.promotion < config.promotion_version { - tracing::info!("New promotion message available for user {}", contact_id); - let promoting_messages = self - .store - .get_own_promotions_after_version(received_version.promotion)?; - messages.extend_from_slice(&promoting_messages); - } - #[cfg(test)] - { - let mut count = TRANSMITTED_NETWORK_BYTES.get().unwrap().lock().unwrap(); - for message in &messages { - *count += message.len(); - } - } - // static TRANSMITTED_NETWORK_BYTES: std::sync::OnceLock = std::sync::OnceLock::new(); - Ok(messages) - } - - /// Checks if the provided user has new announcements. - /// In this case the user should be requested to send there updates. - pub fn should_request_new_messages(&self, contact_id: UserID, version: &[u8]) -> Result { - let received_version = UserDiscoveryVersion::decode(version)?; - let stored_version = match self.store.get_contact_version(contact_id)? { - Some(buf) => UserDiscoveryVersion::decode(buf.as_slice())?, - None => UserDiscoveryVersion { - announcement: 0, - promotion: 0, - }, - }; - // tracing::debug!("{received_version:?} > {stored_version:?}"); - Ok(received_version.announcement > stored_version.announcement - || received_version.promotion > stored_version.promotion) - } - - pub(crate) fn get_contact_version(&self, contact_id: UserID) -> Result>> { - self.store.get_contact_version(contact_id) - } - - /// Returns the latest version for this discovery. - /// Before calling this function the application must sure that contact_id is qualified to be announced. - pub fn handle_user_discovery_messages( - &self, - contact_id: UserID, - messages: Vec>, - ) -> Result<()> { - for message in messages { - let message = UserDiscoveryMessage::decode(message.as_slice())?; - let Some(version) = message.version else { - continue; - }; - - if let Some(uda) = message.user_discovery_announcement { - self.handle_user_discovery_announcement(contact_id, uda)?; - } else if let Some(udp) = message.user_discovery_promotion { - self.handle_user_discovery_promotion(contact_id, udp)?; - } else { - tracing::warn!("Got unknown user discovery messaging. Ignoring it."); - continue; - } - - self.store - .set_contact_version(contact_id, version.encode_to_vec())?; - } - - Ok(()) - } - fn handle_user_discovery_announcement( &self, contact_id: UserID, @@ -505,6 +552,20 @@ impl UserDiscovery Self { + Self { + threshold: 2, + total_number_of_shares: 255, + announcement_version: 0, + promotion_version: 0, + verification_shares: vec![], + public_id: 0, + user_id: 0, + } + } +} + #[cfg(test)] mod tests { From 252e7653db09fde1ec2fa8fc4a4cb32917e8d22f Mon Sep 17 00:00:00 2001 From: otsmr Date: Wed, 15 Apr 2026 23:51:48 +0200 Subject: [PATCH 05/86] move files --- flutter_rust_bridge.yaml | 4 +- lib/core/bridge.dart | 76 +++ lib/core/{twonly => }/database/contact.dart | 6 +- lib/core/frb_generated.dart | 196 +++++++- lib/core/frb_generated.io.dart | 58 ++- lib/core/frb_generated.web.dart | 58 ++- lib/core/twonly.dart | 35 -- lib/core/twonly/database.dart | 20 - lib/main.dart | 6 +- .../database/tables/user_discovery.table.dart | 48 ++ rust/.gitignore | 4 +- rust/Cargo.lock | 433 ++++++++++-------- rust/Cargo.toml | 37 +- rust/build.rs | 5 - rust/core/.gitignore | 3 + rust/core/Cargo.toml | 31 ++ rust/{src/twonly => core/src/bridge}/error.rs | 0 .../twonly => core/src/bridge}/log/mod.rs | 0 rust/{src/twonly => core/src/bridge}/mod.rs | 32 +- rust/core/src/bridge/user_discovery.rs | 72 +++ .../twonly => core/src}/database/contact.rs | 6 +- rust/{src/twonly => core/src}/database/mod.rs | 15 +- rust/{ => core}/src/frb_generated.rs | 211 +++++++-- rust/core/src/lib.rs | 3 + rust/{ => core}/tests/testing.db | Bin rust/protocols/Cargo.toml | 25 + rust/protocols/build.rs | 11 + rust/protocols/src/key_verification/error.rs | 30 ++ rust/protocols/src/key_verification/mod.rs | 194 ++++++++ .../stores/in_memory_store.rs | 22 + .../src/key_verification/stores/mod.rs | 3 + rust/protocols/src/key_verification/traits.rs | 7 + .../src/key_verification/types.proto | 12 + rust/protocols/src/lib.rs | 3 + .../src/passwordless_recovery/mod.rs | 0 .../src/passwordless_recovery/traits.rs | 0 .../src/user_discovery/README.md | 0 .../src/user_discovery/error.rs | 3 + .../{ => protocols}/src/user_discovery/mod.rs | 13 +- .../user_discovery/stores/in_memory_store.rs | 0 .../src/user_discovery/stores/mod.rs | 0 .../src/user_discovery/traits.rs | 0 .../src/user_discovery/types.proto | 1 + rust/src/key_verification/mod.rs | 29 -- rust/src/key_verification/traits.rs | 1 - rust/src/lib.rs | 5 - 46 files changed, 1322 insertions(+), 396 deletions(-) create mode 100644 lib/core/bridge.dart rename lib/core/{twonly => }/database/contact.dart (60%) delete mode 100644 lib/core/twonly.dart delete mode 100644 lib/core/twonly/database.dart create mode 100644 lib/src/database/tables/user_discovery.table.dart delete mode 100644 rust/build.rs create mode 100644 rust/core/.gitignore create mode 100644 rust/core/Cargo.toml rename rust/{src/twonly => core/src/bridge}/error.rs (100%) rename rust/{src/twonly => core/src/bridge}/log/mod.rs (100%) rename rust/{src/twonly => core/src/bridge}/mod.rs (71%) create mode 100644 rust/core/src/bridge/user_discovery.rs rename rust/{src/twonly => core/src}/database/contact.rs (89%) rename rust/{src/twonly => core/src}/database/mod.rs (88%) rename rust/{ => core}/src/frb_generated.rs (62%) create mode 100644 rust/core/src/lib.rs rename rust/{ => core}/tests/testing.db (100%) create mode 100644 rust/protocols/Cargo.toml create mode 100644 rust/protocols/build.rs create mode 100644 rust/protocols/src/key_verification/error.rs create mode 100644 rust/protocols/src/key_verification/mod.rs create mode 100644 rust/protocols/src/key_verification/stores/in_memory_store.rs create mode 100644 rust/protocols/src/key_verification/stores/mod.rs create mode 100644 rust/protocols/src/key_verification/traits.rs create mode 100644 rust/protocols/src/key_verification/types.proto create mode 100644 rust/protocols/src/lib.rs rename rust/{ => protocols}/src/passwordless_recovery/mod.rs (100%) rename rust/{ => protocols}/src/passwordless_recovery/traits.rs (100%) rename rust/{ => protocols}/src/user_discovery/README.md (100%) rename rust/{ => protocols}/src/user_discovery/error.rs (92%) rename rust/{ => protocols}/src/user_discovery/mod.rs (99%) rename rust/{ => protocols}/src/user_discovery/stores/in_memory_store.rs (100%) rename rust/{ => protocols}/src/user_discovery/stores/mod.rs (100%) rename rust/{ => protocols}/src/user_discovery/traits.rs (100%) rename rust/{ => protocols}/src/user_discovery/types.proto (97%) delete mode 100644 rust/src/key_verification/mod.rs delete mode 100644 rust/src/key_verification/traits.rs delete mode 100644 rust/src/lib.rs diff --git a/flutter_rust_bridge.yaml b/flutter_rust_bridge.yaml index bbdc703e..17b5a8f7 100644 --- a/flutter_rust_bridge.yaml +++ b/flutter_rust_bridge.yaml @@ -1,3 +1,3 @@ -rust_input: crate::twonly -rust_root: rust/ +rust_input: crate::bridge +rust_root: rust/core dart_output: lib/core \ No newline at end of file diff --git a/lib/core/bridge.dart b/lib/core/bridge.dart new file mode 100644 index 00000000..1e4d9ec6 --- /dev/null +++ b/lib/core/bridge.dart @@ -0,0 +1,76 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.12.0. + +// ignore_for_file: invalid_use_of_internal_member + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +import 'database/contact.dart'; +import 'frb_generated.dart'; + +// These functions are ignored because they are not marked as `pub`: `get_instance` +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `Twonly` + +Future initializeTwonly({required TwonlyConfig config}) => + RustLib.instance.api.crateBridgeInitializeTwonly(config: config); + +Future> getAllContacts() => + RustLib.instance.api.crateBridgeGetAllContacts(); + +Future loadPromotions() => + RustLib.instance.api.crateBridgeLoadPromotions(); + +class OtherPromotion { + const OtherPromotion({ + required this.promotionId, + required this.publicId, + required this.fromContactId, + required this.threshold, + required this.announcementShare, + this.publicKeyVerifiedTimestamp, + }); + final int promotionId; + final BigInt publicId; + final PlatformInt64 fromContactId; + final int threshold; + final Uint8List announcementShare; + final PlatformInt64? publicKeyVerifiedTimestamp; + + @override + int get hashCode => + promotionId.hashCode ^ + publicId.hashCode ^ + fromContactId.hashCode ^ + threshold.hashCode ^ + announcementShare.hashCode ^ + publicKeyVerifiedTimestamp.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is OtherPromotion && + runtimeType == other.runtimeType && + promotionId == other.promotionId && + publicId == other.publicId && + fromContactId == other.fromContactId && + threshold == other.threshold && + announcementShare == other.announcementShare && + publicKeyVerifiedTimestamp == other.publicKeyVerifiedTimestamp; +} + +class TwonlyConfig { + const TwonlyConfig({ + required this.databasePath, + }); + final String databasePath; + + @override + int get hashCode => databasePath.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is TwonlyConfig && + runtimeType == other.runtimeType && + databasePath == other.databasePath; +} diff --git a/lib/core/twonly/database/contact.dart b/lib/core/database/contact.dart similarity index 60% rename from lib/core/twonly/database/contact.dart rename to lib/core/database/contact.dart index aa7b3f4c..42799c8d 100644 --- a/lib/core/twonly/database/contact.dart +++ b/lib/core/database/contact.dart @@ -5,11 +5,7 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; -import '../../frb_generated.dart'; - -// These functions are ignored because they are not marked as `pub`: `get_all_contacts` -// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `ContactRow` -// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `fmt`, `from_row`, `from` +import '../frb_generated.dart'; class Contact { const Contact({ diff --git a/lib/core/frb_generated.dart b/lib/core/frb_generated.dart index 05958612..e6257b4e 100644 --- a/lib/core/frb_generated.dart +++ b/lib/core/frb_generated.dart @@ -8,11 +8,11 @@ import 'dart:convert'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; +import 'bridge.dart'; +import 'database/contact.dart'; import 'frb_generated.dart'; import 'frb_generated.io.dart' if (dart.library.js_interop) 'frb_generated.web.dart'; -import 'twonly.dart'; -import 'twonly/database/contact.dart'; /// Main entrypoint of the Rust API class RustLib extends BaseEntrypoint { @@ -70,20 +70,22 @@ class RustLib extends BaseEntrypoint { String get codegenVersion => '2.12.0'; @override - int get rustContentHash => 741438464; + int get rustContentHash => 776002844; static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig( stem: 'rust_lib_twonly', - ioDirectory: 'rust/target/release/', + ioDirectory: 'rust/core/target/release/', webPrefix: 'pkg/', ); } abstract class RustLibApi extends BaseApi { - Future> crateTwonlyGetAllContacts(); + Future> crateBridgeGetAllContacts(); - Future crateTwonlyInitializeTwonly({required TwonlyConfig config}); + Future crateBridgeInitializeTwonly({required TwonlyConfig config}); + + Future crateBridgeLoadPromotions(); } class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { @@ -95,7 +97,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { }); @override - Future> crateTwonlyGetAllContacts() { + Future> crateBridgeGetAllContacts() { return handler.executeNormal( NormalTask( callFfi: (port_) { @@ -111,20 +113,20 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { decodeSuccessData: sse_decode_list_contact, decodeErrorData: sse_decode_AnyhowException, ), - constMeta: kCrateTwonlyGetAllContactsConstMeta, + constMeta: kCrateBridgeGetAllContactsConstMeta, argValues: [], apiImpl: this, ), ); } - TaskConstMeta get kCrateTwonlyGetAllContactsConstMeta => const TaskConstMeta( + TaskConstMeta get kCrateBridgeGetAllContactsConstMeta => const TaskConstMeta( debugName: 'get_all_contacts', argNames: [], ); @override - Future crateTwonlyInitializeTwonly({required TwonlyConfig config}) { + Future crateBridgeInitializeTwonly({required TwonlyConfig config}) { return handler.executeNormal( NormalTask( callFfi: (port_) { @@ -141,19 +143,48 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { decodeSuccessData: sse_decode_unit, decodeErrorData: sse_decode_AnyhowException, ), - constMeta: kCrateTwonlyInitializeTwonlyConstMeta, + constMeta: kCrateBridgeInitializeTwonlyConstMeta, argValues: [config], apiImpl: this, ), ); } - TaskConstMeta get kCrateTwonlyInitializeTwonlyConstMeta => + TaskConstMeta get kCrateBridgeInitializeTwonlyConstMeta => const TaskConstMeta( debugName: 'initialize_twonly', argNames: ['config'], ); + @override + Future crateBridgeLoadPromotions() { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 3, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_other_promotion, + decodeErrorData: null, + ), + constMeta: kCrateBridgeLoadPromotionsConstMeta, + argValues: [], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateBridgeLoadPromotionsConstMeta => const TaskConstMeta( + debugName: 'load_promotions', + argNames: [], + ); + @protected AnyhowException dco_decode_AnyhowException(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -166,6 +197,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw as String; } + @protected + PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dco_decode_i_64(raw); + } + @protected TwonlyConfig dco_decode_box_autoadd_twonly_config(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -202,6 +239,28 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw as Uint8List; } + @protected + PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw == null ? null : dco_decode_box_autoadd_i_64(raw); + } + + @protected + OtherPromotion dco_decode_other_promotion(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 6) + throw Exception('unexpected arr length: expect 6 but see ${arr.length}'); + return OtherPromotion( + promotionId: dco_decode_u_32(arr[0]), + publicId: dco_decode_u_64(arr[1]), + fromContactId: dco_decode_i_64(arr[2]), + threshold: dco_decode_u_8(arr[3]), + announcementShare: dco_decode_list_prim_u_8_strict(arr[4]), + publicKeyVerifiedTimestamp: dco_decode_opt_box_autoadd_i_64(arr[5]), + ); + } + @protected TwonlyConfig dco_decode_twonly_config(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -213,6 +272,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); } + @protected + int dco_decode_u_32(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as int; + } + + @protected + BigInt dco_decode_u_64(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dcoDecodeU64(raw); + } + @protected int dco_decode_u_8(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -239,6 +310,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return utf8.decoder.convert(inner); } + @protected + PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return sse_decode_i_64(deserializer); + } + @protected TwonlyConfig sse_decode_box_autoadd_twonly_config( SseDeserializer deserializer, @@ -280,6 +357,38 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return deserializer.buffer.getUint8List(len_); } + @protected + PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + if (sse_decode_bool(deserializer)) { + return sse_decode_box_autoadd_i_64(deserializer); + } else { + return null; + } + } + + @protected + OtherPromotion sse_decode_other_promotion(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final var_promotionId = sse_decode_u_32(deserializer); + final var_publicId = sse_decode_u_64(deserializer); + final var_fromContactId = sse_decode_i_64(deserializer); + final var_threshold = sse_decode_u_8(deserializer); + final var_announcementShare = sse_decode_list_prim_u_8_strict(deserializer); + final var_publicKeyVerifiedTimestamp = sse_decode_opt_box_autoadd_i_64( + deserializer, + ); + return OtherPromotion( + promotionId: var_promotionId, + publicId: var_publicId, + fromContactId: var_fromContactId, + threshold: var_threshold, + announcementShare: var_announcementShare, + publicKeyVerifiedTimestamp: var_publicKeyVerifiedTimestamp, + ); + } + @protected TwonlyConfig sse_decode_twonly_config(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -287,6 +396,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return TwonlyConfig(databasePath: var_databasePath); } + @protected + int sse_decode_u_32(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint32(); + } + + @protected + BigInt sse_decode_u_64(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getBigUint64(); + } + @protected int sse_decode_u_8(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -325,6 +446,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer); } + @protected + void sse_encode_box_autoadd_i_64( + PlatformInt64 self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_64(self, serializer); + } + @protected void sse_encode_box_autoadd_twonly_config( TwonlyConfig self, @@ -366,12 +496,54 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { serializer.buffer.putUint8List(self); } + @protected + void sse_encode_opt_box_autoadd_i_64( + PlatformInt64? self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + sse_encode_bool(self != null, serializer); + if (self != null) { + sse_encode_box_autoadd_i_64(self, serializer); + } + } + + @protected + void sse_encode_other_promotion( + OtherPromotion self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_u_32(self.promotionId, serializer); + sse_encode_u_64(self.publicId, serializer); + sse_encode_i_64(self.fromContactId, serializer); + sse_encode_u_8(self.threshold, serializer); + sse_encode_list_prim_u_8_strict(self.announcementShare, serializer); + sse_encode_opt_box_autoadd_i_64( + self.publicKeyVerifiedTimestamp, + serializer, + ); + } + @protected void sse_encode_twonly_config(TwonlyConfig self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs sse_encode_String(self.databasePath, serializer); } + @protected + void sse_encode_u_32(int self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint32(self); + } + + @protected + void sse_encode_u_64(BigInt self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putBigUint64(self); + } + @protected void sse_encode_u_8(int self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs diff --git a/lib/core/frb_generated.io.dart b/lib/core/frb_generated.io.dart index 93c3b489..910683b8 100644 --- a/lib/core/frb_generated.io.dart +++ b/lib/core/frb_generated.io.dart @@ -9,9 +9,9 @@ import 'dart:ffi' as ffi; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart'; +import 'bridge.dart'; +import 'database/contact.dart'; import 'frb_generated.dart'; -import 'twonly.dart'; -import 'twonly/database/contact.dart'; abstract class RustLibApiImplPlatform extends BaseApiImpl { RustLibApiImplPlatform({ @@ -27,6 +27,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected String dco_decode_String(dynamic raw); + @protected + PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw); + @protected TwonlyConfig dco_decode_box_autoadd_twonly_config(dynamic raw); @@ -42,9 +45,21 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); + @protected + PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw); + + @protected + OtherPromotion dco_decode_other_promotion(dynamic raw); + @protected TwonlyConfig dco_decode_twonly_config(dynamic raw); + @protected + int dco_decode_u_32(dynamic raw); + + @protected + BigInt dco_decode_u_64(dynamic raw); + @protected int dco_decode_u_8(dynamic raw); @@ -57,6 +72,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected String sse_decode_String(SseDeserializer deserializer); + @protected + PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer); + @protected TwonlyConfig sse_decode_box_autoadd_twonly_config( SseDeserializer deserializer, @@ -74,9 +92,21 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); + @protected + PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer); + + @protected + OtherPromotion sse_decode_other_promotion(SseDeserializer deserializer); + @protected TwonlyConfig sse_decode_twonly_config(SseDeserializer deserializer); + @protected + int sse_decode_u_32(SseDeserializer deserializer); + + @protected + BigInt sse_decode_u_64(SseDeserializer deserializer); + @protected int sse_decode_u_8(SseDeserializer deserializer); @@ -98,6 +128,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_String(String self, SseSerializer serializer); + @protected + void sse_encode_box_autoadd_i_64( + PlatformInt64 self, + SseSerializer serializer, + ); + @protected void sse_encode_box_autoadd_twonly_config( TwonlyConfig self, @@ -119,9 +155,27 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); + @protected + void sse_encode_opt_box_autoadd_i_64( + PlatformInt64? self, + SseSerializer serializer, + ); + + @protected + void sse_encode_other_promotion( + OtherPromotion self, + SseSerializer serializer, + ); + @protected void sse_encode_twonly_config(TwonlyConfig self, SseSerializer serializer); + @protected + void sse_encode_u_32(int self, SseSerializer serializer); + + @protected + void sse_encode_u_64(BigInt self, SseSerializer serializer); + @protected void sse_encode_u_8(int self, SseSerializer serializer); diff --git a/lib/core/frb_generated.web.dart b/lib/core/frb_generated.web.dart index e737ff43..d45c0315 100644 --- a/lib/core/frb_generated.web.dart +++ b/lib/core/frb_generated.web.dart @@ -10,9 +10,9 @@ import 'dart:convert'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart'; +import 'bridge.dart'; +import 'database/contact.dart'; import 'frb_generated.dart'; -import 'twonly.dart'; -import 'twonly/database/contact.dart'; abstract class RustLibApiImplPlatform extends BaseApiImpl { RustLibApiImplPlatform({ @@ -28,6 +28,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected String dco_decode_String(dynamic raw); + @protected + PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw); + @protected TwonlyConfig dco_decode_box_autoadd_twonly_config(dynamic raw); @@ -43,9 +46,21 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); + @protected + PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw); + + @protected + OtherPromotion dco_decode_other_promotion(dynamic raw); + @protected TwonlyConfig dco_decode_twonly_config(dynamic raw); + @protected + int dco_decode_u_32(dynamic raw); + + @protected + BigInt dco_decode_u_64(dynamic raw); + @protected int dco_decode_u_8(dynamic raw); @@ -58,6 +73,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected String sse_decode_String(SseDeserializer deserializer); + @protected + PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer); + @protected TwonlyConfig sse_decode_box_autoadd_twonly_config( SseDeserializer deserializer, @@ -75,9 +93,21 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); + @protected + PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer); + + @protected + OtherPromotion sse_decode_other_promotion(SseDeserializer deserializer); + @protected TwonlyConfig sse_decode_twonly_config(SseDeserializer deserializer); + @protected + int sse_decode_u_32(SseDeserializer deserializer); + + @protected + BigInt sse_decode_u_64(SseDeserializer deserializer); + @protected int sse_decode_u_8(SseDeserializer deserializer); @@ -99,6 +129,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_String(String self, SseSerializer serializer); + @protected + void sse_encode_box_autoadd_i_64( + PlatformInt64 self, + SseSerializer serializer, + ); + @protected void sse_encode_box_autoadd_twonly_config( TwonlyConfig self, @@ -120,9 +156,27 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); + @protected + void sse_encode_opt_box_autoadd_i_64( + PlatformInt64? self, + SseSerializer serializer, + ); + + @protected + void sse_encode_other_promotion( + OtherPromotion self, + SseSerializer serializer, + ); + @protected void sse_encode_twonly_config(TwonlyConfig self, SseSerializer serializer); + @protected + void sse_encode_u_32(int self, SseSerializer serializer); + + @protected + void sse_encode_u_64(BigInt self, SseSerializer serializer); + @protected void sse_encode_u_8(int self, SseSerializer serializer); diff --git a/lib/core/twonly.dart b/lib/core/twonly.dart deleted file mode 100644 index 65484480..00000000 --- a/lib/core/twonly.dart +++ /dev/null @@ -1,35 +0,0 @@ -// This file is automatically generated, so please do not edit it. -// @generated by `flutter_rust_bridge`@ 2.12.0. - -// ignore_for_file: invalid_use_of_internal_member, unused_import - -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; - -import 'frb_generated.dart'; -import 'twonly/database/contact.dart'; - -// These functions are ignored because they are not marked as `pub`: `get_instance` -// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `Twonly` - -Future initializeTwonly({required TwonlyConfig config}) => - RustLib.instance.api.crateTwonlyInitializeTwonly(config: config); - -Future> getAllContacts() => - RustLib.instance.api.crateTwonlyGetAllContacts(); - -class TwonlyConfig { - const TwonlyConfig({ - required this.databasePath, - }); - final String databasePath; - - @override - int get hashCode => databasePath.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is TwonlyConfig && - runtimeType == other.runtimeType && - databasePath == other.databasePath; -} diff --git a/lib/core/twonly/database.dart b/lib/core/twonly/database.dart deleted file mode 100644 index 98b7e34b..00000000 --- a/lib/core/twonly/database.dart +++ /dev/null @@ -1,20 +0,0 @@ -// This file is automatically generated, so please do not edit it. -// @generated by `flutter_rust_bridge`@ 2.12.0. - -// ignore_for_file: unused_import - -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; - -import '../frb_generated.dart'; - -// These functions are ignored because they are not marked as `pub`: `new` - -// Rust type: RustOpaqueMoi> -abstract class Database implements RustOpaqueInterface { - SqlitePool get pool; - - set pool(SqlitePool pool); -} - -// Rust type: RustOpaqueMoi> -abstract class SqlitePool implements RustOpaqueInterface {} diff --git a/lib/main.dart b/lib/main.dart index 657ebabf..0236f632 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,8 +7,8 @@ import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:twonly/app.dart'; +import 'package:twonly/core/bridge.dart' as bridge; import 'package:twonly/core/frb_generated.dart'; -import 'package:twonly/core/twonly.dart' as core; import 'package:twonly/globals.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/providers/connection.provider.dart'; @@ -37,8 +37,8 @@ void main() async { globalApplicationSupportDirectory = (await getApplicationSupportDirectory()).path; - await core.initializeTwonly( - config: core.TwonlyConfig( + await bridge.initializeTwonly( + config: bridge.TwonlyConfig( databasePath: '$globalApplicationSupportDirectory/twonly.sqlite', ), ); diff --git a/lib/src/database/tables/user_discovery.table.dart b/lib/src/database/tables/user_discovery.table.dart new file mode 100644 index 00000000..68432a59 --- /dev/null +++ b/lib/src/database/tables/user_discovery.table.dart @@ -0,0 +1,48 @@ +import 'package:drift/drift.dart'; +import 'package:twonly/src/database/tables/contacts.table.dart'; + +// contact_versions: HashMap>, +// -> New Column in Contacts + +// config: Option>, + +// announced_users: HashMap)>>, + +// own_promotions: Vec<(UserID, Vec)>, +@DataClassName('UserDiscoveryOwnPromotion') +class UserDiscoveryOwnPromotions extends Table { + IntColumn get versionId => integer().autoIncrement()(); + IntColumn get contactId => integer().references( + Contacts, + #userId, + onDelete: KeyAction.cascade, + )(); + + BlobColumn get promotion => blob()(); +} + +// other_promotions: Vec, +@DataClassName('UserDiscoveryOtherPromotion') +class UserDiscoveryOtherPromotions extends Table { + IntColumn get versionId => integer().autoIncrement()(); + IntColumn get contactId => integer().references( + Contacts, + #userId, + onDelete: KeyAction.cascade, + )(); + + BlobColumn get promotion => blob()(); +} + +// unused_shares: Vec>, +// used_shares: HashMap>, +@DataClassName('UserDiscoveryShare') +class UserDiscoveryShares extends Table { + IntColumn get shareId => integer().autoIncrement()(); + BlobColumn get share => blob()(); + IntColumn get contactId => integer().nullable().references( + Contacts, + #userId, + onDelete: KeyAction.cascade, + )(); +} diff --git a/rust/.gitignore b/rust/.gitignore index dfb400ce..c41cc9e3 100644 --- a/rust/.gitignore +++ b/rust/.gitignore @@ -1,3 +1 @@ -/target - -tests/tmp_testing.db* \ No newline at end of file +/target \ No newline at end of file diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 07f9c799..918c3469 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -4,24 +4,24 @@ version = 4 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -101,23 +101,23 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-link", ] [[package]] @@ -134,9 +134,9 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" dependencies = [ "serde_core", ] @@ -161,6 +161,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + [[package]] name = "build-target" version = "0.4.0" @@ -169,15 +178,15 @@ checksum = "832133bbabbbaa9fbdba793456a2827627a7d2b8fb96032fa1e7666d7895832b" [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytemuck" -version = "1.14.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "byteorder" @@ -203,9 +212,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chacha20" @@ -215,7 +224,7 @@ checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", "cpufeatures 0.3.0", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -229,6 +238,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "cmov" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" + [[package]] name = "cobs" version = "0.3.0" @@ -263,6 +278,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -325,14 +346,32 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + [[package]] name = "dart-sys" version = "4.1.5" @@ -372,7 +411,7 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", + "const-oid 0.9.6", "pem-rfc7468", "zeroize", ] @@ -383,12 +422,24 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "block-buffer 0.12.0", + "const-oid 0.10.2", + "crypto-common 0.2.1", + "ctutils", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -514,7 +565,7 @@ checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", - "spin 0.9.8", + "spin", ] [[package]] @@ -582,9 +633,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.29" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -597,9 +648,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -607,15 +658,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -635,15 +686,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -652,21 +703,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -676,7 +727,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -710,16 +760,16 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "rand_core 0.10.0", + "rand_core 0.10.1", "wasip2", "wasip3", ] [[package]] name = "gimli" -version = "0.28.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "hash32" @@ -783,7 +833,7 @@ dependencies = [ "hash32", "rustc_version", "serde", - "spin 0.9.8", + "spin", "stable_deref_trait", ] @@ -793,12 +843,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" - [[package]] name = "hermit-abi" version = "0.5.2" @@ -817,7 +861,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac", + "hmac 0.12.1", ] [[package]] @@ -826,7 +870,16 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.2", ] [[package]] @@ -844,6 +897,15 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +[[package]] +name = "hybrid-array" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214" +dependencies = [ + "typenum", +] + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -995,7 +1057,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ - "hermit-abi 0.5.2", + "hermit-abi", "libc", "windows-sys 0.61.2", ] @@ -1017,20 +1079,23 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ + "cfg-if", + "futures-util", + "once_cell", "wasm-bindgen", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.5.2", + "spin", ] [[package]] @@ -1041,9 +1106,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.184" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libm" @@ -1076,9 +1141,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" @@ -1097,9 +1162,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "md-5" @@ -1108,22 +1173,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] name = "memchr" -version = "2.6.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -1191,28 +1256,28 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi", "libc", ] [[package]] name = "object" -version = "0.32.1" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "oslog" @@ -1282,15 +1347,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkcs1" @@ -1315,9 +1374,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plain" @@ -1442,6 +1501,24 @@ dependencies = [ "prost", ] +[[package]] +name = "protocols" +version = "0.1.0" +dependencies = [ + "base64", + "blahaj", + "hmac 0.13.0", + "postcard", + "pretty_env_logger", + "prost", + "prost-build", + "rand 0.10.1", + "serde", + "sha2 0.11.0", + "thiserror", + "tracing", +] + [[package]] name = "quote" version = "1.0.45" @@ -1476,7 +1553,7 @@ checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20", "getrandom 0.4.2", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -1500,9 +1577,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "redox_syscall" @@ -1524,9 +1601,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -1536,9 +1613,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -1547,9 +1624,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rsa" @@ -1557,8 +1634,8 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", @@ -1575,14 +1652,11 @@ dependencies = [ name = "rust_lib_twonly" version = "0.1.0" dependencies = [ - "blahaj", "flutter_rust_bridge", - "postcard", "pretty_env_logger", - "prost", "prost-build", + "protocols", "rand 0.10.1", - "serde", "sqlx", "thiserror", "tokio", @@ -1591,9 +1665,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc_version" @@ -1606,17 +1680,23 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.44" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "ryu" version = "1.0.23" @@ -1698,7 +1778,7 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", ] [[package]] @@ -1709,7 +1789,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.2", ] [[package]] @@ -1734,18 +1825,15 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -1766,12 +1854,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -1830,7 +1912,7 @@ dependencies = [ "percent-encoding", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "thiserror", "tokio", @@ -1867,7 +1949,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -1891,7 +1973,7 @@ dependencies = [ "bytes", "chrono", "crc", - "digest", + "digest 0.10.7", "dotenvy", "either", "futures-channel", @@ -1901,7 +1983,7 @@ dependencies = [ "generic-array", "hex", "hkdf", - "hmac", + "hmac 0.12.1", "itoa", "log", "md-5", @@ -1911,7 +1993,7 @@ dependencies = [ "rsa", "serde", "sha1", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", @@ -1939,7 +2021,7 @@ dependencies = [ "futures-util", "hex", "hkdf", - "hmac", + "hmac 0.12.1", "home", "itoa", "log", @@ -1948,7 +2030,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", @@ -2029,14 +2111,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.4.2", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2104,9 +2187,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.51.1" +version = "1.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" +checksum = "a91135f59b1cbf38c91e73cf3386fca9bb77915c45ce2771460c9d92f0f3d776" dependencies = [ "bytes", "libc", @@ -2175,9 +2258,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-bidi" @@ -2187,9 +2270,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-normalization" @@ -2238,9 +2321,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" @@ -2274,46 +2357,32 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", "once_cell", - "proc-macro2", - "quote", - "syn", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" dependencies = [ - "cfg-if", "js-sys", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2321,22 +2390,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-encoder" @@ -2374,9 +2446,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" dependencies = [ "js-sys", "wasm-bindgen", @@ -2460,15 +2532,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.59.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index eaf86a76..274b4676 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,34 +1,3 @@ -[package] -name = "rust_lib_twonly" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib", "staticlib"] - -[dependencies] -flutter_rust_bridge = "=2.12.0" -thiserror = "2.0.18" -sqlx = { version = "0.9.0-alpha.1", default-features = false, features = [ - "runtime-tokio", - "sqlite", - "migrate", - "macros", - "chrono", - "derive", - "json", -] } -tokio = { version = "1.44", features = ["full"] } -tracing = "0.1.44" -serde = "1.0.228" -prost = "0.14.1" -rand = "0.10.1" -blahaj = "0.6.0" -postcard = { version = "1.1.3", features = ["alloc"] } - -[dev-dependencies] -pretty_env_logger = "0.5.0" - - -[build-dependencies] -prost-build = "0.14.1" +[workspace] +members = ["protocols", "core"] +resolver = "3" diff --git a/rust/build.rs b/rust/build.rs deleted file mode 100644 index 135361e9..00000000 --- a/rust/build.rs +++ /dev/null @@ -1,5 +0,0 @@ -use std::io::Result; -fn main() -> Result<()> { - prost_build::compile_protos(&["src/user_discovery/types.proto"], &["src/"])?; - Ok(()) -} diff --git a/rust/core/.gitignore b/rust/core/.gitignore new file mode 100644 index 00000000..dfb400ce --- /dev/null +++ b/rust/core/.gitignore @@ -0,0 +1,3 @@ +/target + +tests/tmp_testing.db* \ No newline at end of file diff --git a/rust/core/Cargo.toml b/rust/core/Cargo.toml new file mode 100644 index 00000000..1f76cb6f --- /dev/null +++ b/rust/core/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "rust_lib_twonly" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "staticlib"] + +[dependencies] +flutter_rust_bridge = "=2.12.0" +thiserror = "2.0.18" +sqlx = { version = "0.9.0-alpha.1", default-features = false, features = [ + "runtime-tokio", + "sqlite", + "migrate", + "macros", + "chrono", + "derive", + "json", +] } +tokio = { version = "1.44", features = ["full"] } +tracing = "0.1.44" +rand = "0.10.1" +protocols = { path = "../protocols" } + +[dev-dependencies] +pretty_env_logger = "0.5.0" + + +[build-dependencies] +prost-build = "0.14.1" diff --git a/rust/src/twonly/error.rs b/rust/core/src/bridge/error.rs similarity index 100% rename from rust/src/twonly/error.rs rename to rust/core/src/bridge/error.rs diff --git a/rust/src/twonly/log/mod.rs b/rust/core/src/bridge/log/mod.rs similarity index 100% rename from rust/src/twonly/log/mod.rs rename to rust/core/src/bridge/log/mod.rs diff --git a/rust/src/twonly/mod.rs b/rust/core/src/bridge/mod.rs similarity index 71% rename from rust/src/twonly/mod.rs rename to rust/core/src/bridge/mod.rs index bf4e0f95..fbcc08b4 100644 --- a/rust/src/twonly/mod.rs +++ b/rust/core/src/bridge/mod.rs @@ -1,19 +1,33 @@ -pub mod database; pub mod error; -use crate::twonly::{database::contact::Contact, error::TwonlyError}; -use database::Database; +mod user_discovery; +use crate::database::contact::Contact; +use crate::database::Database; use error::Result; +use error::TwonlyError; +use flutter_rust_bridge::frb; use std::sync::Arc; use tokio::sync::OnceCell; +use protocols::user_discovery::traits::OtherPromotion; + +#[frb(mirror(OtherPromotion))] +pub struct _OtherPromotion { + pub promotion_id: u32, + pub public_id: u64, + pub from_contact_id: i64, + pub threshold: u8, + pub announcement_share: Vec, + pub public_key_verified_timestamp: Option, +} + pub struct TwonlyConfig { pub database_path: String, } -struct Twonly { +pub(crate) struct Twonly { #[allow(dead_code)] pub(crate) config: TwonlyConfig, - database: Arc, + pub(crate) database: Arc, } static GLOBAL_TWONLY: OnceCell = OnceCell::const_new(); @@ -41,15 +55,19 @@ pub async fn get_all_contacts() -> Result> { Contact::get_all_contacts(twonly.database.as_ref()).await } +pub fn load_promotions() -> OtherPromotion { + todo!() +} + #[cfg(test)] pub(crate) mod tests { use super::error::Result; use super::Twonly; use std::path::PathBuf; - use crate::twonly::{get_instance, initialize_twonly, TwonlyConfig}; + use super::{get_instance, initialize_twonly, TwonlyConfig}; - pub(super) async fn initialize_twonly_for_testing() -> Result<&'static Twonly> { + pub(crate) async fn initialize_twonly_for_testing() -> Result<&'static Twonly> { let default_twonly_database = PathBuf::from("tests/testing.db"); if !default_twonly_database.is_file() { diff --git a/rust/core/src/bridge/user_discovery.rs b/rust/core/src/bridge/user_discovery.rs new file mode 100644 index 00000000..29e128ec --- /dev/null +++ b/rust/core/src/bridge/user_discovery.rs @@ -0,0 +1,72 @@ +use protocols::user_discovery::error::{Result, UserDiscoveryError}; +use protocols::user_discovery::traits::{AnnouncedUser, OtherPromotion, UserDiscoveryStore}; +use protocols::user_discovery::UserID; +use std::collections::HashMap; + +struct UserDiscoveryDatabaseStore {} + +impl UserDiscoveryStore for UserDiscoveryDatabaseStore { + fn get_config(&self) -> Result> { + todo!() + } + + fn update_config(&self, update: Vec) -> Result<()> { + todo!() + } + + fn set_shares(&self, shares: Vec>) -> Result<()> { + todo!() + } + + fn get_share_for_contact(&self, contact_id: UserID) -> Result> { + todo!() + } + + fn push_own_promotion( + &self, + contact_id: UserID, + version: u32, + promotion: Vec, + ) -> Result<()> { + todo!() + } + + fn get_own_promotions_after_version(&self, version: u32) -> Result>> { + todo!() + } + + fn store_other_promotion(&self, promotion: OtherPromotion) -> Result<()> { + todo!() + } + + fn get_other_promotions_by_public_id(&self, public_id: u64) -> Vec { + todo!() + } + + fn get_announced_user_by_public_id(&self, public_id: u64) -> Result> { + todo!() + } + + fn push_new_user_relation( + &self, + from_contact_id: UserID, + announced_user: AnnouncedUser, + public_key_verified_timestamp: Option, + ) -> Result<()> { + todo!() + } + + fn get_all_announced_users( + &self, + ) -> Result)>>> { + todo!() + } + + fn get_contact_version(&self, contact_id: UserID) -> Result>> { + todo!() + } + + fn set_contact_version(&self, contact_id: UserID, update: Vec) -> Result<()> { + todo!() + } +} diff --git a/rust/src/twonly/database/contact.rs b/rust/core/src/database/contact.rs similarity index 89% rename from rust/src/twonly/database/contact.rs rename to rust/core/src/database/contact.rs index 084d3e09..710c199e 100644 --- a/rust/src/twonly/database/contact.rs +++ b/rust/core/src/database/contact.rs @@ -1,7 +1,8 @@ // use sqlx::types::chrono::{DateTime, Utc}; use sqlx::FromRow; -use crate::twonly::{database::Database, error::Result}; +use super::Database; +use crate::bridge::error::Result; #[derive(FromRow, Clone, Debug)] struct ContactRow { @@ -37,7 +38,8 @@ impl Contact { #[cfg(test)] mod tests { - use crate::twonly::{database::contact::Contact, tests::initialize_twonly_for_testing}; + use crate::bridge::tests::initialize_twonly_for_testing; + use crate::database::contact::Contact; #[tokio::test] async fn test_get_all_contacts() { diff --git a/rust/src/twonly/database/mod.rs b/rust/core/src/database/mod.rs similarity index 88% rename from rust/src/twonly/database/mod.rs rename to rust/core/src/database/mod.rs index d35dff71..db873560 100644 --- a/rust/src/twonly/database/mod.rs +++ b/rust/core/src/database/mod.rs @@ -1,13 +1,8 @@ -pub mod contact; - -use crate::twonly::error::TwonlyError; - -use super::error::Result; -use sqlx::{ - migrate::MigrateDatabase, - sqlite::{SqliteConnectOptions, SqlitePoolOptions}, - ConnectOptions, Sqlite, SqlitePool, -}; +pub(crate) mod contact; +use crate::bridge::error::{Result, TwonlyError}; +use sqlx::migrate::MigrateDatabase; +use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; +use sqlx::{ConnectOptions, Sqlite, SqlitePool}; use std::time::Duration; pub(crate) struct Database { diff --git a/rust/src/frb_generated.rs b/rust/core/src/frb_generated.rs similarity index 62% rename from rust/src/frb_generated.rs rename to rust/core/src/frb_generated.rs index 60ced766..536a9884 100644 --- a/rust/src/frb_generated.rs +++ b/rust/core/src/frb_generated.rs @@ -38,7 +38,7 @@ flutter_rust_bridge::frb_generated_boilerplate!( default_rust_auto_opaque = RustAutoOpaqueMoi, ); pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0"; -pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 741438464; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 776002844; // Section: executor @@ -46,7 +46,7 @@ flutter_rust_bridge::frb_generated_default_handler!(); // Section: wire_funcs -fn wire__crate__twonly__get_all_contacts_impl( +fn wire__crate__bridge__get_all_contacts_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, rust_vec_len_: i32, @@ -72,7 +72,7 @@ fn wire__crate__twonly__get_all_contacts_impl( move |context| async move { transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( (move || async move { - let output_ok = crate::twonly::get_all_contacts().await?; + let output_ok = crate::bridge::get_all_contacts().await?; Ok(output_ok) })() .await, @@ -81,7 +81,7 @@ fn wire__crate__twonly__get_all_contacts_impl( }, ) } -fn wire__crate__twonly__initialize_twonly_impl( +fn wire__crate__bridge__initialize_twonly_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, rust_vec_len_: i32, @@ -103,12 +103,12 @@ fn wire__crate__twonly__initialize_twonly_impl( }; let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); - let api_config = ::sse_decode(&mut deserializer); + let api_config = ::sse_decode(&mut deserializer); deserializer.end(); move |context| async move { transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( (move || async move { - let output_ok = crate::twonly::initialize_twonly(api_config).await?; + let output_ok = crate::bridge::initialize_twonly(api_config).await?; Ok(output_ok) })() .await, @@ -117,6 +117,51 @@ fn wire__crate__twonly__initialize_twonly_impl( }, ) } +fn wire__crate__bridge__load_promotions_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "load_promotions", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok(crate::bridge::load_promotions())?; + Ok(output_ok) + })()) + } + }, + ) +} + +// Section: static_checks + +#[allow(clippy::unnecessary_literal_unwrap)] +const _: fn() = || { + let OtherPromotion = None::.unwrap(); + let _: u32 = OtherPromotion.promotion_id; + let _: u64 = OtherPromotion.public_id; + let _: i64 = OtherPromotion.from_contact_id; + let _: u8 = OtherPromotion.threshold; + let _: Vec = OtherPromotion.announcement_share; + let _: Option = OtherPromotion.public_key_verified_timestamp; +}; // Section: dart2rust @@ -136,12 +181,12 @@ impl SseDecode for String { } } -impl SseDecode for crate::twonly::database::contact::Contact { +impl SseDecode for crate::database::contact::Contact { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { let mut var_userId = ::sse_decode(deserializer); let mut var_username = ::sse_decode(deserializer); - return crate::twonly::database::contact::Contact { + return crate::database::contact::Contact { user_id: var_userId, username: var_username, }; @@ -155,13 +200,13 @@ impl SseDecode for i64 { } } -impl SseDecode for Vec { +impl SseDecode for Vec { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { let mut len_ = ::sse_decode(deserializer); let mut ans_ = Vec::with_capacity(len_ as usize); for idx_ in 0..len_ { - ans_.push(::sse_decode( + ans_.push(::sse_decode( deserializer, )); } @@ -181,16 +226,61 @@ impl SseDecode for Vec { } } -impl SseDecode for crate::twonly::TwonlyConfig { +impl SseDecode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + if (::sse_decode(deserializer)) { + return Some(::sse_decode(deserializer)); + } else { + return None; + } + } +} + +impl SseDecode for crate::bridge::OtherPromotion { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_promotionId = ::sse_decode(deserializer); + let mut var_publicId = ::sse_decode(deserializer); + let mut var_fromContactId = ::sse_decode(deserializer); + let mut var_threshold = ::sse_decode(deserializer); + let mut var_announcementShare = >::sse_decode(deserializer); + let mut var_publicKeyVerifiedTimestamp = >::sse_decode(deserializer); + return crate::bridge::OtherPromotion { + promotion_id: var_promotionId, + public_id: var_publicId, + from_contact_id: var_fromContactId, + threshold: var_threshold, + announcement_share: var_announcementShare, + public_key_verified_timestamp: var_publicKeyVerifiedTimestamp, + }; + } +} + +impl SseDecode for crate::bridge::TwonlyConfig { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { let mut var_databasePath = ::sse_decode(deserializer); - return crate::twonly::TwonlyConfig { + return crate::bridge::TwonlyConfig { database_path: var_databasePath, }; } } +impl SseDecode for u32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u32::().unwrap() + } +} + +impl SseDecode for u64 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u64::().unwrap() + } +} + impl SseDecode for u8 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -226,8 +316,9 @@ fn pde_ffi_dispatcher_primary_impl( ) { // Codec=Pde (Serialization + dispatch), see doc to use other codecs match func_id { - 1 => wire__crate__twonly__get_all_contacts_impl(port, ptr, rust_vec_len, data_len), - 2 => wire__crate__twonly__initialize_twonly_impl(port, ptr, rust_vec_len, data_len), + 1 => wire__crate__bridge__get_all_contacts_impl(port, ptr, rust_vec_len, data_len), + 2 => wire__crate__bridge__initialize_twonly_impl(port, ptr, rust_vec_len, data_len), + 3 => wire__crate__bridge__load_promotions_impl(port, ptr, rust_vec_len, data_len), _ => unreachable!(), } } @@ -247,7 +338,7 @@ fn pde_ffi_dispatcher_sync_impl( // Section: rust2dart // Codec=Dco (DartCObject based), see doc to use other codecs -impl flutter_rust_bridge::IntoDart for crate::twonly::database::contact::Contact { +impl flutter_rust_bridge::IntoDart for crate::database::contact::Contact { fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { [ self.user_id.into_into_dart().into_dart(), @@ -257,27 +348,55 @@ impl flutter_rust_bridge::IntoDart for crate::twonly::database::contact::Contact } } impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive - for crate::twonly::database::contact::Contact + for crate::database::contact::Contact { } -impl flutter_rust_bridge::IntoIntoDart - for crate::twonly::database::contact::Contact +impl flutter_rust_bridge::IntoIntoDart + for crate::database::contact::Contact { - fn into_into_dart(self) -> crate::twonly::database::contact::Contact { + fn into_into_dart(self) -> crate::database::contact::Contact { self } } // Codec=Dco (DartCObject based), see doc to use other codecs -impl flutter_rust_bridge::IntoDart for crate::twonly::TwonlyConfig { +impl flutter_rust_bridge::IntoDart for FrbWrapper { + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + [ + self.0.promotion_id.into_into_dart().into_dart(), + self.0.public_id.into_into_dart().into_dart(), + self.0.from_contact_id.into_into_dart().into_dart(), + self.0.threshold.into_into_dart().into_dart(), + self.0.announcement_share.into_into_dart().into_dart(), + self.0 + .public_key_verified_timestamp + .into_into_dart() + .into_dart(), + ] + .into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive + for FrbWrapper +{ +} +impl flutter_rust_bridge::IntoIntoDart> + for crate::bridge::OtherPromotion +{ + fn into_into_dart(self) -> FrbWrapper { + self.into() + } +} +// Codec=Dco (DartCObject based), see doc to use other codecs +impl flutter_rust_bridge::IntoDart for crate::bridge::TwonlyConfig { fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { [self.database_path.into_into_dart().into_dart()].into_dart() } } -impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::twonly::TwonlyConfig {} -impl flutter_rust_bridge::IntoIntoDart - for crate::twonly::TwonlyConfig +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::bridge::TwonlyConfig {} +impl flutter_rust_bridge::IntoIntoDart + for crate::bridge::TwonlyConfig { - fn into_into_dart(self) -> crate::twonly::TwonlyConfig { + fn into_into_dart(self) -> crate::bridge::TwonlyConfig { self } } @@ -296,7 +415,7 @@ impl SseEncode for String { } } -impl SseEncode for crate::twonly::database::contact::Contact { +impl SseEncode for crate::database::contact::Contact { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { ::sse_encode(self.user_id, serializer); @@ -311,12 +430,12 @@ impl SseEncode for i64 { } } -impl SseEncode for Vec { +impl SseEncode for Vec { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { ::sse_encode(self.len() as _, serializer); for item in self { - ::sse_encode(item, serializer); + ::sse_encode(item, serializer); } } } @@ -331,13 +450,49 @@ impl SseEncode for Vec { } } -impl SseEncode for crate::twonly::TwonlyConfig { +impl SseEncode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.is_some(), serializer); + if let Some(value) = self { + ::sse_encode(value, serializer); + } + } +} + +impl SseEncode for crate::bridge::OtherPromotion { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.promotion_id, serializer); + ::sse_encode(self.public_id, serializer); + ::sse_encode(self.from_contact_id, serializer); + ::sse_encode(self.threshold, serializer); + >::sse_encode(self.announcement_share, serializer); + >::sse_encode(self.public_key_verified_timestamp, serializer); + } +} + +impl SseEncode for crate::bridge::TwonlyConfig { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { ::sse_encode(self.database_path, serializer); } } +impl SseEncode for u32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u32::(self).unwrap(); + } +} + +impl SseEncode for u64 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u64::(self).unwrap(); + } +} + impl SseEncode for u8 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { diff --git a/rust/core/src/lib.rs b/rust/core/src/lib.rs new file mode 100644 index 00000000..ac8b48f8 --- /dev/null +++ b/rust/core/src/lib.rs @@ -0,0 +1,3 @@ +pub mod bridge; +mod database; +mod frb_generated; diff --git a/rust/tests/testing.db b/rust/core/tests/testing.db similarity index 100% rename from rust/tests/testing.db rename to rust/core/tests/testing.db diff --git a/rust/protocols/Cargo.toml b/rust/protocols/Cargo.toml new file mode 100644 index 00000000..d0e95b35 --- /dev/null +++ b/rust/protocols/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "protocols" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["rlib", "cdylib", "staticlib"] + +[dependencies] +thiserror = "2.0.18" +tracing = "0.1.44" +serde = "1.0.228" +prost = "0.14.1" +rand = "0.10.1" +blahaj = "0.6.0" +postcard = { version = "1.1.3", features = ["alloc"] } +base64 = "0.22.1" +hmac = "0.13.0" +sha2 = "0.11.0" + +[dev-dependencies] +pretty_env_logger = "0.5.0" + +[build-dependencies] +prost-build = "0.14.1" diff --git a/rust/protocols/build.rs b/rust/protocols/build.rs new file mode 100644 index 00000000..12e4744b --- /dev/null +++ b/rust/protocols/build.rs @@ -0,0 +1,11 @@ +use std::io::Result; +fn main() -> Result<()> { + prost_build::compile_protos( + &[ + "src/user_discovery/types.proto", + "src/key_verification/types.proto", + ], + &["src/"], + )?; + Ok(()) +} diff --git a/rust/protocols/src/key_verification/error.rs b/rust/protocols/src/key_verification/error.rs new file mode 100644 index 00000000..a23b1d1c --- /dev/null +++ b/rust/protocols/src/key_verification/error.rs @@ -0,0 +1,30 @@ +use prost::DecodeError; +use thiserror::Error; + +pub type Result = core::result::Result; + +#[derive(Error, Debug)] +pub enum KeyVerificationError { + #[error("The prefix deeplink url must start with https:// and end with a #")] + InvalidDeeplinkPrefix, + + #[error("Invalid qr text")] + InvalidQrText, + + #[error( + "Contact user_id is known and the stored public_key does not match the received user id" + )] + InvalidPublicKeyAndUserIdCombination, + + #[error("Store error: `{0}`")] + Store(String), + + #[error("`{0}`")] + Base64(#[from] base64::DecodeError), + + #[error("`{0}`")] + Prost(#[from] DecodeError), + + #[error("`{0}`")] + Hmac(#[from] hmac::digest::InvalidLength), +} diff --git a/rust/protocols/src/key_verification/mod.rs b/rust/protocols/src/key_verification/mod.rs new file mode 100644 index 00000000..f3493473 --- /dev/null +++ b/rust/protocols/src/key_verification/mod.rs @@ -0,0 +1,194 @@ +use crate::key_verification::{error::KeyVerificationError, traits::KeyVerificationStore}; +use crate::user_discovery::UserID; +use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _}; +use error::Result; +use hmac::{Hmac, KeyInit, Mac}; +use prost::Message; +use sha2::Sha256; + +pub(crate) mod error; +pub mod stores; +pub mod traits; + +include!(concat!(env!("OUT_DIR"), "/key_verification.rs")); + +pub struct KeyVerificationConfig { + /// The link prefix for the qr code which should be registered as a deeplink on Android and a universal link on iOS + /// The link MUST start with a https:// and end with a # + /// The link should contain the username of the user so the application can show the scanned user without internet + /// Example: https://me.twonly.eu/tobi# + deeplink_prefix: String, + /// The user ID used to calculate the verification proof + user_id: UserID, + /// The public_key of the user to calculate the verification proof + public_key: Vec, +} + +pub struct ScannedUser { + pub user_id: UserID, + pub public_key: Vec, + pub verification_proof: Vec, +} + +pub struct KeyVerification { + store: Store, + config: KeyVerificationConfig, +} + +impl KeyVerification { + pub fn new(store: Store, config: KeyVerificationConfig) -> Result> { + if !config.deeplink_prefix.starts_with("https://") || !config.deeplink_prefix.ends_with("#") + { + return Err(KeyVerificationError::InvalidDeeplinkPrefix); + } + Ok(Self { store, config }) + } + + /// Generates the a string which should be displayed in the UI so others can scan it. + pub fn generate_qr_text(&self) -> Result { + // 10 Bytes should be enough. Tokens are only valid for one day and then deleted. + let secret_verification_token: Vec = rand::random_iter().take(16).collect(); + + self.store + .push_new_secret_verification_token(&secret_verification_token)?; + + let verification_data = VerificationData { + user_id: self.config.user_id, + public_key: self.config.public_key.clone(), + secret_verification_token, + }; + + let verification_data_bytes = verification_data.encode_to_vec(); + let encoded = URL_SAFE_NO_PAD.encode(verification_data_bytes); + + Ok(format!("{}{}", self.config.deeplink_prefix, encoded)) + } + + /// Handles the scanned qr code text and creates a response message + /// which can be send to the other person + pub fn get_user_from_scanned_qr_text(&self, received_text: &str) -> Result { + let splitted: Vec<_> = received_text.split('#').collect(); + if splitted.len() != 2 { + tracing::info!("Scanned qr text does not contain a #"); + return Err(KeyVerificationError::InvalidQrText); + } + let verification_data_bytes = URL_SAFE_NO_PAD.decode(splitted[1])?; + let verification_data = VerificationData::decode(verification_data_bytes.as_slice())?; + + let mut mac = Hmac::::new_from_slice(&verification_data.secret_verification_token)?; + mac.update(&self.config.user_id.to_le_bytes()); + mac.update(&self.config.public_key); + mac.update(&verification_data.user_id.to_le_bytes()); + mac.update(&verification_data.public_key); + + let verification_proof = mac.finalize().into_bytes().to_vec(); + + Ok(ScannedUser { + user_id: verification_data.user_id, + public_key: verification_data.public_key, + verification_proof, + }) + } + + /// Checks whether the received verification proof is valid + pub fn is_received_verification_proof_valid( + &self, + from_user_id: UserID, + public_key: Vec, + verification_proof: Vec, + ) -> Result { + let verification_tokens = self.store.get_all_valid_verification_tokens()?; + + for verification_token in &verification_tokens { + let calculated_verification_proof = { + let mut mac = Hmac::::new_from_slice(verification_token)?; + mac.update(&from_user_id.to_le_bytes()); + mac.update(&public_key); + mac.update(&self.config.user_id.to_le_bytes()); + mac.update(&self.config.public_key); + mac.finalize().into_bytes().to_vec() + }; + + if calculated_verification_proof == verification_proof { + return Ok(true); + } + } + + Ok(false) + } +} + +#[cfg(test)] +mod tests { + use crate::key_verification::{stores::InMemoryStore, KeyVerification, KeyVerificationConfig}; + + #[test] + fn test_key_verification() { + let _ = pretty_env_logger::try_init(); + + const ALICE_ID: i64 = 10; + const BOB_ID: i64 = 11; + + let alice_kv = KeyVerification::new( + InMemoryStore::default(), + KeyVerificationConfig { + user_id: ALICE_ID, + public_key: vec![ALICE_ID as u8; 32], + deeplink_prefix: "https://me.twonly.eu/alice#".into(), + }, + ) + .unwrap(); + + let bob_kv = KeyVerification::new( + InMemoryStore::default(), + KeyVerificationConfig { + user_id: BOB_ID, + public_key: vec![BOB_ID as u8; 32], + deeplink_prefix: "https://me.twonly.eu/bob#".into(), + }, + ) + .unwrap(); + + let qr_code_text = alice_kv.generate_qr_text().unwrap(); + assert_eq!(qr_code_text.len(), 99); + + tracing::debug!("Generated QR-Code-Link: {qr_code_text}"); + + let scanned_user = bob_kv.get_user_from_scanned_qr_text(&qr_code_text).unwrap(); + + // THIS must be done by the application + assert_eq!(scanned_user.user_id, ALICE_ID); + assert_eq!(scanned_user.public_key, vec![ALICE_ID as u8; 32]); + + // SEND scanned_user.verification_proof over the establish e2ee protected session if public_key verification was valid. + + let valid_verification_proof = alice_kv + .is_received_verification_proof_valid( + BOB_ID, + vec![BOB_ID as u8; 32], + scanned_user.verification_proof.clone(), + ) + .unwrap(); + + assert_eq!(valid_verification_proof, true); + + let valid_verification_proof = alice_kv + .is_received_verification_proof_valid( + BOB_ID, + vec![(BOB_ID + 1) as u8; 32], + scanned_user.verification_proof.clone(), + ) + .unwrap(); + + assert_eq!(valid_verification_proof, false); + + let mut modified_proof = scanned_user.verification_proof; + modified_proof[0] = modified_proof[0] + 1; + + let valid_verification_proof = alice_kv + .is_received_verification_proof_valid(BOB_ID, vec![BOB_ID as u8; 32], modified_proof) + .unwrap(); + + assert_eq!(valid_verification_proof, false); + } +} diff --git a/rust/protocols/src/key_verification/stores/in_memory_store.rs b/rust/protocols/src/key_verification/stores/in_memory_store.rs new file mode 100644 index 00000000..160fbfb8 --- /dev/null +++ b/rust/protocols/src/key_verification/stores/in_memory_store.rs @@ -0,0 +1,22 @@ +use std::sync::{Arc, Mutex}; + +use crate::key_verification::{error::Result, traits::KeyVerificationStore}; + +#[derive(Default)] +pub struct InMemoryStore { + verification_tokens: Arc>>>, +} + +impl KeyVerificationStore for InMemoryStore { + fn push_new_secret_verification_token(&self, token: &[u8]) -> Result<()> { + self.verification_tokens + .lock() + .unwrap() + .push(token.to_vec()); + Ok(()) + } + + fn get_all_valid_verification_tokens(&self) -> Result>> { + Ok(self.verification_tokens.lock().unwrap().clone()) + } +} diff --git a/rust/protocols/src/key_verification/stores/mod.rs b/rust/protocols/src/key_verification/stores/mod.rs new file mode 100644 index 00000000..30b1f14d --- /dev/null +++ b/rust/protocols/src/key_verification/stores/mod.rs @@ -0,0 +1,3 @@ +mod in_memory_store; + +pub use in_memory_store::InMemoryStore; diff --git a/rust/protocols/src/key_verification/traits.rs b/rust/protocols/src/key_verification/traits.rs new file mode 100644 index 00000000..1689e3a8 --- /dev/null +++ b/rust/protocols/src/key_verification/traits.rs @@ -0,0 +1,7 @@ +use super::error::Result; +pub trait KeyVerificationStore { + fn push_new_secret_verification_token(&self, token: &[u8]) -> Result<()>; + /// This function should return all tokens from the last 24h + /// All other tokens can be removed from the database + fn get_all_valid_verification_tokens(&self) -> Result>>; +} diff --git a/rust/protocols/src/key_verification/types.proto b/rust/protocols/src/key_verification/types.proto new file mode 100644 index 00000000..bd515eb0 --- /dev/null +++ b/rust/protocols/src/key_verification/types.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +package key_verification; + +message VerificationData { + int64 user_id = 1; + bytes public_key = 2; + bytes secret_verification_token = 3; +} + +message VerificationMessage { + bytes calculated_mac = 1; +} \ No newline at end of file diff --git a/rust/protocols/src/lib.rs b/rust/protocols/src/lib.rs new file mode 100644 index 00000000..85641306 --- /dev/null +++ b/rust/protocols/src/lib.rs @@ -0,0 +1,3 @@ +pub mod key_verification; +pub mod passwordless_recovery; +pub mod user_discovery; diff --git a/rust/src/passwordless_recovery/mod.rs b/rust/protocols/src/passwordless_recovery/mod.rs similarity index 100% rename from rust/src/passwordless_recovery/mod.rs rename to rust/protocols/src/passwordless_recovery/mod.rs diff --git a/rust/src/passwordless_recovery/traits.rs b/rust/protocols/src/passwordless_recovery/traits.rs similarity index 100% rename from rust/src/passwordless_recovery/traits.rs rename to rust/protocols/src/passwordless_recovery/traits.rs diff --git a/rust/src/user_discovery/README.md b/rust/protocols/src/user_discovery/README.md similarity index 100% rename from rust/src/user_discovery/README.md rename to rust/protocols/src/user_discovery/README.md diff --git a/rust/src/user_discovery/error.rs b/rust/protocols/src/user_discovery/error.rs similarity index 92% rename from rust/src/user_discovery/error.rs rename to rust/protocols/src/user_discovery/error.rs index 0c0246ea..7ef9b105 100644 --- a/rust/src/user_discovery/error.rs +++ b/rust/protocols/src/user_discovery/error.rs @@ -5,6 +5,9 @@ pub type Result = core::result::Result; #[derive(Error, Debug)] pub enum UserDiscoveryError { + #[error("Store error: `{0}`")] + Store(String), + #[error("The encrypted announcement data contains malicious data: `{0}`")] MaliciousAnnouncementData(String), diff --git a/rust/src/user_discovery/mod.rs b/rust/protocols/src/user_discovery/mod.rs similarity index 99% rename from rust/src/user_discovery/mod.rs rename to rust/protocols/src/user_discovery/mod.rs index 89372fa4..4aa1f000 100644 --- a/rust/src/user_discovery/mod.rs +++ b/rust/protocols/src/user_discovery/mod.rs @@ -1,4 +1,4 @@ -mod error; +pub mod error; pub mod stores; pub mod traits; @@ -22,7 +22,7 @@ static TRANSMITTED_NETWORK_BYTES: std::sync::OnceLock> = /// the types.proto pub type UserID = i64; -include!(concat!(env!("OUT_DIR"), "/_.rs")); +include!(concat!(env!("OUT_DIR"), "/user_discovery.rs")); #[derive(Serialize, Deserialize, Clone, Debug)] struct UserDiscoveryConfig { @@ -245,6 +245,7 @@ impl UserDiscovery stored_version.promotion) } + #[cfg(test)] pub(crate) fn get_contact_version(&self, contact_id: UserID) -> Result>> { self.store.get_contact_version(contact_id) } @@ -687,10 +688,10 @@ mod tests { } } - #[tokio::test] - async fn test_initialize_user_discovery() { - pretty_env_logger::init(); - let counter = TRANSMITTED_NETWORK_BYTES.get_or_init(|| std::sync::Mutex::new(0)); + #[test] + fn test_initialize_user_discovery() { + let _ = pretty_env_logger::try_init(); + let _ = TRANSMITTED_NETWORK_BYTES.get_or_init(|| std::sync::Mutex::new(0)); let users = TestUsers::get(); diff --git a/rust/src/user_discovery/stores/in_memory_store.rs b/rust/protocols/src/user_discovery/stores/in_memory_store.rs similarity index 100% rename from rust/src/user_discovery/stores/in_memory_store.rs rename to rust/protocols/src/user_discovery/stores/in_memory_store.rs diff --git a/rust/src/user_discovery/stores/mod.rs b/rust/protocols/src/user_discovery/stores/mod.rs similarity index 100% rename from rust/src/user_discovery/stores/mod.rs rename to rust/protocols/src/user_discovery/stores/mod.rs diff --git a/rust/src/user_discovery/traits.rs b/rust/protocols/src/user_discovery/traits.rs similarity index 100% rename from rust/src/user_discovery/traits.rs rename to rust/protocols/src/user_discovery/traits.rs diff --git a/rust/src/user_discovery/types.proto b/rust/protocols/src/user_discovery/types.proto similarity index 97% rename from rust/src/user_discovery/types.proto rename to rust/protocols/src/user_discovery/types.proto index 9237586a..50dc1ccc 100644 --- a/rust/src/user_discovery/types.proto +++ b/rust/protocols/src/user_discovery/types.proto @@ -1,4 +1,5 @@ syntax = "proto3"; +package user_discovery; message UserDiscoveryVersion { uint32 announcement = 1; diff --git a/rust/src/key_verification/mod.rs b/rust/src/key_verification/mod.rs deleted file mode 100644 index c347d674..00000000 --- a/rust/src/key_verification/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::key_verification::traits::KeyVerificationStore; - -pub mod traits; - -pub struct KeyVerificationConfig { - /// The link prefix for the qr code which should be registered as a deeplink on Android and a universal link on iOS - deeplink_prefix: String, -} - -struct KeyVerification { - store: Store, - config: KeyVerificationConfig, -} - -impl KeyVerification { - pub fn new(store: Store, config: KeyVerificationConfig) -> KeyVerification { - Self { store, config } - } - - /// Generates the a string which should be displayed in the UI so others can scan it. - pub fn generate_qr_code_data() -> String { - todo!(); - } - - /// Generates the a string which should be displayed in the UI so others can scan it. - pub fn handle_qr_code_data() -> String { - todo!(); - } -} diff --git a/rust/src/key_verification/traits.rs b/rust/src/key_verification/traits.rs deleted file mode 100644 index 1fc4c498..00000000 --- a/rust/src/key_verification/traits.rs +++ /dev/null @@ -1 +0,0 @@ -pub trait KeyVerificationStore {} diff --git a/rust/src/lib.rs b/rust/src/lib.rs deleted file mode 100644 index 0b278cda..00000000 --- a/rust/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod frb_generated; -mod key_verification; -mod passwordless_recovery; -mod twonly; -mod user_discovery; From eb22acacee336de4c3746ef45f23104e376bf760 Mon Sep 17 00:00:00 2001 From: otsmr Date: Fri, 17 Apr 2026 00:22:38 +0200 Subject: [PATCH 06/86] user discovery database store works --- lib/core/bridge.dart | 11 +- lib/core/bridge/user_discovery.dart | 25 + lib/core/frb_generated.dart | 36 +- lib/core/frb_generated.io.dart | 9 - lib/core/frb_generated.web.dart | 9 - lib/main.dart | 1 + lib/src/database/daos/user_discovery.dao.dart | 21 + .../database/daos/user_discovery.dao.g.dart | 47 + .../schemas/twonly_db/drift_schema_v12.json | 2655 +++++ lib/src/database/tables/contacts.table.dart | 32 + .../database/tables/user_discovery.table.dart | 46 +- lib/src/database/twonly.db.dart | 25 +- lib/src/database/twonly.db.g.dart | 5036 ++++++++- lib/src/database/twonly.db.steps.dart | 664 ++ rust/Cargo.lock | 87 +- rust/core/Cargo.toml | 2 + rust/core/src/bridge/error.rs | 9 +- rust/core/src/bridge/mod.rs | 119 +- rust/core/src/bridge/user_discovery.rs | 72 - rust/core/src/bridge/user_discovery_utils.rs | 27 + rust/core/src/database/contact.rs | 4 +- rust/core/src/frb_generated.rs | 29 +- rust/core/src/lib.rs | 2 + rust/core/src/user_discovery_store.rs | 349 + rust/core/src/utils.rs | 22 + rust/core/tests/testing.db | Bin 131072 -> 176128 bytes rust/protocols/Cargo.toml | 6 +- .../mod.rs => user_discovery.rs} | 482 +- rust/protocols/src/user_discovery/error.rs | 5 +- .../user_discovery/stores/in_memory_store.rs | 42 +- rust/protocols/src/user_discovery/tests.rs | 272 + rust/protocols/src/user_discovery/traits.rs | 84 +- rust/protocols/src/user_discovery/types.proto | 10 +- test/drift/twonly_db/generated/schema.dart | 5 +- .../drift/twonly_db/generated/schema_v12.dart | 9358 +++++++++++++++++ test/rust/create_db_for_rust_testing.dart | 2 +- 36 files changed, 18939 insertions(+), 666 deletions(-) create mode 100644 lib/core/bridge/user_discovery.dart create mode 100644 lib/src/database/daos/user_discovery.dao.dart create mode 100644 lib/src/database/daos/user_discovery.dao.g.dart create mode 100644 lib/src/database/schemas/twonly_db/drift_schema_v12.json delete mode 100644 rust/core/src/bridge/user_discovery.rs create mode 100644 rust/core/src/bridge/user_discovery_utils.rs create mode 100644 rust/core/src/user_discovery_store.rs create mode 100644 rust/core/src/utils.rs rename rust/protocols/src/{user_discovery/mod.rs => user_discovery.rs} (55%) create mode 100644 rust/protocols/src/user_discovery/tests.rs create mode 100644 test/drift/twonly_db/generated/schema_v12.dart diff --git a/lib/core/bridge.dart b/lib/core/bridge.dart index 1e4d9ec6..91657918 100644 --- a/lib/core/bridge.dart +++ b/lib/core/bridge.dart @@ -8,7 +8,7 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; import 'database/contact.dart'; import 'frb_generated.dart'; -// These functions are ignored because they are not marked as `pub`: `get_instance` +// These functions are ignored because they are not marked as `pub`: `get_workspace` // These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `Twonly` Future initializeTwonly({required TwonlyConfig config}) => @@ -30,7 +30,7 @@ class OtherPromotion { this.publicKeyVerifiedTimestamp, }); final int promotionId; - final BigInt publicId; + final PlatformInt64 publicId; final PlatformInt64 fromContactId; final int threshold; final Uint8List announcementShare; @@ -61,16 +61,19 @@ class OtherPromotion { class TwonlyConfig { const TwonlyConfig({ required this.databasePath, + required this.dataDirectory, }); final String databasePath; + final String dataDirectory; @override - int get hashCode => databasePath.hashCode; + int get hashCode => databasePath.hashCode ^ dataDirectory.hashCode; @override bool operator ==(Object other) => identical(this, other) || other is TwonlyConfig && runtimeType == other.runtimeType && - databasePath == other.databasePath; + databasePath == other.databasePath && + dataDirectory == other.dataDirectory; } diff --git a/lib/core/bridge/user_discovery.dart b/lib/core/bridge/user_discovery.dart new file mode 100644 index 00000000..46bbebe6 --- /dev/null +++ b/lib/core/bridge/user_discovery.dart @@ -0,0 +1,25 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.12.0. + +// ignore_for_file: invalid_use_of_internal_member, unused_import + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +import '../frb_generated.dart'; + +// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `get_all_announced_users`, `get_announced_user_by_public_id`, `get_config`, `get_contact_version`, `get_other_promotions_by_public_id`, `get_own_promotions_after_version`, `get_share_for_contact`, `push_new_user_relation`, `push_own_promotion`, `set_contact_version`, `set_shares`, `store_other_promotion`, `update_config` + +class UserDiscoveryDatabaseStore { + const UserDiscoveryDatabaseStore(); + + static Future default_() => RustLib.instance.api + .crateBridgeUserDiscoveryUserDiscoveryDatabaseStoreDefault(); + + @override + int get hashCode => 0; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is UserDiscoveryDatabaseStore && runtimeType == other.runtimeType; +} diff --git a/lib/core/frb_generated.dart b/lib/core/frb_generated.dart index e6257b4e..8e9bdf11 100644 --- a/lib/core/frb_generated.dart +++ b/lib/core/frb_generated.dart @@ -253,7 +253,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { throw Exception('unexpected arr length: expect 6 but see ${arr.length}'); return OtherPromotion( promotionId: dco_decode_u_32(arr[0]), - publicId: dco_decode_u_64(arr[1]), + publicId: dco_decode_i_64(arr[1]), fromContactId: dco_decode_i_64(arr[2]), threshold: dco_decode_u_8(arr[3]), announcementShare: dco_decode_list_prim_u_8_strict(arr[4]), @@ -265,10 +265,11 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { TwonlyConfig dco_decode_twonly_config(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs final arr = raw as List; - if (arr.length != 1) - throw Exception('unexpected arr length: expect 1 but see ${arr.length}'); + if (arr.length != 2) + throw Exception('unexpected arr length: expect 2 but see ${arr.length}'); return TwonlyConfig( databasePath: dco_decode_String(arr[0]), + dataDirectory: dco_decode_String(arr[1]), ); } @@ -278,12 +279,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw as int; } - @protected - BigInt dco_decode_u_64(dynamic raw) { - // Codec=Dco (DartCObject based), see doc to use other codecs - return dcoDecodeU64(raw); - } - @protected int dco_decode_u_8(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -372,7 +367,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { OtherPromotion sse_decode_other_promotion(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs final var_promotionId = sse_decode_u_32(deserializer); - final var_publicId = sse_decode_u_64(deserializer); + final var_publicId = sse_decode_i_64(deserializer); final var_fromContactId = sse_decode_i_64(deserializer); final var_threshold = sse_decode_u_8(deserializer); final var_announcementShare = sse_decode_list_prim_u_8_strict(deserializer); @@ -393,7 +388,11 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { TwonlyConfig sse_decode_twonly_config(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs final var_databasePath = sse_decode_String(deserializer); - return TwonlyConfig(databasePath: var_databasePath); + final var_dataDirectory = sse_decode_String(deserializer); + return TwonlyConfig( + databasePath: var_databasePath, + dataDirectory: var_dataDirectory, + ); } @protected @@ -402,12 +401,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return deserializer.buffer.getUint32(); } - @protected - BigInt sse_decode_u_64(SseDeserializer deserializer) { - // Codec=Sse (Serialization based), see doc to use other codecs - return deserializer.buffer.getBigUint64(); - } - @protected int sse_decode_u_8(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -516,7 +509,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ) { // Codec=Sse (Serialization based), see doc to use other codecs sse_encode_u_32(self.promotionId, serializer); - sse_encode_u_64(self.publicId, serializer); + sse_encode_i_64(self.publicId, serializer); sse_encode_i_64(self.fromContactId, serializer); sse_encode_u_8(self.threshold, serializer); sse_encode_list_prim_u_8_strict(self.announcementShare, serializer); @@ -530,6 +523,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { void sse_encode_twonly_config(TwonlyConfig self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs sse_encode_String(self.databasePath, serializer); + sse_encode_String(self.dataDirectory, serializer); } @protected @@ -538,12 +532,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { serializer.buffer.putUint32(self); } - @protected - void sse_encode_u_64(BigInt self, SseSerializer serializer) { - // Codec=Sse (Serialization based), see doc to use other codecs - serializer.buffer.putBigUint64(self); - } - @protected void sse_encode_u_8(int self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs diff --git a/lib/core/frb_generated.io.dart b/lib/core/frb_generated.io.dart index 910683b8..2216764d 100644 --- a/lib/core/frb_generated.io.dart +++ b/lib/core/frb_generated.io.dart @@ -57,9 +57,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected int dco_decode_u_32(dynamic raw); - @protected - BigInt dco_decode_u_64(dynamic raw); - @protected int dco_decode_u_8(dynamic raw); @@ -104,9 +101,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected int sse_decode_u_32(SseDeserializer deserializer); - @protected - BigInt sse_decode_u_64(SseDeserializer deserializer); - @protected int sse_decode_u_8(SseDeserializer deserializer); @@ -173,9 +167,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_u_32(int self, SseSerializer serializer); - @protected - void sse_encode_u_64(BigInt self, SseSerializer serializer); - @protected void sse_encode_u_8(int self, SseSerializer serializer); diff --git a/lib/core/frb_generated.web.dart b/lib/core/frb_generated.web.dart index d45c0315..b658ac73 100644 --- a/lib/core/frb_generated.web.dart +++ b/lib/core/frb_generated.web.dart @@ -58,9 +58,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected int dco_decode_u_32(dynamic raw); - @protected - BigInt dco_decode_u_64(dynamic raw); - @protected int dco_decode_u_8(dynamic raw); @@ -105,9 +102,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected int sse_decode_u_32(SseDeserializer deserializer); - @protected - BigInt sse_decode_u_64(SseDeserializer deserializer); - @protected int sse_decode_u_8(SseDeserializer deserializer); @@ -174,9 +168,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_u_32(int self, SseSerializer serializer); - @protected - void sse_encode_u_64(BigInt self, SseSerializer serializer); - @protected void sse_encode_u_8(int self, SseSerializer serializer); diff --git a/lib/main.dart b/lib/main.dart index 0236f632..51d3e381 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -40,6 +40,7 @@ void main() async { await bridge.initializeTwonly( config: bridge.TwonlyConfig( databasePath: '$globalApplicationSupportDirectory/twonly.sqlite', + dataDirectory: globalApplicationSupportDirectory, ), ); diff --git a/lib/src/database/daos/user_discovery.dao.dart b/lib/src/database/daos/user_discovery.dao.dart new file mode 100644 index 00000000..143e2d4c --- /dev/null +++ b/lib/src/database/daos/user_discovery.dao.dart @@ -0,0 +1,21 @@ +import 'package:drift/drift.dart'; +import 'package:twonly/src/database/tables/user_discovery.table.dart'; +import 'package:twonly/src/database/twonly.db.dart'; + +part 'user_discovery.dao.g.dart'; + +@DriftAccessor( + tables: [ + UserDiscoveryAnnouncedUsers, + UserDiscoveryUserRelations, + UserDiscoveryOwnPromotions, + UserDiscoveryShares, + ], +) +class UserDiscoveryDao extends DatabaseAccessor + with _$UserDiscoveryDaoMixin { + // this constructor is required so that the main database can create an instance + // of this object. + // ignore: matching_super_parameters + UserDiscoveryDao(super.db); +} diff --git a/lib/src/database/daos/user_discovery.dao.g.dart b/lib/src/database/daos/user_discovery.dao.g.dart new file mode 100644 index 00000000..f2103528 --- /dev/null +++ b/lib/src/database/daos/user_discovery.dao.g.dart @@ -0,0 +1,47 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user_discovery.dao.dart'; + +// ignore_for_file: type=lint +mixin _$UserDiscoveryDaoMixin on DatabaseAccessor { + $UserDiscoveryAnnouncedUsersTable get userDiscoveryAnnouncedUsers => + attachedDatabase.userDiscoveryAnnouncedUsers; + $ContactsTable get contacts => attachedDatabase.contacts; + $UserDiscoveryUserRelationsTable get userDiscoveryUserRelations => + attachedDatabase.userDiscoveryUserRelations; + $UserDiscoveryOwnPromotionsTable get userDiscoveryOwnPromotions => + attachedDatabase.userDiscoveryOwnPromotions; + $UserDiscoverySharesTable get userDiscoveryShares => + attachedDatabase.userDiscoveryShares; + UserDiscoveryDaoManager get managers => UserDiscoveryDaoManager(this); +} + +class UserDiscoveryDaoManager { + final _$UserDiscoveryDaoMixin _db; + UserDiscoveryDaoManager(this._db); + $$UserDiscoveryAnnouncedUsersTableTableManager + get userDiscoveryAnnouncedUsers => + $$UserDiscoveryAnnouncedUsersTableTableManager( + _db.attachedDatabase, + _db.userDiscoveryAnnouncedUsers, + ); + $$ContactsTableTableManager get contacts => + $$ContactsTableTableManager(_db.attachedDatabase, _db.contacts); + $$UserDiscoveryUserRelationsTableTableManager + get userDiscoveryUserRelations => + $$UserDiscoveryUserRelationsTableTableManager( + _db.attachedDatabase, + _db.userDiscoveryUserRelations, + ); + $$UserDiscoveryOwnPromotionsTableTableManager + get userDiscoveryOwnPromotions => + $$UserDiscoveryOwnPromotionsTableTableManager( + _db.attachedDatabase, + _db.userDiscoveryOwnPromotions, + ); + $$UserDiscoverySharesTableTableManager get userDiscoveryShares => + $$UserDiscoverySharesTableTableManager( + _db.attachedDatabase, + _db.userDiscoveryShares, + ); +} diff --git a/lib/src/database/schemas/twonly_db/drift_schema_v12.json b/lib/src/database/schemas/twonly_db/drift_schema_v12.json new file mode 100644 index 00000000..8a5c1609 --- /dev/null +++ b/lib/src/database/schemas/twonly_db/drift_schema_v12.json @@ -0,0 +1,2655 @@ +{ + "_meta": { + "description": "This file contains a serialized version of schema entities for drift.", + "version": "1.3.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, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "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_compressed", + "getter_name": "avatarSvgCompressed", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_profile_counter", + "getter_name": "senderProfileCounter", + "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": "deleted_by_user", + "getter_name": "deletedByUser", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"deleted_by_user\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"deleted_by_user\" 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": "account_deleted", + "getter_name": "accountDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"account_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"account_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "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": "user_discovery_version", + "getter_name": "userDiscoveryVersion", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "user_id" + ] + } + }, + { + "id": 1, + "references": [], + "type": "table", + "data": { + "name": "groups", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_group_admin", + "getter_name": "isGroupAdmin", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_group_admin\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_group_admin\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_direct_chat", + "getter_name": "isDirectChat", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_direct_chat\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_direct_chat\" 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": "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": "joined_group", + "getter_name": "joinedGroup", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"joined_group\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"joined_group\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "left_group", + "getter_name": "leftGroup", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"left_group\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"left_group\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "deleted_content", + "getter_name": "deletedContent", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"deleted_content\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"deleted_content\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "state_version_id", + "getter_name": "stateVersionId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "state_encryption_key", + "getter_name": "stateEncryptionKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "my_group_private_key", + "getter_name": "myGroupPrivateKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "group_name", + "getter_name": "groupName", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "draft_message", + "getter_name": "draftMessage", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "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": "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_milliseconds", + "getter_name": "deleteMessagesAfterMilliseconds", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('86400000')", + "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": "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": "flame_counter", + "getter_name": "flameCounter", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "max_flame_counter", + "getter_name": "maxFlameCounter", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "max_flame_counter_from", + "getter_name": "maxFlameCounterFrom", + "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": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "group_id" + ] + } + }, + { + "id": 2, + "references": [], + "type": "table", + "data": { + "name": "media_files", + "was_declared_in_moor": false, + "columns": [ + { + "name": "media_id", + "getter_name": "mediaId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MediaType.values)", + "dart_type_name": "MediaType" + } + }, + { + "name": "upload_state", + "getter_name": "uploadState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(UploadState.values)", + "dart_type_name": "UploadState" + } + }, + { + "name": "download_state", + "getter_name": "downloadState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(DownloadState.values)", + "dart_type_name": "DownloadState" + } + }, + { + "name": "requires_authentication", + "getter_name": "requiresAuthentication", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"requires_authentication\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"requires_authentication\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "stored", + "getter_name": "stored", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"stored\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"stored\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_draft_media", + "getter_name": "isDraftMedia", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_draft_media\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_draft_media\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pre_progressing_process", + "getter_name": "preProgressingProcess", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "reupload_requested_by", + "getter_name": "reuploadRequestedBy", + "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": "display_limit_in_milliseconds", + "getter_name": "displayLimitInMilliseconds", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "remove_audio", + "getter_name": "removeAudio", + "moor_type": "bool", + "nullable": true, + "customConstraints": null, + "defaultConstraints": "CHECK (\"remove_audio\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"remove_audio\" IN (0, 1))" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "download_token", + "getter_name": "downloadToken", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_key", + "getter_name": "encryptionKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_mac", + "getter_name": "encryptionMac", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_nonce", + "getter_name": "encryptionNonce", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "stored_file_hash", + "getter_name": "storedFileHash", + "moor_type": "blob", + "nullable": true, + "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": [ + "media_id" + ] + } + }, + { + "id": 3, + "references": [ + 1, + 0, + 2 + ], + "type": "table", + "data": { + "name": "messages", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_id", + "getter_name": "senderId", + "moor_type": "int", + "nullable": true, + "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "content", + "getter_name": "content", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "media_id", + "getter_name": "mediaId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "defaultConstraints": "REFERENCES media_files (media_id) ON DELETE SET NULL", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES media_files (media_id) ON DELETE SET NULL" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "media_files", + "column": "media_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "setNull" + } + } + ] + }, + { + "name": "additional_message_data", + "getter_name": "additionalMessageData", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "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": "media_reopened", + "getter_name": "mediaReopened", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"media_reopened\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"media_reopened\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "download_token", + "getter_name": "downloadToken", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quotes_message_id", + "getter_name": "quotesMessageId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted_from_sender", + "getter_name": "isDeletedFromSender", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted_from_sender\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted_from_sender\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "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": "opened_by_all", + "getter_name": "openedByAll", + "moor_type": "dateTime", + "nullable": true, + "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": [] + }, + { + "name": "modified_at", + "getter_name": "modifiedAt", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_user", + "getter_name": "ackByUser", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_server", + "getter_name": "ackByServer", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "message_id" + ] + } + }, + { + "id": 4, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "message_histories", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "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_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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": "content", + "getter_name": "content", + "moor_type": "string", + "nullable": true, + "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": [] + } + }, + { + "id": 5, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "reactions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "emoji", + "getter_name": "emoji", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_id", + "getter_name": "senderId", + "moor_type": "int", + "nullable": true, + "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": "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": [ + "message_id", + "sender_id", + "emoji" + ] + } + }, + { + "id": 6, + "references": [ + 1, + 0 + ], + "type": "table", + "data": { + "name": "group_members", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "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": "member_state", + "getter_name": "memberState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MemberState.values)", + "dart_type_name": "MemberState" + } + }, + { + "name": "group_public_key", + "getter_name": "groupPublicKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_chat_opened", + "getter_name": "lastChatOpened", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_type_indicator", + "getter_name": "lastTypeIndicator", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_message", + "getter_name": "lastMessage", + "moor_type": "dateTime", + "nullable": true, + "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": [ + "group_id", + "contact_id" + ] + } + }, + { + "id": 7, + "references": [ + 0, + 3 + ], + "type": "table", + "data": { + "name": "receipts", + "was_declared_in_moor": false, + "columns": [ + { + "name": "receipt_id", + "getter_name": "receiptId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "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": "string", + "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": "message", + "getter_name": "message", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "contact_will_sends_receipt", + "getter_name": "contactWillSendsReceipt", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"contact_will_sends_receipt\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"contact_will_sends_receipt\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "will_be_retried_by_media_upload", + "getter_name": "willBeRetriedByMediaUpload", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"will_be_retried_by_media_upload\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"will_be_retried_by_media_upload\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mark_for_retry", + "getter_name": "markForRetry", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mark_for_retry_after_accepted", + "getter_name": "markForRetryAfterAccepted", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_server_at", + "getter_name": "ackByServerAt", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "retry_count", + "getter_name": "retryCount", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_retry", + "getter_name": "lastRetry", + "moor_type": "dateTime", + "nullable": true, + "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": [ + "receipt_id" + ] + } + }, + { + "id": 8, + "references": [], + "type": "table", + "data": { + "name": "received_receipts", + "was_declared_in_moor": false, + "columns": [ + { + "name": "receipt_id", + "getter_name": "receiptId", + "moor_type": "string", + "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": [ + "receipt_id" + ] + } + }, + { + "id": 9, + "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": 10, + "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": 11, + "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": 12, + "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": 13, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "message_actions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MessageActionType.values)", + "dart_type_name": "MessageActionType" + } + }, + { + "name": "action_at", + "getter_name": "actionAt", + "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": [ + "message_id", + "contact_id", + "type" + ] + } + }, + { + "id": 14, + "references": [ + 1, + 0 + ], + "type": "table", + "data": { + "name": "group_histories", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_history_id", + "getter_name": "groupHistoryId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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": "affected_contact_id", + "getter_name": "affectedContactId", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "old_group_name", + "getter_name": "oldGroupName", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "new_group_name", + "getter_name": "newGroupName", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "new_delete_messages_after_milliseconds", + "getter_name": "newDeleteMessagesAfterMilliseconds", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(GroupActionType.values)", + "dart_type_name": "GroupActionType" + } + }, + { + "name": "action_at", + "getter_name": "actionAt", + "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": [ + "group_history_id" + ] + } + }, + { + "id": 15, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "key_verifications", + "was_declared_in_moor": false, + "columns": [ + { + "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(VerificationType.values)", + "dart_type_name": "VerificationType" + } + }, + { + "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": 16, + "references": [], + "type": "table", + "data": { + "name": "verification_tokens", + "was_declared_in_moor": false, + "columns": [ + { + "name": "token_id", + "getter_name": "tokenId", + "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": "token", + "getter_name": "token", + "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": [] + } + }, + { + "id": 17, + "references": [], + "type": "table", + "data": { + "name": "user_discovery_announced_users", + "was_declared_in_moor": false, + "columns": [ + { + "name": "announced_user_id", + "getter_name": "announcedUserId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "announced_public_key", + "getter_name": "announcedPublicKey", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_id", + "getter_name": "publicId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "UNIQUE", + "dialectAwareDefaultConstraints": { + "sqlite": "UNIQUE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + "unique" + ] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "announced_user_id" + ] + } + }, + { + "id": 18, + "references": [ + 17, + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_user_relations", + "was_declared_in_moor": false, + "columns": [ + { + "name": "announced_user_id", + "getter_name": "announcedUserId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "user_discovery_announced_users", + "column": "announced_user_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "from_contact_id", + "getter_name": "fromContactId", + "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": "public_key_verified_timestamp", + "getter_name": "publicKeyVerifiedTimestamp", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "announced_user_id", + "from_contact_id" + ] + } + }, + { + "id": 19, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_other_promotions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "from_contact_id", + "getter_name": "fromContactId", + "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": "promotion_id", + "getter_name": "promotionId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_id", + "getter_name": "publicId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "threshold", + "getter_name": "threshold", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "announcement_share", + "getter_name": "announcementShare", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_key_verified_timestamp", + "getter_name": "publicKeyVerifiedTimestamp", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "from_contact_id", + "promotion_id" + ] + } + }, + { + "id": 20, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_own_promotions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "version_id", + "getter_name": "versionId", + "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": "promotion", + "getter_name": "promotion", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [] + } + }, + { + "id": 21, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_shares", + "was_declared_in_moor": false, + "columns": [ + { + "name": "share_id", + "getter_name": "shareId", + "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": "share", + "getter_name": "share", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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" + } + } + ] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [] + } + } + ], + "fixed_sql": [ + { + "name": "contacts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"contacts\" (\"user_id\" INTEGER NOT NULL, \"username\" TEXT NOT NULL, \"display_name\" TEXT NULL, \"nick_name\" TEXT NULL, \"avatar_svg_compressed\" BLOB NULL, \"sender_profile_counter\" INTEGER NOT NULL DEFAULT 0, \"accepted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"accepted\" IN (0, 1)), \"deleted_by_user\" INTEGER NOT NULL DEFAULT 0 CHECK (\"deleted_by_user\" IN (0, 1)), \"requested\" INTEGER NOT NULL DEFAULT 0 CHECK (\"requested\" IN (0, 1)), \"blocked\" INTEGER NOT NULL DEFAULT 0 CHECK (\"blocked\" IN (0, 1)), \"verified\" INTEGER NOT NULL DEFAULT 0 CHECK (\"verified\" IN (0, 1)), \"account_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"account_deleted\" IN (0, 1)), \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"user_discovery_version\" BLOB NULL, PRIMARY KEY (\"user_id\"));" + } + ] + }, + { + "name": "groups", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"groups\" (\"group_id\" TEXT NOT NULL, \"is_group_admin\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_group_admin\" IN (0, 1)), \"is_direct_chat\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_direct_chat\" IN (0, 1)), \"pinned\" INTEGER NOT NULL DEFAULT 0 CHECK (\"pinned\" IN (0, 1)), \"archived\" INTEGER NOT NULL DEFAULT 0 CHECK (\"archived\" IN (0, 1)), \"joined_group\" INTEGER NOT NULL DEFAULT 0 CHECK (\"joined_group\" IN (0, 1)), \"left_group\" INTEGER NOT NULL DEFAULT 0 CHECK (\"left_group\" IN (0, 1)), \"deleted_content\" INTEGER NOT NULL DEFAULT 0 CHECK (\"deleted_content\" IN (0, 1)), \"state_version_id\" INTEGER NOT NULL DEFAULT 0, \"state_encryption_key\" BLOB NULL, \"my_group_private_key\" BLOB NULL, \"group_name\" TEXT NOT NULL, \"draft_message\" TEXT NULL, \"total_media_counter\" INTEGER NOT NULL DEFAULT 0, \"also_best_friend\" INTEGER NOT NULL DEFAULT 0 CHECK (\"also_best_friend\" IN (0, 1)), \"delete_messages_after_milliseconds\" INTEGER NOT NULL DEFAULT 86400000, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"last_message_send\" INTEGER NULL, \"last_message_received\" INTEGER NULL, \"last_flame_counter_change\" INTEGER NULL, \"last_flame_sync\" INTEGER NULL, \"flame_counter\" INTEGER NOT NULL DEFAULT 0, \"max_flame_counter\" INTEGER NOT NULL DEFAULT 0, \"max_flame_counter_from\" INTEGER NULL, \"last_message_exchange\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_id\"));" + } + ] + }, + { + "name": "media_files", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"media_files\" (\"media_id\" TEXT NOT NULL, \"type\" TEXT NOT NULL, \"upload_state\" TEXT NULL, \"download_state\" TEXT NULL, \"requires_authentication\" INTEGER NOT NULL DEFAULT 0 CHECK (\"requires_authentication\" IN (0, 1)), \"stored\" INTEGER NOT NULL DEFAULT 0 CHECK (\"stored\" IN (0, 1)), \"is_draft_media\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_draft_media\" IN (0, 1)), \"pre_progressing_process\" INTEGER NULL, \"reupload_requested_by\" TEXT NULL, \"display_limit_in_milliseconds\" INTEGER NULL, \"remove_audio\" INTEGER NULL CHECK (\"remove_audio\" IN (0, 1)), \"download_token\" BLOB NULL, \"encryption_key\" BLOB NULL, \"encryption_mac\" BLOB NULL, \"encryption_nonce\" BLOB NULL, \"stored_file_hash\" BLOB NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"media_id\"));" + } + ] + }, + { + "name": "messages", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"messages\" (\"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"message_id\" TEXT NOT NULL, \"sender_id\" INTEGER NULL REFERENCES contacts (user_id), \"type\" TEXT NOT NULL, \"content\" TEXT NULL, \"media_id\" TEXT NULL REFERENCES media_files (media_id) ON DELETE SET NULL, \"additional_message_data\" BLOB NULL, \"media_stored\" INTEGER NOT NULL DEFAULT 0 CHECK (\"media_stored\" IN (0, 1)), \"media_reopened\" INTEGER NOT NULL DEFAULT 0 CHECK (\"media_reopened\" IN (0, 1)), \"download_token\" BLOB NULL, \"quotes_message_id\" TEXT NULL, \"is_deleted_from_sender\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted_from_sender\" IN (0, 1)), \"opened_at\" INTEGER NULL, \"opened_by_all\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"modified_at\" INTEGER NULL, \"ack_by_user\" INTEGER NULL, \"ack_by_server\" INTEGER NULL, PRIMARY KEY (\"message_id\"));" + } + ] + }, + { + "name": "message_histories", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"message_histories\" (\"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"content\" TEXT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)));" + } + ] + }, + { + "name": "reactions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"reactions\" (\"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"emoji\" TEXT NOT NULL, \"sender_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"message_id\", \"sender_id\", \"emoji\"));" + } + ] + }, + { + "name": "group_members", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"group_members\" (\"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id), \"member_state\" TEXT NULL, \"group_public_key\" BLOB NULL, \"last_chat_opened\" INTEGER NULL, \"last_type_indicator\" INTEGER NULL, \"last_message\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_id\", \"contact_id\"));" + } + ] + }, + { + "name": "receipts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"receipts\" (\"receipt_id\" TEXT NOT NULL, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"message_id\" TEXT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"message\" BLOB NOT NULL, \"contact_will_sends_receipt\" INTEGER NOT NULL DEFAULT 1 CHECK (\"contact_will_sends_receipt\" IN (0, 1)), \"will_be_retried_by_media_upload\" INTEGER NOT NULL DEFAULT 0 CHECK (\"will_be_retried_by_media_upload\" IN (0, 1)), \"mark_for_retry\" INTEGER NULL, \"mark_for_retry_after_accepted\" INTEGER NULL, \"ack_by_server_at\" INTEGER NULL, \"retry_count\" INTEGER NOT NULL DEFAULT 0, \"last_retry\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"receipt_id\"));" + } + ] + }, + { + "name": "received_receipts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"received_receipts\" (\"receipt_id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"receipt_id\"));" + } + ] + }, + { + "name": "signal_identity_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_identity_key_stores\" (\"device_id\" INTEGER NOT NULL, \"name\" TEXT NOT NULL, \"identity_key\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"device_id\", \"name\"));" + } + ] + }, + { + "name": "signal_pre_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_pre_key_stores\" (\"pre_key_id\" INTEGER NOT NULL, \"pre_key\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"pre_key_id\"));" + } + ] + }, + { + "name": "signal_sender_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_sender_key_stores\" (\"sender_key_name\" TEXT NOT NULL, \"sender_key\" BLOB NOT NULL, PRIMARY KEY (\"sender_key_name\"));" + } + ] + }, + { + "name": "signal_session_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_session_stores\" (\"device_id\" INTEGER NOT NULL, \"name\" TEXT NOT NULL, \"session_record\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"device_id\", \"name\"));" + } + ] + }, + { + "name": "message_actions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"message_actions\" (\"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"type\" TEXT NOT NULL, \"action_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"message_id\", \"contact_id\", \"type\"));" + } + ] + }, + { + "name": "group_histories", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"group_histories\" (\"group_history_id\" TEXT NOT NULL, \"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id), \"affected_contact_id\" INTEGER NULL, \"old_group_name\" TEXT NULL, \"new_group_name\" TEXT NULL, \"new_delete_messages_after_milliseconds\" INTEGER NULL, \"type\" TEXT NOT NULL, \"action_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_history_id\"));" + } + ] + }, + { + "name": "key_verifications", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"key_verifications\" (\"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"type\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"contact_id\"));" + } + ] + }, + { + "name": "verification_tokens", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"verification_tokens\" (\"token_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"token\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)));" + } + ] + }, + { + "name": "user_discovery_announced_users", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_announced_users\" (\"announced_user_id\" INTEGER NOT NULL, \"announced_public_key\" BLOB NOT NULL, \"public_id\" INTEGER NOT NULL UNIQUE, PRIMARY KEY (\"announced_user_id\"));" + } + ] + }, + { + "name": "user_discovery_user_relations", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_user_relations\" (\"announced_user_id\" INTEGER NOT NULL REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE, \"from_contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"public_key_verified_timestamp\" INTEGER NULL, PRIMARY KEY (\"announced_user_id\", \"from_contact_id\"));" + } + ] + }, + { + "name": "user_discovery_other_promotions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_other_promotions\" (\"from_contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"promotion_id\" INTEGER NOT NULL, \"public_id\" INTEGER NOT NULL, \"threshold\" INTEGER NOT NULL, \"announcement_share\" BLOB NOT NULL, \"public_key_verified_timestamp\" INTEGER NULL, PRIMARY KEY (\"from_contact_id\", \"promotion_id\"));" + } + ] + }, + { + "name": "user_discovery_own_promotions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_own_promotions\" (\"version_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"promotion\" BLOB NOT NULL);" + } + ] + }, + { + "name": "user_discovery_shares", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_shares\" (\"share_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"share\" BLOB NOT NULL, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE);" + } + ] + } + ] +} \ No newline at end of file diff --git a/lib/src/database/tables/contacts.table.dart b/lib/src/database/tables/contacts.table.dart index a427fad5..c66cf61c 100644 --- a/lib/src/database/tables/contacts.table.dart +++ b/lib/src/database/tables/contacts.table.dart @@ -1,5 +1,6 @@ import 'package:drift/drift.dart'; +@DataClassName('Contact') class Contacts extends Table { IntColumn get userId => integer()(); @@ -22,6 +23,37 @@ class Contacts extends Table { DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); + // contact_versions: HashMap>, + BlobColumn get userDiscoveryVersion => blob().nullable()(); + @override Set get primaryKey => {userId}; } + +enum VerificationType { + qr, + link, +} + +@DataClassName('KeyVerification') +class KeyVerifications extends Table { + IntColumn get contactId => integer().references( + Contacts, + #userId, + onDelete: KeyAction.cascade, + )(); + + TextColumn get type => textEnum()(); + + DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); + + @override + Set get primaryKey => {contactId}; +} + +@DataClassName('VerificationToken') +class VerificationTokens extends Table { + IntColumn get tokenId => integer().autoIncrement()(); + BlobColumn get token => blob()(); + DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); +} diff --git a/lib/src/database/tables/user_discovery.table.dart b/lib/src/database/tables/user_discovery.table.dart index 68432a59..5239dc5b 100644 --- a/lib/src/database/tables/user_discovery.table.dart +++ b/lib/src/database/tables/user_discovery.table.dart @@ -1,12 +1,39 @@ import 'package:drift/drift.dart'; import 'package:twonly/src/database/tables/contacts.table.dart'; -// contact_versions: HashMap>, -// -> New Column in Contacts - // config: Option>, // announced_users: HashMap)>>, +@DataClassName('UserDiscoveryAnnouncedUser') +class UserDiscoveryAnnouncedUsers extends Table { + IntColumn get announcedUserId => integer()(); + BlobColumn get announcedPublicKey => blob()(); + IntColumn get publicId => integer().unique()(); + + @override + Set get primaryKey => {announcedUserId}; +} + +// announced_users: HashMap)>>, +@DataClassName('UserDiscoveryUserRelation') +class UserDiscoveryUserRelations extends Table { + IntColumn get announcedUserId => integer().references( + UserDiscoveryAnnouncedUsers, + #announcedUserId, + onDelete: KeyAction.cascade, + )(); + + IntColumn get fromContactId => integer().references( + Contacts, + #userId, + onDelete: KeyAction.cascade, + )(); + + DateTimeColumn get publicKeyVerifiedTimestamp => dateTime().nullable()(); + + @override + Set get primaryKey => {announcedUserId, fromContactId}; +} // own_promotions: Vec<(UserID, Vec)>, @DataClassName('UserDiscoveryOwnPromotion') @@ -17,21 +44,26 @@ class UserDiscoveryOwnPromotions extends Table { #userId, onDelete: KeyAction.cascade, )(); - BlobColumn get promotion => blob()(); } // other_promotions: Vec, @DataClassName('UserDiscoveryOtherPromotion') class UserDiscoveryOtherPromotions extends Table { - IntColumn get versionId => integer().autoIncrement()(); - IntColumn get contactId => integer().references( + IntColumn get fromContactId => integer().references( Contacts, #userId, onDelete: KeyAction.cascade, )(); - BlobColumn get promotion => blob()(); + IntColumn get promotionId => integer()(); + IntColumn get publicId => integer()(); + IntColumn get threshold => integer()(); + BlobColumn get announcementShare => blob()(); + DateTimeColumn get publicKeyVerifiedTimestamp => dateTime().nullable()(); + + @override + Set get primaryKey => {fromContactId, promotionId}; } // unused_shares: Vec>, diff --git a/lib/src/database/twonly.db.dart b/lib/src/database/twonly.db.dart index 1fe3f517..bf28d801 100644 --- a/lib/src/database/twonly.db.dart +++ b/lib/src/database/twonly.db.dart @@ -9,6 +9,7 @@ import 'package:twonly/src/database/daos/mediafiles.dao.dart'; import 'package:twonly/src/database/daos/messages.dao.dart'; import 'package:twonly/src/database/daos/reactions.dao.dart'; import 'package:twonly/src/database/daos/receipts.dao.dart'; +import 'package:twonly/src/database/daos/user_discovery.dao.dart'; import 'package:twonly/src/database/tables/contacts.table.dart'; import 'package:twonly/src/database/tables/groups.table.dart'; import 'package:twonly/src/database/tables/mediafiles.table.dart'; @@ -19,6 +20,7 @@ import 'package:twonly/src/database/tables/signal_identity_key_store.table.dart' import 'package:twonly/src/database/tables/signal_pre_key_store.table.dart'; import 'package:twonly/src/database/tables/signal_sender_key_store.table.dart'; import 'package:twonly/src/database/tables/signal_session_store.table.dart'; +import 'package:twonly/src/database/tables/user_discovery.table.dart'; import 'package:twonly/src/database/twonly.db.steps.dart'; import 'package:twonly/src/utils/log.dart'; @@ -42,6 +44,13 @@ part 'twonly.db.g.dart'; SignalSessionStores, MessageActions, GroupHistories, + KeyVerifications, + VerificationTokens, + UserDiscoveryAnnouncedUsers, + UserDiscoveryUserRelations, + UserDiscoveryOtherPromotions, + UserDiscoveryOwnPromotions, + UserDiscoveryShares, ], daos: [ MessagesDao, @@ -50,6 +59,7 @@ part 'twonly.db.g.dart'; GroupsDao, ReactionsDao, MediaFilesDao, + UserDiscoveryDao, ], ) class TwonlyDB extends _$TwonlyDB { @@ -62,7 +72,7 @@ class TwonlyDB extends _$TwonlyDB { TwonlyDB.forTesting(DatabaseConnection super.connection); @override - int get schemaVersion => 11; + int get schemaVersion => 12; static QueryExecutor _openConnection() { return driftDatabase( @@ -158,6 +168,19 @@ class TwonlyDB extends _$TwonlyDB { schema.groupMembers.lastTypeIndicator, ); }, + from11To12: (m, schema) async { + await m.createTable(schema.verificationTokens); + await m.createTable(schema.keyVerifications); + await m.createTable(schema.userDiscoveryAnnouncedUsers); + await m.createTable(schema.userDiscoveryOwnPromotions); + await m.createTable(schema.userDiscoveryOtherPromotions); + await m.createTable(schema.userDiscoveryShares); + await m.createTable(schema.userDiscoveryUserRelations); + await m.addColumn( + schema.contacts, + schema.contacts.userDiscoveryVersion, + ); + }, )(m, from, to); }, ); diff --git a/lib/src/database/twonly.db.g.dart b/lib/src/database/twonly.db.g.dart index 0e860ed5..44ea5d1e 100644 --- a/lib/src/database/twonly.db.g.dart +++ b/lib/src/database/twonly.db.g.dart @@ -174,6 +174,17 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { requiredDuringInsert: false, defaultValue: currentDateAndTime, ); + static const VerificationMeta _userDiscoveryVersionMeta = + const VerificationMeta('userDiscoveryVersion'); + @override + late final GeneratedColumn userDiscoveryVersion = + GeneratedColumn( + 'user_discovery_version', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + ); @override List get $columns => [ userId, @@ -189,6 +200,7 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { verified, accountDeleted, createdAt, + userDiscoveryVersion, ]; @override String get aliasedName => _alias ?? actualTableName; @@ -297,6 +309,15 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), ); } + if (data.containsKey('user_discovery_version')) { + context.handle( + _userDiscoveryVersionMeta, + userDiscoveryVersion.isAcceptableOrUnknown( + data['user_discovery_version']!, + _userDiscoveryVersionMeta, + ), + ); + } return context; } @@ -358,6 +379,10 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { DriftSqlType.dateTime, data['${effectivePrefix}created_at'], )!, + userDiscoveryVersion: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}user_discovery_version'], + ), ); } @@ -381,6 +406,7 @@ class Contact extends DataClass implements Insertable { final bool verified; final bool accountDeleted; final DateTime createdAt; + final Uint8List? userDiscoveryVersion; const Contact({ required this.userId, required this.username, @@ -395,6 +421,7 @@ class Contact extends DataClass implements Insertable { required this.verified, required this.accountDeleted, required this.createdAt, + this.userDiscoveryVersion, }); @override Map toColumns(bool nullToAbsent) { @@ -418,6 +445,9 @@ class Contact extends DataClass implements Insertable { map['verified'] = Variable(verified); map['account_deleted'] = Variable(accountDeleted); map['created_at'] = Variable(createdAt); + if (!nullToAbsent || userDiscoveryVersion != null) { + map['user_discovery_version'] = Variable(userDiscoveryVersion); + } return map; } @@ -442,6 +472,9 @@ class Contact extends DataClass implements Insertable { verified: Value(verified), accountDeleted: Value(accountDeleted), createdAt: Value(createdAt), + userDiscoveryVersion: userDiscoveryVersion == null && nullToAbsent + ? const Value.absent() + : Value(userDiscoveryVersion), ); } @@ -468,6 +501,9 @@ class Contact extends DataClass implements Insertable { verified: serializer.fromJson(json['verified']), accountDeleted: serializer.fromJson(json['accountDeleted']), createdAt: serializer.fromJson(json['createdAt']), + userDiscoveryVersion: serializer.fromJson( + json['userDiscoveryVersion'], + ), ); } @override @@ -487,6 +523,9 @@ class Contact extends DataClass implements Insertable { 'verified': serializer.toJson(verified), 'accountDeleted': serializer.toJson(accountDeleted), 'createdAt': serializer.toJson(createdAt), + 'userDiscoveryVersion': serializer.toJson( + userDiscoveryVersion, + ), }; } @@ -504,6 +543,7 @@ class Contact extends DataClass implements Insertable { bool? verified, bool? accountDeleted, DateTime? createdAt, + Value userDiscoveryVersion = const Value.absent(), }) => Contact( userId: userId ?? this.userId, username: username ?? this.username, @@ -520,6 +560,9 @@ class Contact extends DataClass implements Insertable { verified: verified ?? this.verified, accountDeleted: accountDeleted ?? this.accountDeleted, createdAt: createdAt ?? this.createdAt, + userDiscoveryVersion: userDiscoveryVersion.present + ? userDiscoveryVersion.value + : this.userDiscoveryVersion, ); Contact copyWithCompanion(ContactsCompanion data) { return Contact( @@ -546,6 +589,9 @@ class Contact extends DataClass implements Insertable { ? data.accountDeleted.value : this.accountDeleted, createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + userDiscoveryVersion: data.userDiscoveryVersion.present + ? data.userDiscoveryVersion.value + : this.userDiscoveryVersion, ); } @@ -564,7 +610,8 @@ class Contact extends DataClass implements Insertable { ..write('blocked: $blocked, ') ..write('verified: $verified, ') ..write('accountDeleted: $accountDeleted, ') - ..write('createdAt: $createdAt') + ..write('createdAt: $createdAt, ') + ..write('userDiscoveryVersion: $userDiscoveryVersion') ..write(')')) .toString(); } @@ -584,6 +631,7 @@ class Contact extends DataClass implements Insertable { verified, accountDeleted, createdAt, + $driftBlobEquality.hash(userDiscoveryVersion), ); @override bool operator ==(Object other) => @@ -604,7 +652,11 @@ class Contact extends DataClass implements Insertable { other.blocked == this.blocked && other.verified == this.verified && other.accountDeleted == this.accountDeleted && - other.createdAt == this.createdAt); + other.createdAt == this.createdAt && + $driftBlobEquality.equals( + other.userDiscoveryVersion, + this.userDiscoveryVersion, + )); } class ContactsCompanion extends UpdateCompanion { @@ -621,6 +673,7 @@ class ContactsCompanion extends UpdateCompanion { final Value verified; final Value accountDeleted; final Value createdAt; + final Value userDiscoveryVersion; const ContactsCompanion({ this.userId = const Value.absent(), this.username = const Value.absent(), @@ -635,6 +688,7 @@ class ContactsCompanion extends UpdateCompanion { this.verified = const Value.absent(), this.accountDeleted = const Value.absent(), this.createdAt = const Value.absent(), + this.userDiscoveryVersion = const Value.absent(), }); ContactsCompanion.insert({ this.userId = const Value.absent(), @@ -650,6 +704,7 @@ class ContactsCompanion extends UpdateCompanion { this.verified = const Value.absent(), this.accountDeleted = const Value.absent(), this.createdAt = const Value.absent(), + this.userDiscoveryVersion = const Value.absent(), }) : username = Value(username); static Insertable custom({ Expression? userId, @@ -665,6 +720,7 @@ class ContactsCompanion extends UpdateCompanion { Expression? verified, Expression? accountDeleted, Expression? createdAt, + Expression? userDiscoveryVersion, }) { return RawValuesInsertable({ if (userId != null) 'user_id': userId, @@ -682,6 +738,8 @@ class ContactsCompanion extends UpdateCompanion { if (verified != null) 'verified': verified, if (accountDeleted != null) 'account_deleted': accountDeleted, if (createdAt != null) 'created_at': createdAt, + if (userDiscoveryVersion != null) + 'user_discovery_version': userDiscoveryVersion, }); } @@ -699,6 +757,7 @@ class ContactsCompanion extends UpdateCompanion { Value? verified, Value? accountDeleted, Value? createdAt, + Value? userDiscoveryVersion, }) { return ContactsCompanion( userId: userId ?? this.userId, @@ -714,6 +773,7 @@ class ContactsCompanion extends UpdateCompanion { verified: verified ?? this.verified, accountDeleted: accountDeleted ?? this.accountDeleted, createdAt: createdAt ?? this.createdAt, + userDiscoveryVersion: userDiscoveryVersion ?? this.userDiscoveryVersion, ); } @@ -761,6 +821,11 @@ class ContactsCompanion extends UpdateCompanion { if (createdAt.present) { map['created_at'] = Variable(createdAt.value); } + if (userDiscoveryVersion.present) { + map['user_discovery_version'] = Variable( + userDiscoveryVersion.value, + ); + } return map; } @@ -779,7 +844,8 @@ class ContactsCompanion extends UpdateCompanion { ..write('blocked: $blocked, ') ..write('verified: $verified, ') ..write('accountDeleted: $accountDeleted, ') - ..write('createdAt: $createdAt') + ..write('createdAt: $createdAt, ') + ..write('userDiscoveryVersion: $userDiscoveryVersion') ..write(')')) .toString(); } @@ -8805,6 +8871,2143 @@ class GroupHistoriesCompanion extends UpdateCompanion { } } +class $KeyVerificationsTable extends KeyVerifications + with TableInfo<$KeyVerificationsTable, KeyVerification> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $KeyVerificationsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _contactIdMeta = const VerificationMeta( + 'contactId', + ); + @override + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES contacts (user_id) ON DELETE CASCADE', + ), + ); + @override + late final GeneratedColumnWithTypeConverter type = + GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ).withConverter($KeyVerificationsTable.$convertertype); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: currentDateAndTime, + ); + @override + List get $columns => [contactId, type, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'key_verifications'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('contact_id')) { + context.handle( + _contactIdMeta, + contactId.isAcceptableOrUnknown(data['contact_id']!, _contactIdMeta), + ); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {contactId}; + @override + KeyVerification map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return KeyVerification( + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + type: $KeyVerificationsTable.$convertertype.fromSql( + attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + $KeyVerificationsTable createAlias(String alias) { + return $KeyVerificationsTable(attachedDatabase, alias); + } + + static JsonTypeConverter2 $convertertype = + const EnumNameConverter(VerificationType.values); +} + +class KeyVerification extends DataClass implements Insertable { + final int contactId; + final VerificationType type; + final DateTime createdAt; + const KeyVerification({ + required this.contactId, + required this.type, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['contact_id'] = Variable(contactId); + { + map['type'] = Variable( + $KeyVerificationsTable.$convertertype.toSql(type), + ); + } + map['created_at'] = Variable(createdAt); + return map; + } + + KeyVerificationsCompanion toCompanion(bool nullToAbsent) { + return KeyVerificationsCompanion( + contactId: Value(contactId), + type: Value(type), + createdAt: Value(createdAt), + ); + } + + factory KeyVerification.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return KeyVerification( + contactId: serializer.fromJson(json['contactId']), + type: $KeyVerificationsTable.$convertertype.fromJson( + serializer.fromJson(json['type']), + ), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'contactId': serializer.toJson(contactId), + 'type': serializer.toJson( + $KeyVerificationsTable.$convertertype.toJson(type), + ), + 'createdAt': serializer.toJson(createdAt), + }; + } + + KeyVerification copyWith({ + int? contactId, + VerificationType? type, + DateTime? createdAt, + }) => KeyVerification( + contactId: contactId ?? this.contactId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + KeyVerification copyWithCompanion(KeyVerificationsCompanion data) { + return KeyVerification( + contactId: data.contactId.present ? data.contactId.value : this.contactId, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('KeyVerification(') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(contactId, type, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is KeyVerification && + other.contactId == this.contactId && + other.type == this.type && + other.createdAt == this.createdAt); +} + +class KeyVerificationsCompanion extends UpdateCompanion { + final Value contactId; + final Value type; + final Value createdAt; + const KeyVerificationsCompanion({ + this.contactId = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + }); + KeyVerificationsCompanion.insert({ + this.contactId = const Value.absent(), + required VerificationType type, + this.createdAt = const Value.absent(), + }) : type = Value(type); + static Insertable custom({ + Expression? contactId, + Expression? type, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (contactId != null) 'contact_id': contactId, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + }); + } + + KeyVerificationsCompanion copyWith({ + Value? contactId, + Value? type, + Value? createdAt, + }) { + return KeyVerificationsCompanion( + contactId: contactId ?? this.contactId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (type.present) { + map['type'] = Variable( + $KeyVerificationsTable.$convertertype.toSql(type.value), + ); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('KeyVerificationsCompanion(') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class $VerificationTokensTable extends VerificationTokens + with TableInfo<$VerificationTokensTable, VerificationToken> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $VerificationTokensTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _tokenIdMeta = const VerificationMeta( + 'tokenId', + ); + @override + late final GeneratedColumn tokenId = GeneratedColumn( + 'token_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const VerificationMeta _tokenMeta = const VerificationMeta('token'); + @override + late final GeneratedColumn token = GeneratedColumn( + 'token', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: currentDateAndTime, + ); + @override + List get $columns => [tokenId, token, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'verification_tokens'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('token_id')) { + context.handle( + _tokenIdMeta, + tokenId.isAcceptableOrUnknown(data['token_id']!, _tokenIdMeta), + ); + } + if (data.containsKey('token')) { + context.handle( + _tokenMeta, + token.isAcceptableOrUnknown(data['token']!, _tokenMeta), + ); + } else if (isInserting) { + context.missing(_tokenMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {tokenId}; + @override + VerificationToken map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return VerificationToken( + tokenId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}token_id'], + )!, + token: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}token'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + $VerificationTokensTable createAlias(String alias) { + return $VerificationTokensTable(attachedDatabase, alias); + } +} + +class VerificationToken extends DataClass + implements Insertable { + final int tokenId; + final Uint8List token; + final DateTime createdAt; + const VerificationToken({ + required this.tokenId, + required this.token, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['token_id'] = Variable(tokenId); + map['token'] = Variable(token); + map['created_at'] = Variable(createdAt); + return map; + } + + VerificationTokensCompanion toCompanion(bool nullToAbsent) { + return VerificationTokensCompanion( + tokenId: Value(tokenId), + token: Value(token), + createdAt: Value(createdAt), + ); + } + + factory VerificationToken.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return VerificationToken( + tokenId: serializer.fromJson(json['tokenId']), + token: serializer.fromJson(json['token']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'tokenId': serializer.toJson(tokenId), + 'token': serializer.toJson(token), + 'createdAt': serializer.toJson(createdAt), + }; + } + + VerificationToken copyWith({ + int? tokenId, + Uint8List? token, + DateTime? createdAt, + }) => VerificationToken( + tokenId: tokenId ?? this.tokenId, + token: token ?? this.token, + createdAt: createdAt ?? this.createdAt, + ); + VerificationToken copyWithCompanion(VerificationTokensCompanion data) { + return VerificationToken( + tokenId: data.tokenId.present ? data.tokenId.value : this.tokenId, + token: data.token.present ? data.token.value : this.token, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('VerificationToken(') + ..write('tokenId: $tokenId, ') + ..write('token: $token, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(tokenId, $driftBlobEquality.hash(token), createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is VerificationToken && + other.tokenId == this.tokenId && + $driftBlobEquality.equals(other.token, this.token) && + other.createdAt == this.createdAt); +} + +class VerificationTokensCompanion extends UpdateCompanion { + final Value tokenId; + final Value token; + final Value createdAt; + const VerificationTokensCompanion({ + this.tokenId = const Value.absent(), + this.token = const Value.absent(), + this.createdAt = const Value.absent(), + }); + VerificationTokensCompanion.insert({ + this.tokenId = const Value.absent(), + required Uint8List token, + this.createdAt = const Value.absent(), + }) : token = Value(token); + static Insertable custom({ + Expression? tokenId, + Expression? token, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (tokenId != null) 'token_id': tokenId, + if (token != null) 'token': token, + if (createdAt != null) 'created_at': createdAt, + }); + } + + VerificationTokensCompanion copyWith({ + Value? tokenId, + Value? token, + Value? createdAt, + }) { + return VerificationTokensCompanion( + tokenId: tokenId ?? this.tokenId, + token: token ?? this.token, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (tokenId.present) { + map['token_id'] = Variable(tokenId.value); + } + if (token.present) { + map['token'] = Variable(token.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('VerificationTokensCompanion(') + ..write('tokenId: $tokenId, ') + ..write('token: $token, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class $UserDiscoveryAnnouncedUsersTable extends UserDiscoveryAnnouncedUsers + with + TableInfo< + $UserDiscoveryAnnouncedUsersTable, + UserDiscoveryAnnouncedUser + > { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $UserDiscoveryAnnouncedUsersTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _announcedUserIdMeta = const VerificationMeta( + 'announcedUserId', + ); + @override + late final GeneratedColumn announcedUserId = GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + static const VerificationMeta _announcedPublicKeyMeta = + const VerificationMeta('announcedPublicKey'); + @override + late final GeneratedColumn announcedPublicKey = + GeneratedColumn( + 'announced_public_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + static const VerificationMeta _publicIdMeta = const VerificationMeta( + 'publicId', + ); + @override + late final GeneratedColumn publicId = GeneratedColumn( + 'public_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways('UNIQUE'), + ); + @override + List get $columns => [ + announcedUserId, + announcedPublicKey, + publicId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_announced_users'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('announced_user_id')) { + context.handle( + _announcedUserIdMeta, + announcedUserId.isAcceptableOrUnknown( + data['announced_user_id']!, + _announcedUserIdMeta, + ), + ); + } + if (data.containsKey('announced_public_key')) { + context.handle( + _announcedPublicKeyMeta, + announcedPublicKey.isAcceptableOrUnknown( + data['announced_public_key']!, + _announcedPublicKeyMeta, + ), + ); + } else if (isInserting) { + context.missing(_announcedPublicKeyMeta); + } + if (data.containsKey('public_id')) { + context.handle( + _publicIdMeta, + publicId.isAcceptableOrUnknown(data['public_id']!, _publicIdMeta), + ); + } else if (isInserting) { + context.missing(_publicIdMeta); + } + return context; + } + + @override + Set get $primaryKey => {announcedUserId}; + @override + UserDiscoveryAnnouncedUser map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryAnnouncedUser( + announcedUserId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}announced_user_id'], + )!, + announcedPublicKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}announced_public_key'], + )!, + publicId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_id'], + )!, + ); + } + + @override + $UserDiscoveryAnnouncedUsersTable createAlias(String alias) { + return $UserDiscoveryAnnouncedUsersTable(attachedDatabase, alias); + } +} + +class UserDiscoveryAnnouncedUser extends DataClass + implements Insertable { + final int announcedUserId; + final Uint8List announcedPublicKey; + final int publicId; + const UserDiscoveryAnnouncedUser({ + required this.announcedUserId, + required this.announcedPublicKey, + required this.publicId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['announced_user_id'] = Variable(announcedUserId); + map['announced_public_key'] = Variable(announcedPublicKey); + map['public_id'] = Variable(publicId); + return map; + } + + UserDiscoveryAnnouncedUsersCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: Value(announcedUserId), + announcedPublicKey: Value(announcedPublicKey), + publicId: Value(publicId), + ); + } + + factory UserDiscoveryAnnouncedUser.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryAnnouncedUser( + announcedUserId: serializer.fromJson(json['announcedUserId']), + announcedPublicKey: serializer.fromJson( + json['announcedPublicKey'], + ), + publicId: serializer.fromJson(json['publicId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'announcedUserId': serializer.toJson(announcedUserId), + 'announcedPublicKey': serializer.toJson(announcedPublicKey), + 'publicId': serializer.toJson(publicId), + }; + } + + UserDiscoveryAnnouncedUser copyWith({ + int? announcedUserId, + Uint8List? announcedPublicKey, + int? publicId, + }) => UserDiscoveryAnnouncedUser( + announcedUserId: announcedUserId ?? this.announcedUserId, + announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, + publicId: publicId ?? this.publicId, + ); + UserDiscoveryAnnouncedUser copyWithCompanion( + UserDiscoveryAnnouncedUsersCompanion data, + ) { + return UserDiscoveryAnnouncedUser( + announcedUserId: data.announcedUserId.present + ? data.announcedUserId.value + : this.announcedUserId, + announcedPublicKey: data.announcedPublicKey.present + ? data.announcedPublicKey.value + : this.announcedPublicKey, + publicId: data.publicId.present ? data.publicId.value : this.publicId, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryAnnouncedUser(') + ..write('announcedUserId: $announcedUserId, ') + ..write('announcedPublicKey: $announcedPublicKey, ') + ..write('publicId: $publicId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + announcedUserId, + $driftBlobEquality.hash(announcedPublicKey), + publicId, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryAnnouncedUser && + other.announcedUserId == this.announcedUserId && + $driftBlobEquality.equals( + other.announcedPublicKey, + this.announcedPublicKey, + ) && + other.publicId == this.publicId); +} + +class UserDiscoveryAnnouncedUsersCompanion + extends UpdateCompanion { + final Value announcedUserId; + final Value announcedPublicKey; + final Value publicId; + const UserDiscoveryAnnouncedUsersCompanion({ + this.announcedUserId = const Value.absent(), + this.announcedPublicKey = const Value.absent(), + this.publicId = const Value.absent(), + }); + UserDiscoveryAnnouncedUsersCompanion.insert({ + this.announcedUserId = const Value.absent(), + required Uint8List announcedPublicKey, + required int publicId, + }) : announcedPublicKey = Value(announcedPublicKey), + publicId = Value(publicId); + static Insertable custom({ + Expression? announcedUserId, + Expression? announcedPublicKey, + Expression? publicId, + }) { + return RawValuesInsertable({ + if (announcedUserId != null) 'announced_user_id': announcedUserId, + if (announcedPublicKey != null) + 'announced_public_key': announcedPublicKey, + if (publicId != null) 'public_id': publicId, + }); + } + + UserDiscoveryAnnouncedUsersCompanion copyWith({ + Value? announcedUserId, + Value? announcedPublicKey, + Value? publicId, + }) { + return UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: announcedUserId ?? this.announcedUserId, + announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, + publicId: publicId ?? this.publicId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (announcedUserId.present) { + map['announced_user_id'] = Variable(announcedUserId.value); + } + if (announcedPublicKey.present) { + map['announced_public_key'] = Variable( + announcedPublicKey.value, + ); + } + if (publicId.present) { + map['public_id'] = Variable(publicId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryAnnouncedUsersCompanion(') + ..write('announcedUserId: $announcedUserId, ') + ..write('announcedPublicKey: $announcedPublicKey, ') + ..write('publicId: $publicId') + ..write(')')) + .toString(); + } +} + +class $UserDiscoveryUserRelationsTable extends UserDiscoveryUserRelations + with + TableInfo<$UserDiscoveryUserRelationsTable, UserDiscoveryUserRelation> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $UserDiscoveryUserRelationsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _announcedUserIdMeta = const VerificationMeta( + 'announcedUserId', + ); + @override + late final GeneratedColumn announcedUserId = GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE', + ), + ); + static const VerificationMeta _fromContactIdMeta = const VerificationMeta( + 'fromContactId', + ); + @override + late final GeneratedColumn fromContactId = GeneratedColumn( + 'from_contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES contacts (user_id) ON DELETE CASCADE', + ), + ); + static const VerificationMeta _publicKeyVerifiedTimestampMeta = + const VerificationMeta('publicKeyVerifiedTimestamp'); + @override + late final GeneratedColumn publicKeyVerifiedTimestamp = + GeneratedColumn( + 'public_key_verified_timestamp', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + announcedUserId, + fromContactId, + publicKeyVerifiedTimestamp, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_user_relations'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('announced_user_id')) { + context.handle( + _announcedUserIdMeta, + announcedUserId.isAcceptableOrUnknown( + data['announced_user_id']!, + _announcedUserIdMeta, + ), + ); + } else if (isInserting) { + context.missing(_announcedUserIdMeta); + } + if (data.containsKey('from_contact_id')) { + context.handle( + _fromContactIdMeta, + fromContactId.isAcceptableOrUnknown( + data['from_contact_id']!, + _fromContactIdMeta, + ), + ); + } else if (isInserting) { + context.missing(_fromContactIdMeta); + } + if (data.containsKey('public_key_verified_timestamp')) { + context.handle( + _publicKeyVerifiedTimestampMeta, + publicKeyVerifiedTimestamp.isAcceptableOrUnknown( + data['public_key_verified_timestamp']!, + _publicKeyVerifiedTimestampMeta, + ), + ); + } + return context; + } + + @override + Set get $primaryKey => {announcedUserId, fromContactId}; + @override + UserDiscoveryUserRelation map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryUserRelation( + announcedUserId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}announced_user_id'], + )!, + fromContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}from_contact_id'], + )!, + publicKeyVerifiedTimestamp: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}public_key_verified_timestamp'], + ), + ); + } + + @override + $UserDiscoveryUserRelationsTable createAlias(String alias) { + return $UserDiscoveryUserRelationsTable(attachedDatabase, alias); + } +} + +class UserDiscoveryUserRelation extends DataClass + implements Insertable { + final int announcedUserId; + final int fromContactId; + final DateTime? publicKeyVerifiedTimestamp; + const UserDiscoveryUserRelation({ + required this.announcedUserId, + required this.fromContactId, + this.publicKeyVerifiedTimestamp, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['announced_user_id'] = Variable(announcedUserId); + map['from_contact_id'] = Variable(fromContactId); + if (!nullToAbsent || publicKeyVerifiedTimestamp != null) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp, + ); + } + return map; + } + + UserDiscoveryUserRelationsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryUserRelationsCompanion( + announcedUserId: Value(announcedUserId), + fromContactId: Value(fromContactId), + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp == null && nullToAbsent + ? const Value.absent() + : Value(publicKeyVerifiedTimestamp), + ); + } + + factory UserDiscoveryUserRelation.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryUserRelation( + announcedUserId: serializer.fromJson(json['announcedUserId']), + fromContactId: serializer.fromJson(json['fromContactId']), + publicKeyVerifiedTimestamp: serializer.fromJson( + json['publicKeyVerifiedTimestamp'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'announcedUserId': serializer.toJson(announcedUserId), + 'fromContactId': serializer.toJson(fromContactId), + 'publicKeyVerifiedTimestamp': serializer.toJson( + publicKeyVerifiedTimestamp, + ), + }; + } + + UserDiscoveryUserRelation copyWith({ + int? announcedUserId, + int? fromContactId, + Value publicKeyVerifiedTimestamp = const Value.absent(), + }) => UserDiscoveryUserRelation( + announcedUserId: announcedUserId ?? this.announcedUserId, + fromContactId: fromContactId ?? this.fromContactId, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp.present + ? publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + UserDiscoveryUserRelation copyWithCompanion( + UserDiscoveryUserRelationsCompanion data, + ) { + return UserDiscoveryUserRelation( + announcedUserId: data.announcedUserId.present + ? data.announcedUserId.value + : this.announcedUserId, + fromContactId: data.fromContactId.present + ? data.fromContactId.value + : this.fromContactId, + publicKeyVerifiedTimestamp: data.publicKeyVerifiedTimestamp.present + ? data.publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryUserRelation(') + ..write('announcedUserId: $announcedUserId, ') + ..write('fromContactId: $fromContactId, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(announcedUserId, fromContactId, publicKeyVerifiedTimestamp); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryUserRelation && + other.announcedUserId == this.announcedUserId && + other.fromContactId == this.fromContactId && + other.publicKeyVerifiedTimestamp == this.publicKeyVerifiedTimestamp); +} + +class UserDiscoveryUserRelationsCompanion + extends UpdateCompanion { + final Value announcedUserId; + final Value fromContactId; + final Value publicKeyVerifiedTimestamp; + final Value rowid; + const UserDiscoveryUserRelationsCompanion({ + this.announcedUserId = const Value.absent(), + this.fromContactId = const Value.absent(), + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }); + UserDiscoveryUserRelationsCompanion.insert({ + required int announcedUserId, + required int fromContactId, + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }) : announcedUserId = Value(announcedUserId), + fromContactId = Value(fromContactId); + static Insertable custom({ + Expression? announcedUserId, + Expression? fromContactId, + Expression? publicKeyVerifiedTimestamp, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (announcedUserId != null) 'announced_user_id': announcedUserId, + if (fromContactId != null) 'from_contact_id': fromContactId, + if (publicKeyVerifiedTimestamp != null) + 'public_key_verified_timestamp': publicKeyVerifiedTimestamp, + if (rowid != null) 'rowid': rowid, + }); + } + + UserDiscoveryUserRelationsCompanion copyWith({ + Value? announcedUserId, + Value? fromContactId, + Value? publicKeyVerifiedTimestamp, + Value? rowid, + }) { + return UserDiscoveryUserRelationsCompanion( + announcedUserId: announcedUserId ?? this.announcedUserId, + fromContactId: fromContactId ?? this.fromContactId, + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp ?? this.publicKeyVerifiedTimestamp, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (announcedUserId.present) { + map['announced_user_id'] = Variable(announcedUserId.value); + } + if (fromContactId.present) { + map['from_contact_id'] = Variable(fromContactId.value); + } + if (publicKeyVerifiedTimestamp.present) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp.value, + ); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryUserRelationsCompanion(') + ..write('announcedUserId: $announcedUserId, ') + ..write('fromContactId: $fromContactId, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $UserDiscoveryOtherPromotionsTable extends UserDiscoveryOtherPromotions + with + TableInfo< + $UserDiscoveryOtherPromotionsTable, + UserDiscoveryOtherPromotion + > { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $UserDiscoveryOtherPromotionsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _fromContactIdMeta = const VerificationMeta( + 'fromContactId', + ); + @override + late final GeneratedColumn fromContactId = GeneratedColumn( + 'from_contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES contacts (user_id) ON DELETE CASCADE', + ), + ); + static const VerificationMeta _promotionIdMeta = const VerificationMeta( + 'promotionId', + ); + @override + late final GeneratedColumn promotionId = GeneratedColumn( + 'promotion_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _publicIdMeta = const VerificationMeta( + 'publicId', + ); + @override + late final GeneratedColumn publicId = GeneratedColumn( + 'public_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _thresholdMeta = const VerificationMeta( + 'threshold', + ); + @override + late final GeneratedColumn threshold = GeneratedColumn( + 'threshold', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _announcementShareMeta = const VerificationMeta( + 'announcementShare', + ); + @override + late final GeneratedColumn announcementShare = + GeneratedColumn( + 'announcement_share', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + static const VerificationMeta _publicKeyVerifiedTimestampMeta = + const VerificationMeta('publicKeyVerifiedTimestamp'); + @override + late final GeneratedColumn publicKeyVerifiedTimestamp = + GeneratedColumn( + 'public_key_verified_timestamp', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + fromContactId, + promotionId, + publicId, + threshold, + announcementShare, + publicKeyVerifiedTimestamp, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_other_promotions'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('from_contact_id')) { + context.handle( + _fromContactIdMeta, + fromContactId.isAcceptableOrUnknown( + data['from_contact_id']!, + _fromContactIdMeta, + ), + ); + } else if (isInserting) { + context.missing(_fromContactIdMeta); + } + if (data.containsKey('promotion_id')) { + context.handle( + _promotionIdMeta, + promotionId.isAcceptableOrUnknown( + data['promotion_id']!, + _promotionIdMeta, + ), + ); + } else if (isInserting) { + context.missing(_promotionIdMeta); + } + if (data.containsKey('public_id')) { + context.handle( + _publicIdMeta, + publicId.isAcceptableOrUnknown(data['public_id']!, _publicIdMeta), + ); + } else if (isInserting) { + context.missing(_publicIdMeta); + } + if (data.containsKey('threshold')) { + context.handle( + _thresholdMeta, + threshold.isAcceptableOrUnknown(data['threshold']!, _thresholdMeta), + ); + } else if (isInserting) { + context.missing(_thresholdMeta); + } + if (data.containsKey('announcement_share')) { + context.handle( + _announcementShareMeta, + announcementShare.isAcceptableOrUnknown( + data['announcement_share']!, + _announcementShareMeta, + ), + ); + } else if (isInserting) { + context.missing(_announcementShareMeta); + } + if (data.containsKey('public_key_verified_timestamp')) { + context.handle( + _publicKeyVerifiedTimestampMeta, + publicKeyVerifiedTimestamp.isAcceptableOrUnknown( + data['public_key_verified_timestamp']!, + _publicKeyVerifiedTimestampMeta, + ), + ); + } + return context; + } + + @override + Set get $primaryKey => {fromContactId, promotionId}; + @override + UserDiscoveryOtherPromotion map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryOtherPromotion( + fromContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}from_contact_id'], + )!, + promotionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}promotion_id'], + )!, + publicId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_id'], + )!, + threshold: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}threshold'], + )!, + announcementShare: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}announcement_share'], + )!, + publicKeyVerifiedTimestamp: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}public_key_verified_timestamp'], + ), + ); + } + + @override + $UserDiscoveryOtherPromotionsTable createAlias(String alias) { + return $UserDiscoveryOtherPromotionsTable(attachedDatabase, alias); + } +} + +class UserDiscoveryOtherPromotion extends DataClass + implements Insertable { + final int fromContactId; + final int promotionId; + final int publicId; + final int threshold; + final Uint8List announcementShare; + final DateTime? publicKeyVerifiedTimestamp; + const UserDiscoveryOtherPromotion({ + required this.fromContactId, + required this.promotionId, + required this.publicId, + required this.threshold, + required this.announcementShare, + this.publicKeyVerifiedTimestamp, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['from_contact_id'] = Variable(fromContactId); + map['promotion_id'] = Variable(promotionId); + map['public_id'] = Variable(publicId); + map['threshold'] = Variable(threshold); + map['announcement_share'] = Variable(announcementShare); + if (!nullToAbsent || publicKeyVerifiedTimestamp != null) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp, + ); + } + return map; + } + + UserDiscoveryOtherPromotionsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryOtherPromotionsCompanion( + fromContactId: Value(fromContactId), + promotionId: Value(promotionId), + publicId: Value(publicId), + threshold: Value(threshold), + announcementShare: Value(announcementShare), + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp == null && nullToAbsent + ? const Value.absent() + : Value(publicKeyVerifiedTimestamp), + ); + } + + factory UserDiscoveryOtherPromotion.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryOtherPromotion( + fromContactId: serializer.fromJson(json['fromContactId']), + promotionId: serializer.fromJson(json['promotionId']), + publicId: serializer.fromJson(json['publicId']), + threshold: serializer.fromJson(json['threshold']), + announcementShare: serializer.fromJson( + json['announcementShare'], + ), + publicKeyVerifiedTimestamp: serializer.fromJson( + json['publicKeyVerifiedTimestamp'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'fromContactId': serializer.toJson(fromContactId), + 'promotionId': serializer.toJson(promotionId), + 'publicId': serializer.toJson(publicId), + 'threshold': serializer.toJson(threshold), + 'announcementShare': serializer.toJson(announcementShare), + 'publicKeyVerifiedTimestamp': serializer.toJson( + publicKeyVerifiedTimestamp, + ), + }; + } + + UserDiscoveryOtherPromotion copyWith({ + int? fromContactId, + int? promotionId, + int? publicId, + int? threshold, + Uint8List? announcementShare, + Value publicKeyVerifiedTimestamp = const Value.absent(), + }) => UserDiscoveryOtherPromotion( + fromContactId: fromContactId ?? this.fromContactId, + promotionId: promotionId ?? this.promotionId, + publicId: publicId ?? this.publicId, + threshold: threshold ?? this.threshold, + announcementShare: announcementShare ?? this.announcementShare, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp.present + ? publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + UserDiscoveryOtherPromotion copyWithCompanion( + UserDiscoveryOtherPromotionsCompanion data, + ) { + return UserDiscoveryOtherPromotion( + fromContactId: data.fromContactId.present + ? data.fromContactId.value + : this.fromContactId, + promotionId: data.promotionId.present + ? data.promotionId.value + : this.promotionId, + publicId: data.publicId.present ? data.publicId.value : this.publicId, + threshold: data.threshold.present ? data.threshold.value : this.threshold, + announcementShare: data.announcementShare.present + ? data.announcementShare.value + : this.announcementShare, + publicKeyVerifiedTimestamp: data.publicKeyVerifiedTimestamp.present + ? data.publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOtherPromotion(') + ..write('fromContactId: $fromContactId, ') + ..write('promotionId: $promotionId, ') + ..write('publicId: $publicId, ') + ..write('threshold: $threshold, ') + ..write('announcementShare: $announcementShare, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + fromContactId, + promotionId, + publicId, + threshold, + $driftBlobEquality.hash(announcementShare), + publicKeyVerifiedTimestamp, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryOtherPromotion && + other.fromContactId == this.fromContactId && + other.promotionId == this.promotionId && + other.publicId == this.publicId && + other.threshold == this.threshold && + $driftBlobEquality.equals( + other.announcementShare, + this.announcementShare, + ) && + other.publicKeyVerifiedTimestamp == this.publicKeyVerifiedTimestamp); +} + +class UserDiscoveryOtherPromotionsCompanion + extends UpdateCompanion { + final Value fromContactId; + final Value promotionId; + final Value publicId; + final Value threshold; + final Value announcementShare; + final Value publicKeyVerifiedTimestamp; + final Value rowid; + const UserDiscoveryOtherPromotionsCompanion({ + this.fromContactId = const Value.absent(), + this.promotionId = const Value.absent(), + this.publicId = const Value.absent(), + this.threshold = const Value.absent(), + this.announcementShare = const Value.absent(), + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }); + UserDiscoveryOtherPromotionsCompanion.insert({ + required int fromContactId, + required int promotionId, + required int publicId, + required int threshold, + required Uint8List announcementShare, + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }) : fromContactId = Value(fromContactId), + promotionId = Value(promotionId), + publicId = Value(publicId), + threshold = Value(threshold), + announcementShare = Value(announcementShare); + static Insertable custom({ + Expression? fromContactId, + Expression? promotionId, + Expression? publicId, + Expression? threshold, + Expression? announcementShare, + Expression? publicKeyVerifiedTimestamp, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (fromContactId != null) 'from_contact_id': fromContactId, + if (promotionId != null) 'promotion_id': promotionId, + if (publicId != null) 'public_id': publicId, + if (threshold != null) 'threshold': threshold, + if (announcementShare != null) 'announcement_share': announcementShare, + if (publicKeyVerifiedTimestamp != null) + 'public_key_verified_timestamp': publicKeyVerifiedTimestamp, + if (rowid != null) 'rowid': rowid, + }); + } + + UserDiscoveryOtherPromotionsCompanion copyWith({ + Value? fromContactId, + Value? promotionId, + Value? publicId, + Value? threshold, + Value? announcementShare, + Value? publicKeyVerifiedTimestamp, + Value? rowid, + }) { + return UserDiscoveryOtherPromotionsCompanion( + fromContactId: fromContactId ?? this.fromContactId, + promotionId: promotionId ?? this.promotionId, + publicId: publicId ?? this.publicId, + threshold: threshold ?? this.threshold, + announcementShare: announcementShare ?? this.announcementShare, + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp ?? this.publicKeyVerifiedTimestamp, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (fromContactId.present) { + map['from_contact_id'] = Variable(fromContactId.value); + } + if (promotionId.present) { + map['promotion_id'] = Variable(promotionId.value); + } + if (publicId.present) { + map['public_id'] = Variable(publicId.value); + } + if (threshold.present) { + map['threshold'] = Variable(threshold.value); + } + if (announcementShare.present) { + map['announcement_share'] = Variable(announcementShare.value); + } + if (publicKeyVerifiedTimestamp.present) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp.value, + ); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOtherPromotionsCompanion(') + ..write('fromContactId: $fromContactId, ') + ..write('promotionId: $promotionId, ') + ..write('publicId: $publicId, ') + ..write('threshold: $threshold, ') + ..write('announcementShare: $announcementShare, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $UserDiscoveryOwnPromotionsTable extends UserDiscoveryOwnPromotions + with + TableInfo<$UserDiscoveryOwnPromotionsTable, UserDiscoveryOwnPromotion> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $UserDiscoveryOwnPromotionsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _versionIdMeta = const VerificationMeta( + 'versionId', + ); + @override + late final GeneratedColumn versionId = GeneratedColumn( + 'version_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const VerificationMeta _contactIdMeta = const VerificationMeta( + 'contactId', + ); + @override + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES contacts (user_id) ON DELETE CASCADE', + ), + ); + static const VerificationMeta _promotionMeta = const VerificationMeta( + 'promotion', + ); + @override + late final GeneratedColumn promotion = GeneratedColumn( + 'promotion', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + @override + List get $columns => [versionId, contactId, promotion]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_own_promotions'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('version_id')) { + context.handle( + _versionIdMeta, + versionId.isAcceptableOrUnknown(data['version_id']!, _versionIdMeta), + ); + } + if (data.containsKey('contact_id')) { + context.handle( + _contactIdMeta, + contactId.isAcceptableOrUnknown(data['contact_id']!, _contactIdMeta), + ); + } else if (isInserting) { + context.missing(_contactIdMeta); + } + if (data.containsKey('promotion')) { + context.handle( + _promotionMeta, + promotion.isAcceptableOrUnknown(data['promotion']!, _promotionMeta), + ); + } else if (isInserting) { + context.missing(_promotionMeta); + } + return context; + } + + @override + Set get $primaryKey => {versionId}; + @override + UserDiscoveryOwnPromotion map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryOwnPromotion( + versionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}version_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + promotion: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}promotion'], + )!, + ); + } + + @override + $UserDiscoveryOwnPromotionsTable createAlias(String alias) { + return $UserDiscoveryOwnPromotionsTable(attachedDatabase, alias); + } +} + +class UserDiscoveryOwnPromotion extends DataClass + implements Insertable { + final int versionId; + final int contactId; + final Uint8List promotion; + const UserDiscoveryOwnPromotion({ + required this.versionId, + required this.contactId, + required this.promotion, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['version_id'] = Variable(versionId); + map['contact_id'] = Variable(contactId); + map['promotion'] = Variable(promotion); + return map; + } + + UserDiscoveryOwnPromotionsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryOwnPromotionsCompanion( + versionId: Value(versionId), + contactId: Value(contactId), + promotion: Value(promotion), + ); + } + + factory UserDiscoveryOwnPromotion.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryOwnPromotion( + versionId: serializer.fromJson(json['versionId']), + contactId: serializer.fromJson(json['contactId']), + promotion: serializer.fromJson(json['promotion']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'versionId': serializer.toJson(versionId), + 'contactId': serializer.toJson(contactId), + 'promotion': serializer.toJson(promotion), + }; + } + + UserDiscoveryOwnPromotion copyWith({ + int? versionId, + int? contactId, + Uint8List? promotion, + }) => UserDiscoveryOwnPromotion( + versionId: versionId ?? this.versionId, + contactId: contactId ?? this.contactId, + promotion: promotion ?? this.promotion, + ); + UserDiscoveryOwnPromotion copyWithCompanion( + UserDiscoveryOwnPromotionsCompanion data, + ) { + return UserDiscoveryOwnPromotion( + versionId: data.versionId.present ? data.versionId.value : this.versionId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + promotion: data.promotion.present ? data.promotion.value : this.promotion, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOwnPromotion(') + ..write('versionId: $versionId, ') + ..write('contactId: $contactId, ') + ..write('promotion: $promotion') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(versionId, contactId, $driftBlobEquality.hash(promotion)); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryOwnPromotion && + other.versionId == this.versionId && + other.contactId == this.contactId && + $driftBlobEquality.equals(other.promotion, this.promotion)); +} + +class UserDiscoveryOwnPromotionsCompanion + extends UpdateCompanion { + final Value versionId; + final Value contactId; + final Value promotion; + const UserDiscoveryOwnPromotionsCompanion({ + this.versionId = const Value.absent(), + this.contactId = const Value.absent(), + this.promotion = const Value.absent(), + }); + UserDiscoveryOwnPromotionsCompanion.insert({ + this.versionId = const Value.absent(), + required int contactId, + required Uint8List promotion, + }) : contactId = Value(contactId), + promotion = Value(promotion); + static Insertable custom({ + Expression? versionId, + Expression? contactId, + Expression? promotion, + }) { + return RawValuesInsertable({ + if (versionId != null) 'version_id': versionId, + if (contactId != null) 'contact_id': contactId, + if (promotion != null) 'promotion': promotion, + }); + } + + UserDiscoveryOwnPromotionsCompanion copyWith({ + Value? versionId, + Value? contactId, + Value? promotion, + }) { + return UserDiscoveryOwnPromotionsCompanion( + versionId: versionId ?? this.versionId, + contactId: contactId ?? this.contactId, + promotion: promotion ?? this.promotion, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (versionId.present) { + map['version_id'] = Variable(versionId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (promotion.present) { + map['promotion'] = Variable(promotion.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOwnPromotionsCompanion(') + ..write('versionId: $versionId, ') + ..write('contactId: $contactId, ') + ..write('promotion: $promotion') + ..write(')')) + .toString(); + } +} + +class $UserDiscoverySharesTable extends UserDiscoveryShares + with TableInfo<$UserDiscoverySharesTable, UserDiscoveryShare> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $UserDiscoverySharesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _shareIdMeta = const VerificationMeta( + 'shareId', + ); + @override + late final GeneratedColumn shareId = GeneratedColumn( + 'share_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const VerificationMeta _shareMeta = const VerificationMeta('share'); + @override + late final GeneratedColumn share = GeneratedColumn( + 'share', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + static const VerificationMeta _contactIdMeta = const VerificationMeta( + 'contactId', + ); + @override + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES contacts (user_id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [shareId, share, contactId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_shares'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('share_id')) { + context.handle( + _shareIdMeta, + shareId.isAcceptableOrUnknown(data['share_id']!, _shareIdMeta), + ); + } + if (data.containsKey('share')) { + context.handle( + _shareMeta, + share.isAcceptableOrUnknown(data['share']!, _shareMeta), + ); + } else if (isInserting) { + context.missing(_shareMeta); + } + if (data.containsKey('contact_id')) { + context.handle( + _contactIdMeta, + contactId.isAcceptableOrUnknown(data['contact_id']!, _contactIdMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {shareId}; + @override + UserDiscoveryShare map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryShare( + shareId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}share_id'], + )!, + share: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}share'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + ); + } + + @override + $UserDiscoverySharesTable createAlias(String alias) { + return $UserDiscoverySharesTable(attachedDatabase, alias); + } +} + +class UserDiscoveryShare extends DataClass + implements Insertable { + final int shareId; + final Uint8List share; + final int? contactId; + const UserDiscoveryShare({ + required this.shareId, + required this.share, + this.contactId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['share_id'] = Variable(shareId); + map['share'] = Variable(share); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + return map; + } + + UserDiscoverySharesCompanion toCompanion(bool nullToAbsent) { + return UserDiscoverySharesCompanion( + shareId: Value(shareId), + share: Value(share), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + ); + } + + factory UserDiscoveryShare.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryShare( + shareId: serializer.fromJson(json['shareId']), + share: serializer.fromJson(json['share']), + contactId: serializer.fromJson(json['contactId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'shareId': serializer.toJson(shareId), + 'share': serializer.toJson(share), + 'contactId': serializer.toJson(contactId), + }; + } + + UserDiscoveryShare copyWith({ + int? shareId, + Uint8List? share, + Value contactId = const Value.absent(), + }) => UserDiscoveryShare( + shareId: shareId ?? this.shareId, + share: share ?? this.share, + contactId: contactId.present ? contactId.value : this.contactId, + ); + UserDiscoveryShare copyWithCompanion(UserDiscoverySharesCompanion data) { + return UserDiscoveryShare( + shareId: data.shareId.present ? data.shareId.value : this.shareId, + share: data.share.present ? data.share.value : this.share, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryShare(') + ..write('shareId: $shareId, ') + ..write('share: $share, ') + ..write('contactId: $contactId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(shareId, $driftBlobEquality.hash(share), contactId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryShare && + other.shareId == this.shareId && + $driftBlobEquality.equals(other.share, this.share) && + other.contactId == this.contactId); +} + +class UserDiscoverySharesCompanion extends UpdateCompanion { + final Value shareId; + final Value share; + final Value contactId; + const UserDiscoverySharesCompanion({ + this.shareId = const Value.absent(), + this.share = const Value.absent(), + this.contactId = const Value.absent(), + }); + UserDiscoverySharesCompanion.insert({ + this.shareId = const Value.absent(), + required Uint8List share, + this.contactId = const Value.absent(), + }) : share = Value(share); + static Insertable custom({ + Expression? shareId, + Expression? share, + Expression? contactId, + }) { + return RawValuesInsertable({ + if (shareId != null) 'share_id': shareId, + if (share != null) 'share': share, + if (contactId != null) 'contact_id': contactId, + }); + } + + UserDiscoverySharesCompanion copyWith({ + Value? shareId, + Value? share, + Value? contactId, + }) { + return UserDiscoverySharesCompanion( + shareId: shareId ?? this.shareId, + share: share ?? this.share, + contactId: contactId ?? this.contactId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (shareId.present) { + map['share_id'] = Variable(shareId.value); + } + if (share.present) { + map['share'] = Variable(share.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoverySharesCompanion(') + ..write('shareId: $shareId, ') + ..write('share: $share, ') + ..write('contactId: $contactId') + ..write(')')) + .toString(); + } +} + abstract class _$TwonlyDB extends GeneratedDatabase { _$TwonlyDB(QueryExecutor e) : super(e); $TwonlyDBManager get managers => $TwonlyDBManager(this); @@ -8831,12 +11034,30 @@ abstract class _$TwonlyDB extends GeneratedDatabase { $SignalSessionStoresTable(this); late final $MessageActionsTable messageActions = $MessageActionsTable(this); late final $GroupHistoriesTable groupHistories = $GroupHistoriesTable(this); + late final $KeyVerificationsTable keyVerifications = $KeyVerificationsTable( + this, + ); + late final $VerificationTokensTable verificationTokens = + $VerificationTokensTable(this); + late final $UserDiscoveryAnnouncedUsersTable userDiscoveryAnnouncedUsers = + $UserDiscoveryAnnouncedUsersTable(this); + late final $UserDiscoveryUserRelationsTable userDiscoveryUserRelations = + $UserDiscoveryUserRelationsTable(this); + late final $UserDiscoveryOtherPromotionsTable userDiscoveryOtherPromotions = + $UserDiscoveryOtherPromotionsTable(this); + late final $UserDiscoveryOwnPromotionsTable userDiscoveryOwnPromotions = + $UserDiscoveryOwnPromotionsTable(this); + late final $UserDiscoverySharesTable userDiscoveryShares = + $UserDiscoverySharesTable(this); late final MessagesDao messagesDao = MessagesDao(this as TwonlyDB); late final ContactsDao contactsDao = ContactsDao(this as TwonlyDB); late final ReceiptsDao receiptsDao = ReceiptsDao(this as TwonlyDB); late final GroupsDao groupsDao = GroupsDao(this as TwonlyDB); late final ReactionsDao reactionsDao = ReactionsDao(this as TwonlyDB); late final MediaFilesDao mediaFilesDao = MediaFilesDao(this as TwonlyDB); + late final UserDiscoveryDao userDiscoveryDao = UserDiscoveryDao( + this as TwonlyDB, + ); @override Iterable> get allTables => allSchemaEntities.whereType>(); @@ -8857,6 +11078,13 @@ abstract class _$TwonlyDB extends GeneratedDatabase { signalSessionStores, messageActions, groupHistories, + keyVerifications, + verificationTokens, + userDiscoveryAnnouncedUsers, + userDiscoveryUserRelations, + userDiscoveryOtherPromotions, + userDiscoveryOwnPromotions, + userDiscoveryShares, ]; @override StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules([ @@ -8944,6 +11172,56 @@ abstract class _$TwonlyDB extends GeneratedDatabase { ), result: [TableUpdate('group_histories', kind: UpdateKind.delete)], ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('key_verifications', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'user_discovery_announced_users', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_user_relations', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_user_relations', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_other_promotions', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_own_promotions', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('user_discovery_shares', kind: UpdateKind.delete)], + ), ]); } @@ -8962,6 +11240,7 @@ typedef $$ContactsTableCreateCompanionBuilder = Value verified, Value accountDeleted, Value createdAt, + Value userDiscoveryVersion, }); typedef $$ContactsTableUpdateCompanionBuilder = ContactsCompanion Function({ @@ -8978,6 +11257,7 @@ typedef $$ContactsTableUpdateCompanionBuilder = Value verified, Value accountDeleted, Value createdAt, + Value userDiscoveryVersion, }); final class $$ContactsTableReferences @@ -9124,6 +11404,153 @@ final class $$ContactsTableReferences manager.$state.copyWith(prefetchedData: cache), ); } + + static MultiTypedResultKey<$KeyVerificationsTable, List> + _keyVerificationsRefsTable(_$TwonlyDB db) => MultiTypedResultKey.fromTable( + db.keyVerifications, + aliasName: $_aliasNameGenerator( + db.contacts.userId, + db.keyVerifications.contactId, + ), + ); + + $$KeyVerificationsTableProcessedTableManager get keyVerificationsRefs { + final manager = + $$KeyVerificationsTableTableManager($_db, $_db.keyVerifications).filter( + (f) => f.contactId.userId.sqlEquals($_itemColumn('user_id')!), + ); + + final cache = $_typedResult.readTableOrNull( + _keyVerificationsRefsTable($_db), + ); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } + + static MultiTypedResultKey< + $UserDiscoveryUserRelationsTable, + List + > + _userDiscoveryUserRelationsRefsTable(_$TwonlyDB db) => + MultiTypedResultKey.fromTable( + db.userDiscoveryUserRelations, + aliasName: $_aliasNameGenerator( + db.contacts.userId, + db.userDiscoveryUserRelations.fromContactId, + ), + ); + + $$UserDiscoveryUserRelationsTableProcessedTableManager + get userDiscoveryUserRelationsRefs { + final manager = + $$UserDiscoveryUserRelationsTableTableManager( + $_db, + $_db.userDiscoveryUserRelations, + ).filter( + (f) => + f.fromContactId.userId.sqlEquals($_itemColumn('user_id')!), + ); + + final cache = $_typedResult.readTableOrNull( + _userDiscoveryUserRelationsRefsTable($_db), + ); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } + + static MultiTypedResultKey< + $UserDiscoveryOtherPromotionsTable, + List + > + _userDiscoveryOtherPromotionsRefsTable(_$TwonlyDB db) => + MultiTypedResultKey.fromTable( + db.userDiscoveryOtherPromotions, + aliasName: $_aliasNameGenerator( + db.contacts.userId, + db.userDiscoveryOtherPromotions.fromContactId, + ), + ); + + $$UserDiscoveryOtherPromotionsTableProcessedTableManager + get userDiscoveryOtherPromotionsRefs { + final manager = + $$UserDiscoveryOtherPromotionsTableTableManager( + $_db, + $_db.userDiscoveryOtherPromotions, + ).filter( + (f) => + f.fromContactId.userId.sqlEquals($_itemColumn('user_id')!), + ); + + final cache = $_typedResult.readTableOrNull( + _userDiscoveryOtherPromotionsRefsTable($_db), + ); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } + + static MultiTypedResultKey< + $UserDiscoveryOwnPromotionsTable, + List + > + _userDiscoveryOwnPromotionsRefsTable(_$TwonlyDB db) => + MultiTypedResultKey.fromTable( + db.userDiscoveryOwnPromotions, + aliasName: $_aliasNameGenerator( + db.contacts.userId, + db.userDiscoveryOwnPromotions.contactId, + ), + ); + + $$UserDiscoveryOwnPromotionsTableProcessedTableManager + get userDiscoveryOwnPromotionsRefs { + final manager = + $$UserDiscoveryOwnPromotionsTableTableManager( + $_db, + $_db.userDiscoveryOwnPromotions, + ).filter( + (f) => f.contactId.userId.sqlEquals($_itemColumn('user_id')!), + ); + + final cache = $_typedResult.readTableOrNull( + _userDiscoveryOwnPromotionsRefsTable($_db), + ); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } + + static MultiTypedResultKey< + $UserDiscoverySharesTable, + List + > + _userDiscoverySharesRefsTable(_$TwonlyDB db) => MultiTypedResultKey.fromTable( + db.userDiscoveryShares, + aliasName: $_aliasNameGenerator( + db.contacts.userId, + db.userDiscoveryShares.contactId, + ), + ); + + $$UserDiscoverySharesTableProcessedTableManager get userDiscoverySharesRefs { + final manager = + $$UserDiscoverySharesTableTableManager( + $_db, + $_db.userDiscoveryShares, + ).filter( + (f) => f.contactId.userId.sqlEquals($_itemColumn('user_id')!), + ); + + final cache = $_typedResult.readTableOrNull( + _userDiscoverySharesRefsTable($_db), + ); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } } class $$ContactsTableFilterComposer @@ -9200,6 +11627,11 @@ class $$ContactsTableFilterComposer builder: (column) => ColumnFilters(column), ); + ColumnFilters get userDiscoveryVersion => $composableBuilder( + column: $table.userDiscoveryVersion, + builder: (column) => ColumnFilters(column), + ); + Expression messagesRefs( Expression Function($$MessagesTableFilterComposer f) f, ) { @@ -9374,6 +11806,139 @@ class $$ContactsTableFilterComposer ); return f(composer); } + + Expression keyVerificationsRefs( + Expression Function($$KeyVerificationsTableFilterComposer f) f, + ) { + final $$KeyVerificationsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: $db.keyVerifications, + getReferencedColumn: (t) => t.contactId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$KeyVerificationsTableFilterComposer( + $db: $db, + $table: $db.keyVerifications, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression userDiscoveryUserRelationsRefs( + Expression Function($$UserDiscoveryUserRelationsTableFilterComposer f) + f, + ) { + final $$UserDiscoveryUserRelationsTableFilterComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: $db.userDiscoveryUserRelations, + getReferencedColumn: (t) => t.fromContactId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoveryUserRelationsTableFilterComposer( + $db: $db, + $table: $db.userDiscoveryUserRelations, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression userDiscoveryOtherPromotionsRefs( + Expression Function( + $$UserDiscoveryOtherPromotionsTableFilterComposer f, + ) + f, + ) { + final $$UserDiscoveryOtherPromotionsTableFilterComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: $db.userDiscoveryOtherPromotions, + getReferencedColumn: (t) => t.fromContactId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoveryOtherPromotionsTableFilterComposer( + $db: $db, + $table: $db.userDiscoveryOtherPromotions, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression userDiscoveryOwnPromotionsRefs( + Expression Function($$UserDiscoveryOwnPromotionsTableFilterComposer f) + f, + ) { + final $$UserDiscoveryOwnPromotionsTableFilterComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: $db.userDiscoveryOwnPromotions, + getReferencedColumn: (t) => t.contactId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoveryOwnPromotionsTableFilterComposer( + $db: $db, + $table: $db.userDiscoveryOwnPromotions, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression userDiscoverySharesRefs( + Expression Function($$UserDiscoverySharesTableFilterComposer f) f, + ) { + final $$UserDiscoverySharesTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: $db.userDiscoveryShares, + getReferencedColumn: (t) => t.contactId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoverySharesTableFilterComposer( + $db: $db, + $table: $db.userDiscoveryShares, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } } class $$ContactsTableOrderingComposer @@ -9449,6 +12014,11 @@ class $$ContactsTableOrderingComposer column: $table.createdAt, builder: (column) => ColumnOrderings(column), ); + + ColumnOrderings get userDiscoveryVersion => $composableBuilder( + column: $table.userDiscoveryVersion, + builder: (column) => ColumnOrderings(column), + ); } class $$ContactsTableAnnotationComposer @@ -9509,6 +12079,11 @@ class $$ContactsTableAnnotationComposer GeneratedColumn get createdAt => $composableBuilder(column: $table.createdAt, builder: (column) => column); + GeneratedColumn get userDiscoveryVersion => $composableBuilder( + column: $table.userDiscoveryVersion, + builder: (column) => column, + ); + Expression messagesRefs( Expression Function($$MessagesTableAnnotationComposer a) f, ) { @@ -9683,6 +12258,144 @@ class $$ContactsTableAnnotationComposer ); return f(composer); } + + Expression keyVerificationsRefs( + Expression Function($$KeyVerificationsTableAnnotationComposer a) f, + ) { + final $$KeyVerificationsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: $db.keyVerifications, + getReferencedColumn: (t) => t.contactId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$KeyVerificationsTableAnnotationComposer( + $db: $db, + $table: $db.keyVerifications, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression userDiscoveryUserRelationsRefs( + Expression Function( + $$UserDiscoveryUserRelationsTableAnnotationComposer a, + ) + f, + ) { + final $$UserDiscoveryUserRelationsTableAnnotationComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: $db.userDiscoveryUserRelations, + getReferencedColumn: (t) => t.fromContactId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoveryUserRelationsTableAnnotationComposer( + $db: $db, + $table: $db.userDiscoveryUserRelations, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression userDiscoveryOtherPromotionsRefs( + Expression Function( + $$UserDiscoveryOtherPromotionsTableAnnotationComposer a, + ) + f, + ) { + final $$UserDiscoveryOtherPromotionsTableAnnotationComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: $db.userDiscoveryOtherPromotions, + getReferencedColumn: (t) => t.fromContactId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoveryOtherPromotionsTableAnnotationComposer( + $db: $db, + $table: $db.userDiscoveryOtherPromotions, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression userDiscoveryOwnPromotionsRefs( + Expression Function( + $$UserDiscoveryOwnPromotionsTableAnnotationComposer a, + ) + f, + ) { + final $$UserDiscoveryOwnPromotionsTableAnnotationComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: $db.userDiscoveryOwnPromotions, + getReferencedColumn: (t) => t.contactId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoveryOwnPromotionsTableAnnotationComposer( + $db: $db, + $table: $db.userDiscoveryOwnPromotions, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression userDiscoverySharesRefs( + Expression Function($$UserDiscoverySharesTableAnnotationComposer a) f, + ) { + final $$UserDiscoverySharesTableAnnotationComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: $db.userDiscoveryShares, + getReferencedColumn: (t) => t.contactId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoverySharesTableAnnotationComposer( + $db: $db, + $table: $db.userDiscoveryShares, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } } class $$ContactsTableTableManager @@ -9706,6 +12419,11 @@ class $$ContactsTableTableManager bool receiptsRefs, bool messageActionsRefs, bool groupHistoriesRefs, + bool keyVerificationsRefs, + bool userDiscoveryUserRelationsRefs, + bool userDiscoveryOtherPromotionsRefs, + bool userDiscoveryOwnPromotionsRefs, + bool userDiscoverySharesRefs, }) > { $$ContactsTableTableManager(_$TwonlyDB db, $ContactsTable table) @@ -9734,6 +12452,7 @@ class $$ContactsTableTableManager Value verified = const Value.absent(), Value accountDeleted = const Value.absent(), Value createdAt = const Value.absent(), + Value userDiscoveryVersion = const Value.absent(), }) => ContactsCompanion( userId: userId, username: username, @@ -9748,6 +12467,7 @@ class $$ContactsTableTableManager verified: verified, accountDeleted: accountDeleted, createdAt: createdAt, + userDiscoveryVersion: userDiscoveryVersion, ), createCompanionCallback: ({ @@ -9764,6 +12484,7 @@ class $$ContactsTableTableManager Value verified = const Value.absent(), Value accountDeleted = const Value.absent(), Value createdAt = const Value.absent(), + Value userDiscoveryVersion = const Value.absent(), }) => ContactsCompanion.insert( userId: userId, username: username, @@ -9778,6 +12499,7 @@ class $$ContactsTableTableManager verified: verified, accountDeleted: accountDeleted, createdAt: createdAt, + userDiscoveryVersion: userDiscoveryVersion, ), withReferenceMapper: (p0) => p0 .map( @@ -9796,6 +12518,11 @@ class $$ContactsTableTableManager receiptsRefs = false, messageActionsRefs = false, groupHistoriesRefs = false, + keyVerificationsRefs = false, + userDiscoveryUserRelationsRefs = false, + userDiscoveryOtherPromotionsRefs = false, + userDiscoveryOwnPromotionsRefs = false, + userDiscoverySharesRefs = false, }) { return PrefetchHooks( db: db, @@ -9807,6 +12534,14 @@ class $$ContactsTableTableManager if (receiptsRefs) db.receipts, if (messageActionsRefs) db.messageActions, if (groupHistoriesRefs) db.groupHistories, + if (keyVerificationsRefs) db.keyVerifications, + if (userDiscoveryUserRelationsRefs) + db.userDiscoveryUserRelations, + if (userDiscoveryOtherPromotionsRefs) + db.userDiscoveryOtherPromotions, + if (userDiscoveryOwnPromotionsRefs) + db.userDiscoveryOwnPromotions, + if (userDiscoverySharesRefs) db.userDiscoveryShares, ], addJoins: null, getPrefetchedDataCallback: (items) async { @@ -9958,6 +12693,111 @@ class $$ContactsTableTableManager ), typedResults: items, ), + if (keyVerificationsRefs) + await $_getPrefetchedData< + Contact, + $ContactsTable, + KeyVerification + >( + currentTable: table, + referencedTable: $$ContactsTableReferences + ._keyVerificationsRefsTable(db), + managerFromTypedResult: (p0) => + $$ContactsTableReferences( + db, + table, + p0, + ).keyVerificationsRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.contactId == item.userId, + ), + typedResults: items, + ), + if (userDiscoveryUserRelationsRefs) + await $_getPrefetchedData< + Contact, + $ContactsTable, + UserDiscoveryUserRelation + >( + currentTable: table, + referencedTable: $$ContactsTableReferences + ._userDiscoveryUserRelationsRefsTable(db), + managerFromTypedResult: (p0) => + $$ContactsTableReferences( + db, + table, + p0, + ).userDiscoveryUserRelationsRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.fromContactId == item.userId, + ), + typedResults: items, + ), + if (userDiscoveryOtherPromotionsRefs) + await $_getPrefetchedData< + Contact, + $ContactsTable, + UserDiscoveryOtherPromotion + >( + currentTable: table, + referencedTable: $$ContactsTableReferences + ._userDiscoveryOtherPromotionsRefsTable(db), + managerFromTypedResult: (p0) => + $$ContactsTableReferences( + db, + table, + p0, + ).userDiscoveryOtherPromotionsRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.fromContactId == item.userId, + ), + typedResults: items, + ), + if (userDiscoveryOwnPromotionsRefs) + await $_getPrefetchedData< + Contact, + $ContactsTable, + UserDiscoveryOwnPromotion + >( + currentTable: table, + referencedTable: $$ContactsTableReferences + ._userDiscoveryOwnPromotionsRefsTable(db), + managerFromTypedResult: (p0) => + $$ContactsTableReferences( + db, + table, + p0, + ).userDiscoveryOwnPromotionsRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.contactId == item.userId, + ), + typedResults: items, + ), + if (userDiscoverySharesRefs) + await $_getPrefetchedData< + Contact, + $ContactsTable, + UserDiscoveryShare + >( + currentTable: table, + referencedTable: $$ContactsTableReferences + ._userDiscoverySharesRefsTable(db), + managerFromTypedResult: (p0) => + $$ContactsTableReferences( + db, + table, + p0, + ).userDiscoverySharesRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.contactId == item.userId, + ), + typedResults: items, + ), ]; }, ); @@ -9986,6 +12826,11 @@ typedef $$ContactsTableProcessedTableManager = bool receiptsRefs, bool messageActionsRefs, bool groupHistoriesRefs, + bool keyVerificationsRefs, + bool userDiscoveryUserRelationsRefs, + bool userDiscoveryOtherPromotionsRefs, + bool userDiscoveryOwnPromotionsRefs, + bool userDiscoverySharesRefs, }) >; typedef $$GroupsTableCreateCompanionBuilder = @@ -16244,6 +19089,2161 @@ typedef $$GroupHistoriesTableProcessedTableManager = GroupHistory, PrefetchHooks Function({bool groupId, bool contactId}) >; +typedef $$KeyVerificationsTableCreateCompanionBuilder = + KeyVerificationsCompanion Function({ + Value contactId, + required VerificationType type, + Value createdAt, + }); +typedef $$KeyVerificationsTableUpdateCompanionBuilder = + KeyVerificationsCompanion Function({ + Value contactId, + Value type, + Value createdAt, + }); + +final class $$KeyVerificationsTableReferences + extends + BaseReferences<_$TwonlyDB, $KeyVerificationsTable, KeyVerification> { + $$KeyVerificationsTableReferences( + super.$_db, + super.$_table, + super.$_typedResult, + ); + + static $ContactsTable _contactIdTable(_$TwonlyDB db) => + db.contacts.createAlias( + $_aliasNameGenerator(db.keyVerifications.contactId, db.contacts.userId), + ); + + $$ContactsTableProcessedTableManager get contactId { + final $_column = $_itemColumn('contact_id')!; + + final manager = $$ContactsTableTableManager( + $_db, + $_db.contacts, + ).filter((f) => f.userId.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_contactIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$KeyVerificationsTableFilterComposer + extends Composer<_$TwonlyDB, $KeyVerificationsTable> { + $$KeyVerificationsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnWithTypeConverterFilters + get type => $composableBuilder( + column: $table.type, + builder: (column) => ColumnWithTypeConverterFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + $$ContactsTableFilterComposer get contactId { + final $$ContactsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.contactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableFilterComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$KeyVerificationsTableOrderingComposer + extends Composer<_$TwonlyDB, $KeyVerificationsTable> { + $$KeyVerificationsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get type => $composableBuilder( + column: $table.type, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + $$ContactsTableOrderingComposer get contactId { + final $$ContactsTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.contactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableOrderingComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$KeyVerificationsTableAnnotationComposer + extends Composer<_$TwonlyDB, $KeyVerificationsTable> { + $$KeyVerificationsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumnWithTypeConverter get type => + $composableBuilder(column: $table.type, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + $$ContactsTableAnnotationComposer get contactId { + final $$ContactsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.contactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableAnnotationComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$KeyVerificationsTableTableManager + extends + RootTableManager< + _$TwonlyDB, + $KeyVerificationsTable, + KeyVerification, + $$KeyVerificationsTableFilterComposer, + $$KeyVerificationsTableOrderingComposer, + $$KeyVerificationsTableAnnotationComposer, + $$KeyVerificationsTableCreateCompanionBuilder, + $$KeyVerificationsTableUpdateCompanionBuilder, + (KeyVerification, $$KeyVerificationsTableReferences), + KeyVerification, + PrefetchHooks Function({bool contactId}) + > { + $$KeyVerificationsTableTableManager( + _$TwonlyDB db, + $KeyVerificationsTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$KeyVerificationsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$KeyVerificationsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$KeyVerificationsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value contactId = const Value.absent(), + Value type = const Value.absent(), + Value createdAt = const Value.absent(), + }) => KeyVerificationsCompanion( + contactId: contactId, + type: type, + createdAt: createdAt, + ), + createCompanionCallback: + ({ + Value contactId = const Value.absent(), + required VerificationType type, + Value createdAt = const Value.absent(), + }) => KeyVerificationsCompanion.insert( + contactId: contactId, + type: type, + createdAt: createdAt, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$KeyVerificationsTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({contactId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (contactId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.contactId, + referencedTable: + $$KeyVerificationsTableReferences + ._contactIdTable(db), + referencedColumn: + $$KeyVerificationsTableReferences + ._contactIdTable(db) + .userId, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + ), + ); +} + +typedef $$KeyVerificationsTableProcessedTableManager = + ProcessedTableManager< + _$TwonlyDB, + $KeyVerificationsTable, + KeyVerification, + $$KeyVerificationsTableFilterComposer, + $$KeyVerificationsTableOrderingComposer, + $$KeyVerificationsTableAnnotationComposer, + $$KeyVerificationsTableCreateCompanionBuilder, + $$KeyVerificationsTableUpdateCompanionBuilder, + (KeyVerification, $$KeyVerificationsTableReferences), + KeyVerification, + PrefetchHooks Function({bool contactId}) + >; +typedef $$VerificationTokensTableCreateCompanionBuilder = + VerificationTokensCompanion Function({ + Value tokenId, + required Uint8List token, + Value createdAt, + }); +typedef $$VerificationTokensTableUpdateCompanionBuilder = + VerificationTokensCompanion Function({ + Value tokenId, + Value token, + Value createdAt, + }); + +class $$VerificationTokensTableFilterComposer + extends Composer<_$TwonlyDB, $VerificationTokensTable> { + $$VerificationTokensTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get tokenId => $composableBuilder( + column: $table.tokenId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get token => $composableBuilder( + column: $table.token, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); +} + +class $$VerificationTokensTableOrderingComposer + extends Composer<_$TwonlyDB, $VerificationTokensTable> { + $$VerificationTokensTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get tokenId => $composableBuilder( + column: $table.tokenId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get token => $composableBuilder( + column: $table.token, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$VerificationTokensTableAnnotationComposer + extends Composer<_$TwonlyDB, $VerificationTokensTable> { + $$VerificationTokensTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get tokenId => + $composableBuilder(column: $table.tokenId, builder: (column) => column); + + GeneratedColumn get token => + $composableBuilder(column: $table.token, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); +} + +class $$VerificationTokensTableTableManager + extends + RootTableManager< + _$TwonlyDB, + $VerificationTokensTable, + VerificationToken, + $$VerificationTokensTableFilterComposer, + $$VerificationTokensTableOrderingComposer, + $$VerificationTokensTableAnnotationComposer, + $$VerificationTokensTableCreateCompanionBuilder, + $$VerificationTokensTableUpdateCompanionBuilder, + ( + VerificationToken, + BaseReferences< + _$TwonlyDB, + $VerificationTokensTable, + VerificationToken + >, + ), + VerificationToken, + PrefetchHooks Function() + > { + $$VerificationTokensTableTableManager( + _$TwonlyDB db, + $VerificationTokensTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$VerificationTokensTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$VerificationTokensTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$VerificationTokensTableAnnotationComposer( + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + Value tokenId = const Value.absent(), + Value token = const Value.absent(), + Value createdAt = const Value.absent(), + }) => VerificationTokensCompanion( + tokenId: tokenId, + token: token, + createdAt: createdAt, + ), + createCompanionCallback: + ({ + Value tokenId = const Value.absent(), + required Uint8List token, + Value createdAt = const Value.absent(), + }) => VerificationTokensCompanion.insert( + tokenId: tokenId, + token: token, + createdAt: createdAt, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$VerificationTokensTableProcessedTableManager = + ProcessedTableManager< + _$TwonlyDB, + $VerificationTokensTable, + VerificationToken, + $$VerificationTokensTableFilterComposer, + $$VerificationTokensTableOrderingComposer, + $$VerificationTokensTableAnnotationComposer, + $$VerificationTokensTableCreateCompanionBuilder, + $$VerificationTokensTableUpdateCompanionBuilder, + ( + VerificationToken, + BaseReferences<_$TwonlyDB, $VerificationTokensTable, VerificationToken>, + ), + VerificationToken, + PrefetchHooks Function() + >; +typedef $$UserDiscoveryAnnouncedUsersTableCreateCompanionBuilder = + UserDiscoveryAnnouncedUsersCompanion Function({ + Value announcedUserId, + required Uint8List announcedPublicKey, + required int publicId, + }); +typedef $$UserDiscoveryAnnouncedUsersTableUpdateCompanionBuilder = + UserDiscoveryAnnouncedUsersCompanion Function({ + Value announcedUserId, + Value announcedPublicKey, + Value publicId, + }); + +final class $$UserDiscoveryAnnouncedUsersTableReferences + extends + BaseReferences< + _$TwonlyDB, + $UserDiscoveryAnnouncedUsersTable, + UserDiscoveryAnnouncedUser + > { + $$UserDiscoveryAnnouncedUsersTableReferences( + super.$_db, + super.$_table, + super.$_typedResult, + ); + + static MultiTypedResultKey< + $UserDiscoveryUserRelationsTable, + List + > + _userDiscoveryUserRelationsRefsTable(_$TwonlyDB db) => + MultiTypedResultKey.fromTable( + db.userDiscoveryUserRelations, + aliasName: $_aliasNameGenerator( + db.userDiscoveryAnnouncedUsers.announcedUserId, + db.userDiscoveryUserRelations.announcedUserId, + ), + ); + + $$UserDiscoveryUserRelationsTableProcessedTableManager + get userDiscoveryUserRelationsRefs { + final manager = + $$UserDiscoveryUserRelationsTableTableManager( + $_db, + $_db.userDiscoveryUserRelations, + ).filter( + (f) => f.announcedUserId.announcedUserId.sqlEquals( + $_itemColumn('announced_user_id')!, + ), + ); + + final cache = $_typedResult.readTableOrNull( + _userDiscoveryUserRelationsRefsTable($_db), + ); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } +} + +class $$UserDiscoveryAnnouncedUsersTableFilterComposer + extends Composer<_$TwonlyDB, $UserDiscoveryAnnouncedUsersTable> { + $$UserDiscoveryAnnouncedUsersTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get announcedUserId => $composableBuilder( + column: $table.announcedUserId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get announcedPublicKey => $composableBuilder( + column: $table.announcedPublicKey, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get publicId => $composableBuilder( + column: $table.publicId, + builder: (column) => ColumnFilters(column), + ); + + Expression userDiscoveryUserRelationsRefs( + Expression Function($$UserDiscoveryUserRelationsTableFilterComposer f) + f, + ) { + final $$UserDiscoveryUserRelationsTableFilterComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.announcedUserId, + referencedTable: $db.userDiscoveryUserRelations, + getReferencedColumn: (t) => t.announcedUserId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoveryUserRelationsTableFilterComposer( + $db: $db, + $table: $db.userDiscoveryUserRelations, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$UserDiscoveryAnnouncedUsersTableOrderingComposer + extends Composer<_$TwonlyDB, $UserDiscoveryAnnouncedUsersTable> { + $$UserDiscoveryAnnouncedUsersTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get announcedUserId => $composableBuilder( + column: $table.announcedUserId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get announcedPublicKey => $composableBuilder( + column: $table.announcedPublicKey, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get publicId => $composableBuilder( + column: $table.publicId, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$UserDiscoveryAnnouncedUsersTableAnnotationComposer + extends Composer<_$TwonlyDB, $UserDiscoveryAnnouncedUsersTable> { + $$UserDiscoveryAnnouncedUsersTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get announcedUserId => $composableBuilder( + column: $table.announcedUserId, + builder: (column) => column, + ); + + GeneratedColumn get announcedPublicKey => $composableBuilder( + column: $table.announcedPublicKey, + builder: (column) => column, + ); + + GeneratedColumn get publicId => + $composableBuilder(column: $table.publicId, builder: (column) => column); + + Expression userDiscoveryUserRelationsRefs( + Expression Function( + $$UserDiscoveryUserRelationsTableAnnotationComposer a, + ) + f, + ) { + final $$UserDiscoveryUserRelationsTableAnnotationComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.announcedUserId, + referencedTable: $db.userDiscoveryUserRelations, + getReferencedColumn: (t) => t.announcedUserId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoveryUserRelationsTableAnnotationComposer( + $db: $db, + $table: $db.userDiscoveryUserRelations, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$UserDiscoveryAnnouncedUsersTableTableManager + extends + RootTableManager< + _$TwonlyDB, + $UserDiscoveryAnnouncedUsersTable, + UserDiscoveryAnnouncedUser, + $$UserDiscoveryAnnouncedUsersTableFilterComposer, + $$UserDiscoveryAnnouncedUsersTableOrderingComposer, + $$UserDiscoveryAnnouncedUsersTableAnnotationComposer, + $$UserDiscoveryAnnouncedUsersTableCreateCompanionBuilder, + $$UserDiscoveryAnnouncedUsersTableUpdateCompanionBuilder, + ( + UserDiscoveryAnnouncedUser, + $$UserDiscoveryAnnouncedUsersTableReferences, + ), + UserDiscoveryAnnouncedUser, + PrefetchHooks Function({bool userDiscoveryUserRelationsRefs}) + > { + $$UserDiscoveryAnnouncedUsersTableTableManager( + _$TwonlyDB db, + $UserDiscoveryAnnouncedUsersTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$UserDiscoveryAnnouncedUsersTableFilterComposer( + $db: db, + $table: table, + ), + createOrderingComposer: () => + $$UserDiscoveryAnnouncedUsersTableOrderingComposer( + $db: db, + $table: table, + ), + createComputedFieldComposer: () => + $$UserDiscoveryAnnouncedUsersTableAnnotationComposer( + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + Value announcedUserId = const Value.absent(), + Value announcedPublicKey = const Value.absent(), + Value publicId = const Value.absent(), + }) => UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: announcedUserId, + announcedPublicKey: announcedPublicKey, + publicId: publicId, + ), + createCompanionCallback: + ({ + Value announcedUserId = const Value.absent(), + required Uint8List announcedPublicKey, + required int publicId, + }) => UserDiscoveryAnnouncedUsersCompanion.insert( + announcedUserId: announcedUserId, + announcedPublicKey: announcedPublicKey, + publicId: publicId, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$UserDiscoveryAnnouncedUsersTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({userDiscoveryUserRelationsRefs = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [ + if (userDiscoveryUserRelationsRefs) + db.userDiscoveryUserRelations, + ], + addJoins: null, + getPrefetchedDataCallback: (items) async { + return [ + if (userDiscoveryUserRelationsRefs) + await $_getPrefetchedData< + UserDiscoveryAnnouncedUser, + $UserDiscoveryAnnouncedUsersTable, + UserDiscoveryUserRelation + >( + currentTable: table, + referencedTable: + $$UserDiscoveryAnnouncedUsersTableReferences + ._userDiscoveryUserRelationsRefsTable(db), + managerFromTypedResult: (p0) => + $$UserDiscoveryAnnouncedUsersTableReferences( + db, + table, + p0, + ).userDiscoveryUserRelationsRefs, + referencedItemsForCurrentItem: (item, referencedItems) => + referencedItems.where( + (e) => e.announcedUserId == item.announcedUserId, + ), + typedResults: items, + ), + ]; + }, + ); + }, + ), + ); +} + +typedef $$UserDiscoveryAnnouncedUsersTableProcessedTableManager = + ProcessedTableManager< + _$TwonlyDB, + $UserDiscoveryAnnouncedUsersTable, + UserDiscoveryAnnouncedUser, + $$UserDiscoveryAnnouncedUsersTableFilterComposer, + $$UserDiscoveryAnnouncedUsersTableOrderingComposer, + $$UserDiscoveryAnnouncedUsersTableAnnotationComposer, + $$UserDiscoveryAnnouncedUsersTableCreateCompanionBuilder, + $$UserDiscoveryAnnouncedUsersTableUpdateCompanionBuilder, + ( + UserDiscoveryAnnouncedUser, + $$UserDiscoveryAnnouncedUsersTableReferences, + ), + UserDiscoveryAnnouncedUser, + PrefetchHooks Function({bool userDiscoveryUserRelationsRefs}) + >; +typedef $$UserDiscoveryUserRelationsTableCreateCompanionBuilder = + UserDiscoveryUserRelationsCompanion Function({ + required int announcedUserId, + required int fromContactId, + Value publicKeyVerifiedTimestamp, + Value rowid, + }); +typedef $$UserDiscoveryUserRelationsTableUpdateCompanionBuilder = + UserDiscoveryUserRelationsCompanion Function({ + Value announcedUserId, + Value fromContactId, + Value publicKeyVerifiedTimestamp, + Value rowid, + }); + +final class $$UserDiscoveryUserRelationsTableReferences + extends + BaseReferences< + _$TwonlyDB, + $UserDiscoveryUserRelationsTable, + UserDiscoveryUserRelation + > { + $$UserDiscoveryUserRelationsTableReferences( + super.$_db, + super.$_table, + super.$_typedResult, + ); + + static $UserDiscoveryAnnouncedUsersTable _announcedUserIdTable( + _$TwonlyDB db, + ) => db.userDiscoveryAnnouncedUsers.createAlias( + $_aliasNameGenerator( + db.userDiscoveryUserRelations.announcedUserId, + db.userDiscoveryAnnouncedUsers.announcedUserId, + ), + ); + + $$UserDiscoveryAnnouncedUsersTableProcessedTableManager get announcedUserId { + final $_column = $_itemColumn('announced_user_id')!; + + final manager = $$UserDiscoveryAnnouncedUsersTableTableManager( + $_db, + $_db.userDiscoveryAnnouncedUsers, + ).filter((f) => f.announcedUserId.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_announcedUserIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } + + static $ContactsTable _fromContactIdTable(_$TwonlyDB db) => + db.contacts.createAlias( + $_aliasNameGenerator( + db.userDiscoveryUserRelations.fromContactId, + db.contacts.userId, + ), + ); + + $$ContactsTableProcessedTableManager get fromContactId { + final $_column = $_itemColumn('from_contact_id')!; + + final manager = $$ContactsTableTableManager( + $_db, + $_db.contacts, + ).filter((f) => f.userId.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_fromContactIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$UserDiscoveryUserRelationsTableFilterComposer + extends Composer<_$TwonlyDB, $UserDiscoveryUserRelationsTable> { + $$UserDiscoveryUserRelationsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get publicKeyVerifiedTimestamp => $composableBuilder( + column: $table.publicKeyVerifiedTimestamp, + builder: (column) => ColumnFilters(column), + ); + + $$UserDiscoveryAnnouncedUsersTableFilterComposer get announcedUserId { + final $$UserDiscoveryAnnouncedUsersTableFilterComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.announcedUserId, + referencedTable: $db.userDiscoveryAnnouncedUsers, + getReferencedColumn: (t) => t.announcedUserId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoveryAnnouncedUsersTableFilterComposer( + $db: $db, + $table: $db.userDiscoveryAnnouncedUsers, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$ContactsTableFilterComposer get fromContactId { + final $$ContactsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.fromContactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableFilterComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoveryUserRelationsTableOrderingComposer + extends Composer<_$TwonlyDB, $UserDiscoveryUserRelationsTable> { + $$UserDiscoveryUserRelationsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get publicKeyVerifiedTimestamp => + $composableBuilder( + column: $table.publicKeyVerifiedTimestamp, + builder: (column) => ColumnOrderings(column), + ); + + $$UserDiscoveryAnnouncedUsersTableOrderingComposer get announcedUserId { + final $$UserDiscoveryAnnouncedUsersTableOrderingComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.announcedUserId, + referencedTable: $db.userDiscoveryAnnouncedUsers, + getReferencedColumn: (t) => t.announcedUserId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoveryAnnouncedUsersTableOrderingComposer( + $db: $db, + $table: $db.userDiscoveryAnnouncedUsers, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$ContactsTableOrderingComposer get fromContactId { + final $$ContactsTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.fromContactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableOrderingComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoveryUserRelationsTableAnnotationComposer + extends Composer<_$TwonlyDB, $UserDiscoveryUserRelationsTable> { + $$UserDiscoveryUserRelationsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get publicKeyVerifiedTimestamp => + $composableBuilder( + column: $table.publicKeyVerifiedTimestamp, + builder: (column) => column, + ); + + $$UserDiscoveryAnnouncedUsersTableAnnotationComposer get announcedUserId { + final $$UserDiscoveryAnnouncedUsersTableAnnotationComposer composer = + $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.announcedUserId, + referencedTable: $db.userDiscoveryAnnouncedUsers, + getReferencedColumn: (t) => t.announcedUserId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$UserDiscoveryAnnouncedUsersTableAnnotationComposer( + $db: $db, + $table: $db.userDiscoveryAnnouncedUsers, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$ContactsTableAnnotationComposer get fromContactId { + final $$ContactsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.fromContactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableAnnotationComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoveryUserRelationsTableTableManager + extends + RootTableManager< + _$TwonlyDB, + $UserDiscoveryUserRelationsTable, + UserDiscoveryUserRelation, + $$UserDiscoveryUserRelationsTableFilterComposer, + $$UserDiscoveryUserRelationsTableOrderingComposer, + $$UserDiscoveryUserRelationsTableAnnotationComposer, + $$UserDiscoveryUserRelationsTableCreateCompanionBuilder, + $$UserDiscoveryUserRelationsTableUpdateCompanionBuilder, + ( + UserDiscoveryUserRelation, + $$UserDiscoveryUserRelationsTableReferences, + ), + UserDiscoveryUserRelation, + PrefetchHooks Function({bool announcedUserId, bool fromContactId}) + > { + $$UserDiscoveryUserRelationsTableTableManager( + _$TwonlyDB db, + $UserDiscoveryUserRelationsTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$UserDiscoveryUserRelationsTableFilterComposer( + $db: db, + $table: table, + ), + createOrderingComposer: () => + $$UserDiscoveryUserRelationsTableOrderingComposer( + $db: db, + $table: table, + ), + createComputedFieldComposer: () => + $$UserDiscoveryUserRelationsTableAnnotationComposer( + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + Value announcedUserId = const Value.absent(), + Value fromContactId = const Value.absent(), + Value publicKeyVerifiedTimestamp = + const Value.absent(), + Value rowid = const Value.absent(), + }) => UserDiscoveryUserRelationsCompanion( + announcedUserId: announcedUserId, + fromContactId: fromContactId, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp, + rowid: rowid, + ), + createCompanionCallback: + ({ + required int announcedUserId, + required int fromContactId, + Value publicKeyVerifiedTimestamp = + const Value.absent(), + Value rowid = const Value.absent(), + }) => UserDiscoveryUserRelationsCompanion.insert( + announcedUserId: announcedUserId, + fromContactId: fromContactId, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$UserDiscoveryUserRelationsTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({announcedUserId = false, fromContactId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (announcedUserId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.announcedUserId, + referencedTable: + $$UserDiscoveryUserRelationsTableReferences + ._announcedUserIdTable(db), + referencedColumn: + $$UserDiscoveryUserRelationsTableReferences + ._announcedUserIdTable(db) + .announcedUserId, + ) + as T; + } + if (fromContactId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.fromContactId, + referencedTable: + $$UserDiscoveryUserRelationsTableReferences + ._fromContactIdTable(db), + referencedColumn: + $$UserDiscoveryUserRelationsTableReferences + ._fromContactIdTable(db) + .userId, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + ), + ); +} + +typedef $$UserDiscoveryUserRelationsTableProcessedTableManager = + ProcessedTableManager< + _$TwonlyDB, + $UserDiscoveryUserRelationsTable, + UserDiscoveryUserRelation, + $$UserDiscoveryUserRelationsTableFilterComposer, + $$UserDiscoveryUserRelationsTableOrderingComposer, + $$UserDiscoveryUserRelationsTableAnnotationComposer, + $$UserDiscoveryUserRelationsTableCreateCompanionBuilder, + $$UserDiscoveryUserRelationsTableUpdateCompanionBuilder, + (UserDiscoveryUserRelation, $$UserDiscoveryUserRelationsTableReferences), + UserDiscoveryUserRelation, + PrefetchHooks Function({bool announcedUserId, bool fromContactId}) + >; +typedef $$UserDiscoveryOtherPromotionsTableCreateCompanionBuilder = + UserDiscoveryOtherPromotionsCompanion Function({ + required int fromContactId, + required int promotionId, + required int publicId, + required int threshold, + required Uint8List announcementShare, + Value publicKeyVerifiedTimestamp, + Value rowid, + }); +typedef $$UserDiscoveryOtherPromotionsTableUpdateCompanionBuilder = + UserDiscoveryOtherPromotionsCompanion Function({ + Value fromContactId, + Value promotionId, + Value publicId, + Value threshold, + Value announcementShare, + Value publicKeyVerifiedTimestamp, + Value rowid, + }); + +final class $$UserDiscoveryOtherPromotionsTableReferences + extends + BaseReferences< + _$TwonlyDB, + $UserDiscoveryOtherPromotionsTable, + UserDiscoveryOtherPromotion + > { + $$UserDiscoveryOtherPromotionsTableReferences( + super.$_db, + super.$_table, + super.$_typedResult, + ); + + static $ContactsTable _fromContactIdTable(_$TwonlyDB db) => + db.contacts.createAlias( + $_aliasNameGenerator( + db.userDiscoveryOtherPromotions.fromContactId, + db.contacts.userId, + ), + ); + + $$ContactsTableProcessedTableManager get fromContactId { + final $_column = $_itemColumn('from_contact_id')!; + + final manager = $$ContactsTableTableManager( + $_db, + $_db.contacts, + ).filter((f) => f.userId.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_fromContactIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$UserDiscoveryOtherPromotionsTableFilterComposer + extends Composer<_$TwonlyDB, $UserDiscoveryOtherPromotionsTable> { + $$UserDiscoveryOtherPromotionsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get promotionId => $composableBuilder( + column: $table.promotionId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get publicId => $composableBuilder( + column: $table.publicId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get threshold => $composableBuilder( + column: $table.threshold, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get announcementShare => $composableBuilder( + column: $table.announcementShare, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get publicKeyVerifiedTimestamp => $composableBuilder( + column: $table.publicKeyVerifiedTimestamp, + builder: (column) => ColumnFilters(column), + ); + + $$ContactsTableFilterComposer get fromContactId { + final $$ContactsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.fromContactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableFilterComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoveryOtherPromotionsTableOrderingComposer + extends Composer<_$TwonlyDB, $UserDiscoveryOtherPromotionsTable> { + $$UserDiscoveryOtherPromotionsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get promotionId => $composableBuilder( + column: $table.promotionId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get publicId => $composableBuilder( + column: $table.publicId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get threshold => $composableBuilder( + column: $table.threshold, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get announcementShare => $composableBuilder( + column: $table.announcementShare, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get publicKeyVerifiedTimestamp => + $composableBuilder( + column: $table.publicKeyVerifiedTimestamp, + builder: (column) => ColumnOrderings(column), + ); + + $$ContactsTableOrderingComposer get fromContactId { + final $$ContactsTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.fromContactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableOrderingComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoveryOtherPromotionsTableAnnotationComposer + extends Composer<_$TwonlyDB, $UserDiscoveryOtherPromotionsTable> { + $$UserDiscoveryOtherPromotionsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get promotionId => $composableBuilder( + column: $table.promotionId, + builder: (column) => column, + ); + + GeneratedColumn get publicId => + $composableBuilder(column: $table.publicId, builder: (column) => column); + + GeneratedColumn get threshold => + $composableBuilder(column: $table.threshold, builder: (column) => column); + + GeneratedColumn get announcementShare => $composableBuilder( + column: $table.announcementShare, + builder: (column) => column, + ); + + GeneratedColumn get publicKeyVerifiedTimestamp => + $composableBuilder( + column: $table.publicKeyVerifiedTimestamp, + builder: (column) => column, + ); + + $$ContactsTableAnnotationComposer get fromContactId { + final $$ContactsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.fromContactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableAnnotationComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoveryOtherPromotionsTableTableManager + extends + RootTableManager< + _$TwonlyDB, + $UserDiscoveryOtherPromotionsTable, + UserDiscoveryOtherPromotion, + $$UserDiscoveryOtherPromotionsTableFilterComposer, + $$UserDiscoveryOtherPromotionsTableOrderingComposer, + $$UserDiscoveryOtherPromotionsTableAnnotationComposer, + $$UserDiscoveryOtherPromotionsTableCreateCompanionBuilder, + $$UserDiscoveryOtherPromotionsTableUpdateCompanionBuilder, + ( + UserDiscoveryOtherPromotion, + $$UserDiscoveryOtherPromotionsTableReferences, + ), + UserDiscoveryOtherPromotion, + PrefetchHooks Function({bool fromContactId}) + > { + $$UserDiscoveryOtherPromotionsTableTableManager( + _$TwonlyDB db, + $UserDiscoveryOtherPromotionsTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$UserDiscoveryOtherPromotionsTableFilterComposer( + $db: db, + $table: table, + ), + createOrderingComposer: () => + $$UserDiscoveryOtherPromotionsTableOrderingComposer( + $db: db, + $table: table, + ), + createComputedFieldComposer: () => + $$UserDiscoveryOtherPromotionsTableAnnotationComposer( + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + Value fromContactId = const Value.absent(), + Value promotionId = const Value.absent(), + Value publicId = const Value.absent(), + Value threshold = const Value.absent(), + Value announcementShare = const Value.absent(), + Value publicKeyVerifiedTimestamp = + const Value.absent(), + Value rowid = const Value.absent(), + }) => UserDiscoveryOtherPromotionsCompanion( + fromContactId: fromContactId, + promotionId: promotionId, + publicId: publicId, + threshold: threshold, + announcementShare: announcementShare, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp, + rowid: rowid, + ), + createCompanionCallback: + ({ + required int fromContactId, + required int promotionId, + required int publicId, + required int threshold, + required Uint8List announcementShare, + Value publicKeyVerifiedTimestamp = + const Value.absent(), + Value rowid = const Value.absent(), + }) => UserDiscoveryOtherPromotionsCompanion.insert( + fromContactId: fromContactId, + promotionId: promotionId, + publicId: publicId, + threshold: threshold, + announcementShare: announcementShare, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$UserDiscoveryOtherPromotionsTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({fromContactId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (fromContactId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.fromContactId, + referencedTable: + $$UserDiscoveryOtherPromotionsTableReferences + ._fromContactIdTable(db), + referencedColumn: + $$UserDiscoveryOtherPromotionsTableReferences + ._fromContactIdTable(db) + .userId, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + ), + ); +} + +typedef $$UserDiscoveryOtherPromotionsTableProcessedTableManager = + ProcessedTableManager< + _$TwonlyDB, + $UserDiscoveryOtherPromotionsTable, + UserDiscoveryOtherPromotion, + $$UserDiscoveryOtherPromotionsTableFilterComposer, + $$UserDiscoveryOtherPromotionsTableOrderingComposer, + $$UserDiscoveryOtherPromotionsTableAnnotationComposer, + $$UserDiscoveryOtherPromotionsTableCreateCompanionBuilder, + $$UserDiscoveryOtherPromotionsTableUpdateCompanionBuilder, + ( + UserDiscoveryOtherPromotion, + $$UserDiscoveryOtherPromotionsTableReferences, + ), + UserDiscoveryOtherPromotion, + PrefetchHooks Function({bool fromContactId}) + >; +typedef $$UserDiscoveryOwnPromotionsTableCreateCompanionBuilder = + UserDiscoveryOwnPromotionsCompanion Function({ + Value versionId, + required int contactId, + required Uint8List promotion, + }); +typedef $$UserDiscoveryOwnPromotionsTableUpdateCompanionBuilder = + UserDiscoveryOwnPromotionsCompanion Function({ + Value versionId, + Value contactId, + Value promotion, + }); + +final class $$UserDiscoveryOwnPromotionsTableReferences + extends + BaseReferences< + _$TwonlyDB, + $UserDiscoveryOwnPromotionsTable, + UserDiscoveryOwnPromotion + > { + $$UserDiscoveryOwnPromotionsTableReferences( + super.$_db, + super.$_table, + super.$_typedResult, + ); + + static $ContactsTable _contactIdTable(_$TwonlyDB db) => + db.contacts.createAlias( + $_aliasNameGenerator( + db.userDiscoveryOwnPromotions.contactId, + db.contacts.userId, + ), + ); + + $$ContactsTableProcessedTableManager get contactId { + final $_column = $_itemColumn('contact_id')!; + + final manager = $$ContactsTableTableManager( + $_db, + $_db.contacts, + ).filter((f) => f.userId.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_contactIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$UserDiscoveryOwnPromotionsTableFilterComposer + extends Composer<_$TwonlyDB, $UserDiscoveryOwnPromotionsTable> { + $$UserDiscoveryOwnPromotionsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get versionId => $composableBuilder( + column: $table.versionId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get promotion => $composableBuilder( + column: $table.promotion, + builder: (column) => ColumnFilters(column), + ); + + $$ContactsTableFilterComposer get contactId { + final $$ContactsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.contactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableFilterComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoveryOwnPromotionsTableOrderingComposer + extends Composer<_$TwonlyDB, $UserDiscoveryOwnPromotionsTable> { + $$UserDiscoveryOwnPromotionsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get versionId => $composableBuilder( + column: $table.versionId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get promotion => $composableBuilder( + column: $table.promotion, + builder: (column) => ColumnOrderings(column), + ); + + $$ContactsTableOrderingComposer get contactId { + final $$ContactsTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.contactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableOrderingComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoveryOwnPromotionsTableAnnotationComposer + extends Composer<_$TwonlyDB, $UserDiscoveryOwnPromotionsTable> { + $$UserDiscoveryOwnPromotionsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get versionId => + $composableBuilder(column: $table.versionId, builder: (column) => column); + + GeneratedColumn get promotion => + $composableBuilder(column: $table.promotion, builder: (column) => column); + + $$ContactsTableAnnotationComposer get contactId { + final $$ContactsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.contactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableAnnotationComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoveryOwnPromotionsTableTableManager + extends + RootTableManager< + _$TwonlyDB, + $UserDiscoveryOwnPromotionsTable, + UserDiscoveryOwnPromotion, + $$UserDiscoveryOwnPromotionsTableFilterComposer, + $$UserDiscoveryOwnPromotionsTableOrderingComposer, + $$UserDiscoveryOwnPromotionsTableAnnotationComposer, + $$UserDiscoveryOwnPromotionsTableCreateCompanionBuilder, + $$UserDiscoveryOwnPromotionsTableUpdateCompanionBuilder, + ( + UserDiscoveryOwnPromotion, + $$UserDiscoveryOwnPromotionsTableReferences, + ), + UserDiscoveryOwnPromotion, + PrefetchHooks Function({bool contactId}) + > { + $$UserDiscoveryOwnPromotionsTableTableManager( + _$TwonlyDB db, + $UserDiscoveryOwnPromotionsTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$UserDiscoveryOwnPromotionsTableFilterComposer( + $db: db, + $table: table, + ), + createOrderingComposer: () => + $$UserDiscoveryOwnPromotionsTableOrderingComposer( + $db: db, + $table: table, + ), + createComputedFieldComposer: () => + $$UserDiscoveryOwnPromotionsTableAnnotationComposer( + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + Value versionId = const Value.absent(), + Value contactId = const Value.absent(), + Value promotion = const Value.absent(), + }) => UserDiscoveryOwnPromotionsCompanion( + versionId: versionId, + contactId: contactId, + promotion: promotion, + ), + createCompanionCallback: + ({ + Value versionId = const Value.absent(), + required int contactId, + required Uint8List promotion, + }) => UserDiscoveryOwnPromotionsCompanion.insert( + versionId: versionId, + contactId: contactId, + promotion: promotion, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$UserDiscoveryOwnPromotionsTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({contactId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (contactId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.contactId, + referencedTable: + $$UserDiscoveryOwnPromotionsTableReferences + ._contactIdTable(db), + referencedColumn: + $$UserDiscoveryOwnPromotionsTableReferences + ._contactIdTable(db) + .userId, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + ), + ); +} + +typedef $$UserDiscoveryOwnPromotionsTableProcessedTableManager = + ProcessedTableManager< + _$TwonlyDB, + $UserDiscoveryOwnPromotionsTable, + UserDiscoveryOwnPromotion, + $$UserDiscoveryOwnPromotionsTableFilterComposer, + $$UserDiscoveryOwnPromotionsTableOrderingComposer, + $$UserDiscoveryOwnPromotionsTableAnnotationComposer, + $$UserDiscoveryOwnPromotionsTableCreateCompanionBuilder, + $$UserDiscoveryOwnPromotionsTableUpdateCompanionBuilder, + (UserDiscoveryOwnPromotion, $$UserDiscoveryOwnPromotionsTableReferences), + UserDiscoveryOwnPromotion, + PrefetchHooks Function({bool contactId}) + >; +typedef $$UserDiscoverySharesTableCreateCompanionBuilder = + UserDiscoverySharesCompanion Function({ + Value shareId, + required Uint8List share, + Value contactId, + }); +typedef $$UserDiscoverySharesTableUpdateCompanionBuilder = + UserDiscoverySharesCompanion Function({ + Value shareId, + Value share, + Value contactId, + }); + +final class $$UserDiscoverySharesTableReferences + extends + BaseReferences< + _$TwonlyDB, + $UserDiscoverySharesTable, + UserDiscoveryShare + > { + $$UserDiscoverySharesTableReferences( + super.$_db, + super.$_table, + super.$_typedResult, + ); + + static $ContactsTable _contactIdTable(_$TwonlyDB db) => + db.contacts.createAlias( + $_aliasNameGenerator( + db.userDiscoveryShares.contactId, + db.contacts.userId, + ), + ); + + $$ContactsTableProcessedTableManager? get contactId { + final $_column = $_itemColumn('contact_id'); + if ($_column == null) return null; + final manager = $$ContactsTableTableManager( + $_db, + $_db.contacts, + ).filter((f) => f.userId.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_contactIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$UserDiscoverySharesTableFilterComposer + extends Composer<_$TwonlyDB, $UserDiscoverySharesTable> { + $$UserDiscoverySharesTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get shareId => $composableBuilder( + column: $table.shareId, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get share => $composableBuilder( + column: $table.share, + builder: (column) => ColumnFilters(column), + ); + + $$ContactsTableFilterComposer get contactId { + final $$ContactsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.contactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableFilterComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoverySharesTableOrderingComposer + extends Composer<_$TwonlyDB, $UserDiscoverySharesTable> { + $$UserDiscoverySharesTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get shareId => $composableBuilder( + column: $table.shareId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get share => $composableBuilder( + column: $table.share, + builder: (column) => ColumnOrderings(column), + ); + + $$ContactsTableOrderingComposer get contactId { + final $$ContactsTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.contactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableOrderingComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoverySharesTableAnnotationComposer + extends Composer<_$TwonlyDB, $UserDiscoverySharesTable> { + $$UserDiscoverySharesTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get shareId => + $composableBuilder(column: $table.shareId, builder: (column) => column); + + GeneratedColumn get share => + $composableBuilder(column: $table.share, builder: (column) => column); + + $$ContactsTableAnnotationComposer get contactId { + final $$ContactsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.contactId, + referencedTable: $db.contacts, + getReferencedColumn: (t) => t.userId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$ContactsTableAnnotationComposer( + $db: $db, + $table: $db.contacts, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$UserDiscoverySharesTableTableManager + extends + RootTableManager< + _$TwonlyDB, + $UserDiscoverySharesTable, + UserDiscoveryShare, + $$UserDiscoverySharesTableFilterComposer, + $$UserDiscoverySharesTableOrderingComposer, + $$UserDiscoverySharesTableAnnotationComposer, + $$UserDiscoverySharesTableCreateCompanionBuilder, + $$UserDiscoverySharesTableUpdateCompanionBuilder, + (UserDiscoveryShare, $$UserDiscoverySharesTableReferences), + UserDiscoveryShare, + PrefetchHooks Function({bool contactId}) + > { + $$UserDiscoverySharesTableTableManager( + _$TwonlyDB db, + $UserDiscoverySharesTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$UserDiscoverySharesTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$UserDiscoverySharesTableOrderingComposer( + $db: db, + $table: table, + ), + createComputedFieldComposer: () => + $$UserDiscoverySharesTableAnnotationComposer( + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + Value shareId = const Value.absent(), + Value share = const Value.absent(), + Value contactId = const Value.absent(), + }) => UserDiscoverySharesCompanion( + shareId: shareId, + share: share, + contactId: contactId, + ), + createCompanionCallback: + ({ + Value shareId = const Value.absent(), + required Uint8List share, + Value contactId = const Value.absent(), + }) => UserDiscoverySharesCompanion.insert( + shareId: shareId, + share: share, + contactId: contactId, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$UserDiscoverySharesTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({contactId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (contactId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.contactId, + referencedTable: + $$UserDiscoverySharesTableReferences + ._contactIdTable(db), + referencedColumn: + $$UserDiscoverySharesTableReferences + ._contactIdTable(db) + .userId, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + ), + ); +} + +typedef $$UserDiscoverySharesTableProcessedTableManager = + ProcessedTableManager< + _$TwonlyDB, + $UserDiscoverySharesTable, + UserDiscoveryShare, + $$UserDiscoverySharesTableFilterComposer, + $$UserDiscoverySharesTableOrderingComposer, + $$UserDiscoverySharesTableAnnotationComposer, + $$UserDiscoverySharesTableCreateCompanionBuilder, + $$UserDiscoverySharesTableUpdateCompanionBuilder, + (UserDiscoveryShare, $$UserDiscoverySharesTableReferences), + UserDiscoveryShare, + PrefetchHooks Function({bool contactId}) + >; class $TwonlyDBManager { final _$TwonlyDB _db; @@ -16281,4 +21281,34 @@ class $TwonlyDBManager { $$MessageActionsTableTableManager(_db, _db.messageActions); $$GroupHistoriesTableTableManager get groupHistories => $$GroupHistoriesTableTableManager(_db, _db.groupHistories); + $$KeyVerificationsTableTableManager get keyVerifications => + $$KeyVerificationsTableTableManager(_db, _db.keyVerifications); + $$VerificationTokensTableTableManager get verificationTokens => + $$VerificationTokensTableTableManager(_db, _db.verificationTokens); + $$UserDiscoveryAnnouncedUsersTableTableManager + get userDiscoveryAnnouncedUsers => + $$UserDiscoveryAnnouncedUsersTableTableManager( + _db, + _db.userDiscoveryAnnouncedUsers, + ); + $$UserDiscoveryUserRelationsTableTableManager + get userDiscoveryUserRelations => + $$UserDiscoveryUserRelationsTableTableManager( + _db, + _db.userDiscoveryUserRelations, + ); + $$UserDiscoveryOtherPromotionsTableTableManager + get userDiscoveryOtherPromotions => + $$UserDiscoveryOtherPromotionsTableTableManager( + _db, + _db.userDiscoveryOtherPromotions, + ); + $$UserDiscoveryOwnPromotionsTableTableManager + get userDiscoveryOwnPromotions => + $$UserDiscoveryOwnPromotionsTableTableManager( + _db, + _db.userDiscoveryOwnPromotions, + ); + $$UserDiscoverySharesTableTableManager get userDiscoveryShares => + $$UserDiscoverySharesTableTableManager(_db, _db.userDiscoveryShares); } diff --git a/lib/src/database/twonly.db.steps.dart b/lib/src/database/twonly.db.steps.dart index d07f9b2b..85e6cec2 100644 --- a/lib/src/database/twonly.db.steps.dart +++ b/lib/src/database/twonly.db.steps.dart @@ -5823,6 +5823,662 @@ i1.GeneratedColumn _column_210(String aliasedName) => type: i1.DriftSqlType.int, $customConstraints: 'NULL', ); + +final class Schema12 extends i0.VersionedSchema { + Schema12({required super.database}) : super(version: 12); + @override + late final List entities = [ + contacts, + groups, + mediaFiles, + messages, + messageHistories, + reactions, + groupMembers, + receipts, + receivedReceipts, + signalIdentityKeyStores, + signalPreKeyStores, + signalSenderKeyStores, + signalSessionStores, + messageActions, + groupHistories, + keyVerifications, + verificationTokens, + userDiscoveryAnnouncedUsers, + userDiscoveryUserRelations, + userDiscoveryOtherPromotions, + userDiscoveryOwnPromotions, + userDiscoveryShares, + ]; + late final Shape39 contacts = Shape39( + source: i0.VersionedTable( + entityName: 'contacts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(user_id)'], + columns: [ + _column_106, + _column_107, + _column_108, + _column_109, + _column_110, + _column_111, + _column_112, + _column_113, + _column_114, + _column_115, + _column_116, + _column_117, + _column_118, + _column_211, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape23 groups = Shape23( + source: i0.VersionedTable( + entityName: 'groups', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_id)'], + columns: [ + _column_119, + _column_120, + _column_121, + _column_122, + _column_123, + _column_124, + _column_125, + _column_126, + _column_127, + _column_128, + _column_129, + _column_130, + _column_131, + _column_132, + _column_133, + _column_134, + _column_118, + _column_135, + _column_136, + _column_137, + _column_138, + _column_139, + _column_140, + _column_141, + _column_142, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape36 mediaFiles = Shape36( + source: i0.VersionedTable( + entityName: 'media_files', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(media_id)'], + columns: [ + _column_143, + _column_144, + _column_145, + _column_146, + _column_147, + _column_148, + _column_149, + _column_207, + _column_150, + _column_151, + _column_152, + _column_153, + _column_154, + _column_155, + _column_156, + _column_157, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape25 messages = Shape25( + source: i0.VersionedTable( + entityName: 'messages', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id)'], + columns: [ + _column_158, + _column_159, + _column_160, + _column_144, + _column_161, + _column_162, + _column_163, + _column_164, + _column_165, + _column_153, + _column_166, + _column_167, + _column_168, + _column_169, + _column_118, + _column_170, + _column_171, + _column_172, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape26 messageHistories = Shape26( + source: i0.VersionedTable( + entityName: 'message_histories', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_173, + _column_174, + _column_175, + _column_161, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape27 reactions = Shape27( + source: i0.VersionedTable( + entityName: 'reactions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id, sender_id, emoji)'], + columns: [_column_174, _column_176, _column_177, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape38 groupMembers = Shape38( + source: i0.VersionedTable( + entityName: 'group_members', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_id, contact_id)'], + columns: [ + _column_158, + _column_178, + _column_179, + _column_180, + _column_209, + _column_210, + _column_181, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape37 receipts = Shape37( + source: i0.VersionedTable( + entityName: 'receipts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(receipt_id)'], + columns: [ + _column_182, + _column_183, + _column_184, + _column_185, + _column_186, + _column_208, + _column_187, + _column_188, + _column_189, + _column_190, + _column_191, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape30 receivedReceipts = Shape30( + source: i0.VersionedTable( + entityName: 'received_receipts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(receipt_id)'], + columns: [_column_182, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape31 signalIdentityKeyStores = Shape31( + source: i0.VersionedTable( + entityName: 'signal_identity_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(device_id, name)'], + columns: [_column_192, _column_193, _column_194, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape32 signalPreKeyStores = Shape32( + source: i0.VersionedTable( + entityName: 'signal_pre_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(pre_key_id)'], + columns: [_column_195, _column_196, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape11 signalSenderKeyStores = Shape11( + source: i0.VersionedTable( + entityName: 'signal_sender_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(sender_key_name)'], + columns: [_column_197, _column_198], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape33 signalSessionStores = Shape33( + source: i0.VersionedTable( + entityName: 'signal_session_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(device_id, name)'], + columns: [_column_192, _column_193, _column_199, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape34 messageActions = Shape34( + source: i0.VersionedTable( + entityName: 'message_actions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id, contact_id, type)'], + columns: [_column_174, _column_183, _column_144, _column_200], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape35 groupHistories = Shape35( + source: i0.VersionedTable( + entityName: 'group_histories', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_history_id)'], + columns: [ + _column_201, + _column_158, + _column_202, + _column_203, + _column_204, + _column_205, + _column_206, + _column_144, + _column_200, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape40 keyVerifications = Shape40( + source: i0.VersionedTable( + entityName: 'key_verifications', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(contact_id)'], + columns: [_column_183, _column_144, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape41 verificationTokens = Shape41( + source: i0.VersionedTable( + entityName: 'verification_tokens', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_212, _column_213, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape42 userDiscoveryAnnouncedUsers = Shape42( + source: i0.VersionedTable( + entityName: 'user_discovery_announced_users', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(announced_user_id)'], + columns: [_column_214, _column_215, _column_216], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape43 userDiscoveryUserRelations = Shape43( + source: i0.VersionedTable( + entityName: 'user_discovery_user_relations', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(announced_user_id, from_contact_id)'], + columns: [_column_217, _column_218, _column_219], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape44 userDiscoveryOtherPromotions = Shape44( + source: i0.VersionedTable( + entityName: 'user_discovery_other_promotions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(from_contact_id, promotion_id)'], + columns: [ + _column_218, + _column_220, + _column_221, + _column_222, + _column_223, + _column_219, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape45 userDiscoveryOwnPromotions = Shape45( + source: i0.VersionedTable( + entityName: 'user_discovery_own_promotions', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_224, _column_183, _column_225], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape46 userDiscoveryShares = Shape46( + source: i0.VersionedTable( + entityName: 'user_discovery_shares', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_226, _column_227, _column_175], + attachedDatabase: database, + ), + alias: null, + ); +} + +class Shape39 extends i0.VersionedTable { + Shape39({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get userId => + columnsByName['user_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get username => + columnsByName['username']! as i1.GeneratedColumn; + i1.GeneratedColumn get displayName => + columnsByName['display_name']! as i1.GeneratedColumn; + i1.GeneratedColumn get nickName => + columnsByName['nick_name']! as i1.GeneratedColumn; + i1.GeneratedColumn get avatarSvgCompressed => + columnsByName['avatar_svg_compressed']! + as i1.GeneratedColumn; + i1.GeneratedColumn get senderProfileCounter => + columnsByName['sender_profile_counter']! as i1.GeneratedColumn; + i1.GeneratedColumn get accepted => + columnsByName['accepted']! as i1.GeneratedColumn; + i1.GeneratedColumn get deletedByUser => + columnsByName['deleted_by_user']! as i1.GeneratedColumn; + i1.GeneratedColumn get requested => + columnsByName['requested']! as i1.GeneratedColumn; + i1.GeneratedColumn get blocked => + columnsByName['blocked']! as i1.GeneratedColumn; + i1.GeneratedColumn get verified => + columnsByName['verified']! as i1.GeneratedColumn; + i1.GeneratedColumn get accountDeleted => + columnsByName['account_deleted']! as i1.GeneratedColumn; + i1.GeneratedColumn get createdAt => + columnsByName['created_at']! as i1.GeneratedColumn; + i1.GeneratedColumn get userDiscoveryVersion => + columnsByName['user_discovery_version']! + as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_211(String aliasedName) => + i1.GeneratedColumn( + 'user_discovery_version', + aliasedName, + true, + type: i1.DriftSqlType.blob, + $customConstraints: 'NULL', + ); + +class Shape40 extends i0.VersionedTable { + Shape40({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get contactId => + columnsByName['contact_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get type => + columnsByName['type']! as i1.GeneratedColumn; + i1.GeneratedColumn get createdAt => + columnsByName['created_at']! as i1.GeneratedColumn; +} + +class Shape41 extends i0.VersionedTable { + Shape41({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get tokenId => + columnsByName['token_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get token => + columnsByName['token']! as i1.GeneratedColumn; + i1.GeneratedColumn get createdAt => + columnsByName['created_at']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_212(String aliasedName) => + i1.GeneratedColumn( + 'token_id', + aliasedName, + false, + hasAutoIncrement: true, + type: i1.DriftSqlType.int, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); +i1.GeneratedColumn _column_213(String aliasedName) => + i1.GeneratedColumn( + 'token', + aliasedName, + false, + type: i1.DriftSqlType.blob, + $customConstraints: 'NOT NULL', + ); + +class Shape42 extends i0.VersionedTable { + Shape42({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get announcedUserId => + columnsByName['announced_user_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get announcedPublicKey => + columnsByName['announced_public_key']! + as i1.GeneratedColumn; + i1.GeneratedColumn get publicId => + columnsByName['public_id']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_214(String aliasedName) => + i1.GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: 'NOT NULL', + ); +i1.GeneratedColumn _column_215(String aliasedName) => + i1.GeneratedColumn( + 'announced_public_key', + aliasedName, + false, + type: i1.DriftSqlType.blob, + $customConstraints: 'NOT NULL', + ); +i1.GeneratedColumn _column_216(String aliasedName) => + i1.GeneratedColumn( + 'public_id', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: 'NOT NULL UNIQUE', + ); + +class Shape43 extends i0.VersionedTable { + Shape43({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get announcedUserId => + columnsByName['announced_user_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get fromContactId => + columnsByName['from_contact_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get publicKeyVerifiedTimestamp => + columnsByName['public_key_verified_timestamp']! + as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_217( + String aliasedName, +) => i1.GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: + 'NOT NULL REFERENCES user_discovery_announced_users(announced_user_id)ON DELETE CASCADE', +); +i1.GeneratedColumn _column_218(String aliasedName) => + i1.GeneratedColumn( + 'from_contact_id', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); +i1.GeneratedColumn _column_219(String aliasedName) => + i1.GeneratedColumn( + 'public_key_verified_timestamp', + aliasedName, + true, + type: i1.DriftSqlType.int, + $customConstraints: 'NULL', + ); + +class Shape44 extends i0.VersionedTable { + Shape44({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get fromContactId => + columnsByName['from_contact_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get promotionId => + columnsByName['promotion_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get publicId => + columnsByName['public_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get threshold => + columnsByName['threshold']! as i1.GeneratedColumn; + i1.GeneratedColumn get announcementShare => + columnsByName['announcement_share']! as i1.GeneratedColumn; + i1.GeneratedColumn get publicKeyVerifiedTimestamp => + columnsByName['public_key_verified_timestamp']! + as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_220(String aliasedName) => + i1.GeneratedColumn( + 'promotion_id', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: 'NOT NULL', + ); +i1.GeneratedColumn _column_221(String aliasedName) => + i1.GeneratedColumn( + 'public_id', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: 'NOT NULL', + ); +i1.GeneratedColumn _column_222(String aliasedName) => + i1.GeneratedColumn( + 'threshold', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: 'NOT NULL', + ); +i1.GeneratedColumn _column_223(String aliasedName) => + i1.GeneratedColumn( + 'announcement_share', + aliasedName, + false, + type: i1.DriftSqlType.blob, + $customConstraints: 'NOT NULL', + ); + +class Shape45 extends i0.VersionedTable { + Shape45({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get versionId => + columnsByName['version_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get contactId => + columnsByName['contact_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get promotion => + columnsByName['promotion']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_224(String aliasedName) => + i1.GeneratedColumn( + 'version_id', + aliasedName, + false, + hasAutoIncrement: true, + type: i1.DriftSqlType.int, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); +i1.GeneratedColumn _column_225(String aliasedName) => + i1.GeneratedColumn( + 'promotion', + aliasedName, + false, + type: i1.DriftSqlType.blob, + $customConstraints: 'NOT NULL', + ); + +class Shape46 extends i0.VersionedTable { + Shape46({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get shareId => + columnsByName['share_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get share => + columnsByName['share']! as i1.GeneratedColumn; + i1.GeneratedColumn get contactId => + columnsByName['contact_id']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_226(String aliasedName) => + i1.GeneratedColumn( + 'share_id', + aliasedName, + false, + hasAutoIncrement: true, + type: i1.DriftSqlType.int, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); +i1.GeneratedColumn _column_227(String aliasedName) => + i1.GeneratedColumn( + 'share', + aliasedName, + false, + type: i1.DriftSqlType.blob, + $customConstraints: 'NOT NULL', + ); i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema2 schema) from1To2, required Future Function(i1.Migrator m, Schema3 schema) from2To3, @@ -5834,6 +6490,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) { @@ -5887,6 +6544,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'); } @@ -5904,6 +6566,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( from1To2: from1To2, @@ -5916,5 +6579,6 @@ i1.OnUpgrade stepByStep({ from8To9: from8To9, from9To10: from9To10, from10To11: from10To11, + from11To12: from11To12, ), ); diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 918c3469..c792ed14 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -90,15 +90,6 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - [[package]] name = "autocfg" version = "1.5.0" @@ -244,15 +235,6 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror", -] - [[package]] name = "concurrent-queue" version = "2.5.0" @@ -323,12 +305,6 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -466,18 +442,6 @@ dependencies = [ "serde", ] -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - [[package]] name = "env_filter" version = "0.1.4" @@ -771,15 +735,6 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - [[package]] name = "hashbrown" version = "0.14.5" @@ -823,20 +778,6 @@ dependencies = [ "hashbrown 0.15.5", ] -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin", - "stable_deref_trait", -] - [[package]] name = "heck" version = "0.5.0" @@ -1390,19 +1331,6 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "heapless", - "serde", -] - [[package]] name = "potential_utf" version = "0.1.5" @@ -1508,14 +1436,16 @@ dependencies = [ "base64", "blahaj", "hmac 0.13.0", - "postcard", "pretty_env_logger", "prost", "prost-build", "rand 0.10.1", "serde", + "serde_json", "sha2 0.11.0", + "sqlx", "thiserror", + "tokio", "tracing", ] @@ -1653,11 +1583,13 @@ name = "rust_lib_twonly" version = "0.1.0" dependencies = [ "flutter_rust_bridge", + "parking_lot", "pretty_env_logger", "prost-build", "protocols", "rand 0.10.1", "sqlx", + "tempfile", "thiserror", "tokio", "tracing", @@ -1669,15 +1601,6 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - [[package]] name = "rustix" version = "1.1.4" diff --git a/rust/core/Cargo.toml b/rust/core/Cargo.toml index 1f76cb6f..25875329 100644 --- a/rust/core/Cargo.toml +++ b/rust/core/Cargo.toml @@ -22,9 +22,11 @@ tokio = { version = "1.44", features = ["full"] } tracing = "0.1.44" rand = "0.10.1" protocols = { path = "../protocols" } +parking_lot = "0.12.5" [dev-dependencies] pretty_env_logger = "0.5.0" +tempfile = "3.27.0" [build-dependencies] diff --git a/rust/core/src/bridge/error.rs b/rust/core/src/bridge/error.rs index 9838940e..b77e8f03 100644 --- a/rust/core/src/bridge/error.rs +++ b/rust/core/src/bridge/error.rs @@ -1,3 +1,4 @@ +use protocols::user_discovery::error::UserDiscoveryError; use thiserror::Error; pub type Result = core::result::Result; @@ -8,6 +9,12 @@ pub enum TwonlyError { Initialization, #[error("Could not find the given database")] DatabaseNotFound, - #[error("sqlx error")] + #[error("{0}")] SqliteError(#[from] sqlx::Error), } + +impl From for UserDiscoveryError { + fn from(error: TwonlyError) -> Self { + UserDiscoveryError::Store(error.to_string()) + } +} diff --git a/rust/core/src/bridge/mod.rs b/rust/core/src/bridge/mod.rs index fbcc08b4..fdb518dc 100644 --- a/rust/core/src/bridge/mod.rs +++ b/rust/core/src/bridge/mod.rs @@ -1,19 +1,24 @@ +#![allow(unexpected_cfgs)] pub mod error; -mod user_discovery; +mod user_discovery_utils; +use crate::bridge::user_discovery_utils::UserDiscoveryUtilsFlutter; use crate::database::contact::Contact; use crate::database::Database; +use crate::user_discovery_store::UserDiscoveryDatabaseStore; +use crate::utils::Shared; use error::Result; use error::TwonlyError; use flutter_rust_bridge::frb; +use protocols::user_discovery::UserDiscovery; use std::sync::Arc; use tokio::sync::OnceCell; -use protocols::user_discovery::traits::OtherPromotion; +pub use protocols::user_discovery::traits::OtherPromotion; #[frb(mirror(OtherPromotion))] pub struct _OtherPromotion { pub promotion_id: u32, - pub public_id: u64, + pub public_id: i64, pub from_contact_id: i64, pub threshold: u8, pub announcement_share: Vec, @@ -22,26 +27,33 @@ pub struct _OtherPromotion { pub struct TwonlyConfig { pub database_path: String, + pub data_directory: String, } pub(crate) struct Twonly { #[allow(dead_code)] pub(crate) config: TwonlyConfig, pub(crate) database: Arc, + pub(crate) user_discovery: + Shared>>, } static GLOBAL_TWONLY: OnceCell = OnceCell::const_new(); -fn get_instance() -> Result<&'static Twonly> { +pub(crate) fn get_workspace() -> Result<&'static Twonly> { GLOBAL_TWONLY.get().ok_or(TwonlyError::Initialization) } pub async fn initialize_twonly(config: TwonlyConfig) -> Result<()> { - println!("initialized twonly"); + tracing::debug!("Initialized twonly workspace."); let twonly_res: Result<&'static Twonly> = GLOBAL_TWONLY .get_or_try_init(|| async { let database = Arc::new(Database::new(&config.database_path).await?); - Ok(Twonly { config, database }) + Ok(Twonly { + config, + database, + user_discovery: Shared::default(), + }) }) .await; @@ -51,7 +63,7 @@ pub async fn initialize_twonly(config: TwonlyConfig) -> Result<()> { } pub async fn get_all_contacts() -> Result> { - let twonly = get_instance()?; + let twonly = get_workspace()?; Contact::get_all_contacts(twonly.database.as_ref()).await } @@ -61,35 +73,90 @@ pub fn load_promotions() -> OtherPromotion { #[cfg(test)] pub(crate) mod tests { + use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; + use tempfile::{NamedTempFile, TempDir}; + use tokio::sync::OnceCell; + + use crate::{database::Database, utils::Shared}; + use super::error::Result; use super::Twonly; - use std::path::PathBuf; + use std::{path::PathBuf, sync::Arc}; + use tokio::sync::Mutex; - use super::{get_instance, initialize_twonly, TwonlyConfig}; + use super::{get_workspace, initialize_twonly, TwonlyConfig}; - pub(crate) async fn initialize_twonly_for_testing() -> Result<&'static Twonly> { + static TWONLY_TESTING: [OnceCell; 10] = [ + OnceCell::const_new(), + OnceCell::const_new(), + OnceCell::const_new(), + OnceCell::const_new(), + OnceCell::const_new(), + OnceCell::const_new(), + OnceCell::const_new(), + OnceCell::const_new(), + OnceCell::const_new(), + OnceCell::const_new(), + ]; + + static TWONLY_TESTING_INDEX: OnceCell>> = OnceCell::const_new(); + + pub(crate) async fn initialize_twonly_for_testing(use_global: bool) -> Result<&'static Twonly> { let default_twonly_database = PathBuf::from("tests/testing.db"); if !default_twonly_database.is_file() { panic!("{} not found!", default_twonly_database.display()) } - let copied_twonly_database = default_twonly_database - .parent() - .unwrap() - .join("tmp_testing.db"); - if copied_twonly_database.exists() { - std::fs::remove_file(&copied_twonly_database).unwrap(); + let temp_file = NamedTempFile::new().unwrap().path().to_owned(); + + tracing::info!("Crated db copy: {}", temp_file.display()); + + let conn = SqlitePoolOptions::new() + .connect_with( + format!("sqlite://{}", default_twonly_database.display()) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + + let path_str = temp_file.display().to_string(); + sqlx::query("VACUUM INTO $1") + .bind(path_str) + .execute(&conn) + .await + .expect("Failed to backup database"); + + let tmp_dir = TempDir::new().unwrap().path().to_owned(); + std::fs::create_dir_all(&tmp_dir).unwrap(); + let config = TwonlyConfig { + database_path: temp_file.display().to_string(), + data_directory: tmp_dir.to_str().unwrap().to_string(), + }; + + if use_global { + initialize_twonly(config).await.unwrap(); + + get_workspace() + } else { + let index = TWONLY_TESTING_INDEX + .get_or_init(|| async { Arc::default() }) + .await; + let mut index = index.lock().await; + let res: Result<&'static Twonly> = TWONLY_TESTING[*index] + .get_or_try_init(|| async { + let database = Arc::new(Database::new(&config.database_path).await?); + Ok(Twonly { + config, + database, + user_discovery: Shared::default(), + }) + }) + .await; + tracing::debug!("TWONLY_TESTING_INDEX: {index}"); + *index += 1; + res } - - std::fs::copy(default_twonly_database, &copied_twonly_database).unwrap(); - - initialize_twonly(TwonlyConfig { - database_path: copied_twonly_database.display().to_string(), - }) - .await - .unwrap(); - - get_instance() } } diff --git a/rust/core/src/bridge/user_discovery.rs b/rust/core/src/bridge/user_discovery.rs deleted file mode 100644 index 29e128ec..00000000 --- a/rust/core/src/bridge/user_discovery.rs +++ /dev/null @@ -1,72 +0,0 @@ -use protocols::user_discovery::error::{Result, UserDiscoveryError}; -use protocols::user_discovery::traits::{AnnouncedUser, OtherPromotion, UserDiscoveryStore}; -use protocols::user_discovery::UserID; -use std::collections::HashMap; - -struct UserDiscoveryDatabaseStore {} - -impl UserDiscoveryStore for UserDiscoveryDatabaseStore { - fn get_config(&self) -> Result> { - todo!() - } - - fn update_config(&self, update: Vec) -> Result<()> { - todo!() - } - - fn set_shares(&self, shares: Vec>) -> Result<()> { - todo!() - } - - fn get_share_for_contact(&self, contact_id: UserID) -> Result> { - todo!() - } - - fn push_own_promotion( - &self, - contact_id: UserID, - version: u32, - promotion: Vec, - ) -> Result<()> { - todo!() - } - - fn get_own_promotions_after_version(&self, version: u32) -> Result>> { - todo!() - } - - fn store_other_promotion(&self, promotion: OtherPromotion) -> Result<()> { - todo!() - } - - fn get_other_promotions_by_public_id(&self, public_id: u64) -> Vec { - todo!() - } - - fn get_announced_user_by_public_id(&self, public_id: u64) -> Result> { - todo!() - } - - fn push_new_user_relation( - &self, - from_contact_id: UserID, - announced_user: AnnouncedUser, - public_key_verified_timestamp: Option, - ) -> Result<()> { - todo!() - } - - fn get_all_announced_users( - &self, - ) -> Result)>>> { - todo!() - } - - fn get_contact_version(&self, contact_id: UserID) -> Result>> { - todo!() - } - - fn set_contact_version(&self, contact_id: UserID, update: Vec) -> Result<()> { - todo!() - } -} diff --git a/rust/core/src/bridge/user_discovery_utils.rs b/rust/core/src/bridge/user_discovery_utils.rs new file mode 100644 index 00000000..fe83916e --- /dev/null +++ b/rust/core/src/bridge/user_discovery_utils.rs @@ -0,0 +1,27 @@ +use protocols::user_discovery::error::Result; +use protocols::user_discovery::traits::UserDiscoveryUtils; + +pub(crate) struct UserDiscoveryUtilsFlutter {} + +impl UserDiscoveryUtils for UserDiscoveryUtilsFlutter { + async fn sign_data(&self, input_data: &[u8]) -> Result> { + todo!() + } + + async fn verify_signature( + &self, + input_data: &[u8], + pubkey: &[u8], + signature: &[u8], + ) -> Result { + todo!() + } + + async fn verify_stored_pubkey( + &self, + from_contact_id: protocols::user_discovery::UserID, + pubkey: &[u8], + ) -> Result { + todo!() + } +} diff --git a/rust/core/src/database/contact.rs b/rust/core/src/database/contact.rs index 710c199e..f6833366 100644 --- a/rust/core/src/database/contact.rs +++ b/rust/core/src/database/contact.rs @@ -43,11 +43,11 @@ mod tests { #[tokio::test] async fn test_get_all_contacts() { - let twonly = initialize_twonly_for_testing().await.unwrap(); + let twonly = initialize_twonly_for_testing(true).await.unwrap(); let contacts = Contact::get_all_contacts(&twonly.database).await.unwrap(); - let users = vec!["alice", "bob", "charlie", "diana", "eve", "frank", "grace"]; + let users = vec!["alice", "bob", "charlie", "david", "frank"]; assert_eq!(contacts.len(), users.len()); diff --git a/rust/core/src/frb_generated.rs b/rust/core/src/frb_generated.rs index 536a9884..6a960195 100644 --- a/rust/core/src/frb_generated.rs +++ b/rust/core/src/frb_generated.rs @@ -156,7 +156,7 @@ fn wire__crate__bridge__load_promotions_impl( const _: fn() = || { let OtherPromotion = None::.unwrap(); let _: u32 = OtherPromotion.promotion_id; - let _: u64 = OtherPromotion.public_id; + let _: i64 = OtherPromotion.public_id; let _: i64 = OtherPromotion.from_contact_id; let _: u8 = OtherPromotion.threshold; let _: Vec = OtherPromotion.announcement_share; @@ -241,7 +241,7 @@ impl SseDecode for crate::bridge::OtherPromotion { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { let mut var_promotionId = ::sse_decode(deserializer); - let mut var_publicId = ::sse_decode(deserializer); + let mut var_publicId = ::sse_decode(deserializer); let mut var_fromContactId = ::sse_decode(deserializer); let mut var_threshold = ::sse_decode(deserializer); let mut var_announcementShare = >::sse_decode(deserializer); @@ -261,8 +261,10 @@ impl SseDecode for crate::bridge::TwonlyConfig { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { let mut var_databasePath = ::sse_decode(deserializer); + let mut var_dataDirectory = ::sse_decode(deserializer); return crate::bridge::TwonlyConfig { database_path: var_databasePath, + data_directory: var_dataDirectory, }; } } @@ -274,13 +276,6 @@ impl SseDecode for u32 { } } -impl SseDecode for u64 { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { - deserializer.cursor.read_u64::().unwrap() - } -} - impl SseDecode for u8 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -389,7 +384,11 @@ impl flutter_rust_bridge::IntoIntoDart // Codec=Dco (DartCObject based), see doc to use other codecs impl flutter_rust_bridge::IntoDart for crate::bridge::TwonlyConfig { fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { - [self.database_path.into_into_dart().into_dart()].into_dart() + [ + self.database_path.into_into_dart().into_dart(), + self.data_directory.into_into_dart().into_dart(), + ] + .into_dart() } } impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::bridge::TwonlyConfig {} @@ -464,7 +463,7 @@ impl SseEncode for crate::bridge::OtherPromotion { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { ::sse_encode(self.promotion_id, serializer); - ::sse_encode(self.public_id, serializer); + ::sse_encode(self.public_id, serializer); ::sse_encode(self.from_contact_id, serializer); ::sse_encode(self.threshold, serializer); >::sse_encode(self.announcement_share, serializer); @@ -476,6 +475,7 @@ impl SseEncode for crate::bridge::TwonlyConfig { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { ::sse_encode(self.database_path, serializer); + ::sse_encode(self.data_directory, serializer); } } @@ -486,13 +486,6 @@ impl SseEncode for u32 { } } -impl SseEncode for u64 { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { - serializer.cursor.write_u64::(self).unwrap(); - } -} - impl SseEncode for u8 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { diff --git a/rust/core/src/lib.rs b/rust/core/src/lib.rs index ac8b48f8..519a5714 100644 --- a/rust/core/src/lib.rs +++ b/rust/core/src/lib.rs @@ -1,3 +1,5 @@ pub mod bridge; mod database; mod frb_generated; +mod user_discovery_store; +mod utils; diff --git a/rust/core/src/user_discovery_store.rs b/rust/core/src/user_discovery_store.rs new file mode 100644 index 00000000..1cee04e1 --- /dev/null +++ b/rust/core/src/user_discovery_store.rs @@ -0,0 +1,349 @@ +#[allow(async_fn_in_trait)] +use protocols::user_discovery::error::{Result, UserDiscoveryError}; +use protocols::user_discovery::traits::{AnnouncedUser, OtherPromotion, UserDiscoveryStore}; +use protocols::user_discovery::UserID; +use sqlx::{QueryBuilder, Row, Sqlite, Transaction}; +use std::collections::HashMap; +use std::path::PathBuf; +use std::sync::Arc; + +use crate::bridge::error::TwonlyError; +use crate::bridge::{get_workspace, Twonly}; + +#[derive(Clone)] +pub(crate) struct UserDiscoveryDatabaseStore { + ws: Arc<&'static Twonly>, +} + +impl UserDiscoveryStore for UserDiscoveryDatabaseStore { + async fn new() -> Self { + #[cfg(test)] + return Self { + ws: Arc::new( + crate::bridge::tests::initialize_twonly_for_testing(false) + .await + .unwrap(), + ), + }; + #[allow(unreachable_code)] + Self { + ws: Arc::new(get_workspace().unwrap()), + } + } + async fn get_config(&self) -> Result { + let config_path = + PathBuf::from(&self.ws.config.data_directory).join("user_discovery_config.json"); + + if !config_path.is_file() { + return Err(UserDiscoveryError::NotInitialized); + } + + tracing::debug!("Loading Config from {}", config_path.display()); + Ok(std::fs::read_to_string(&config_path)?) + } + + async fn update_config(&self, update: String) -> Result<()> { + tracing::debug!("Updating configuration file."); + let config_path = + PathBuf::from(&self.ws.config.data_directory).join("user_discovery_config.json"); + std::fs::write(config_path, &update)?; + Ok(()) + } + + async fn set_shares(&self, shares: Vec>) -> Result<()> { + let mut query_builder: QueryBuilder = + QueryBuilder::new("INSERT INTO user_discovery_shares (share) "); + + query_builder.push_values(shares, |mut b, share| { + b.push_bind(share); + }); + + query_builder + .build() + .execute(&self.ws.database.pool) + .await + .map_err(TwonlyError::from)?; + + Ok(()) + } + + async fn get_share_for_contact(&self, contact_id: UserID) -> Result> { + let mut tx: Transaction<'_, Sqlite> = self + .ws + .database + .pool + .begin() + .await + .map_err(TwonlyError::from)?; + + // 1. Check if the user already has a share assigned + let existing: Option> = + sqlx::query_scalar("SELECT share FROM user_discovery_shares WHERE contact_id = ?") + .bind(contact_id) + .fetch_optional(&mut *tx) + .await + .map_err(TwonlyError::from)?; + + if let Some(share) = existing { + tx.commit().await.map_err(TwonlyError::from)?; + return Ok(share); + } + + // 2. No share found. Try to assign an available one (where contact_id is NULL) + let rows_affected = sqlx::query( + "UPDATE user_discovery_shares + SET contact_id = ? + WHERE share_id = ( + SELECT share_id FROM user_discovery_shares + WHERE contact_id IS NULL + LIMIT 1 + )", + ) + .bind(contact_id) + .execute(&mut *tx) + .await + .map_err(TwonlyError::from)? + .rows_affected(); + + if rows_affected == 0 { + return Err(UserDiscoveryError::NoSharesLeft); + } + + // 3. Retrieve the newly assigned share + let assigned_share: Vec = + sqlx::query_scalar("SELECT share FROM user_discovery_shares WHERE contact_id = ?") + .bind(contact_id) + .fetch_one(&mut *tx) + .await + .map_err(TwonlyError::from)?; + + tx.commit().await.map_err(TwonlyError::from)?; + Ok(assigned_share) + } + + async fn push_own_promotion( + &self, + contact_id: UserID, + version: u32, + promotion: Vec, + ) -> Result<()> { + sqlx::query( + r#" + INSERT INTO user_discovery_own_promotions (contact_id, promotion, version_id) + VALUES (?1, ?2, ?3) + "#, + ) + .bind(contact_id) + .bind(promotion) + .bind(version as i64) // SQLite integers are usually i32/i64 + .execute(&self.ws.database.pool) + .await + .map_err(TwonlyError::from)?; + Ok(()) + } + + async fn get_own_promotions_after_version(&self, version: u32) -> Result>> { + let promotions: Vec> = sqlx::query_scalar( + "SELECT promotion FROM user_discovery_own_promotions + WHERE version_id > ? + ORDER BY version_id ASC", + ) + .bind(version as i64) + .fetch_all(&self.ws.database.pool) + .await + .map_err(TwonlyError::from)?; + Ok(promotions) + } + + async fn store_other_promotion(&self, promotion: OtherPromotion) -> Result<()> { + sqlx::query( + r" + INSERT INTO user_discovery_other_promotions ( + from_contact_id, + promotion_id, + public_id, + threshold, + announcement_share, + public_key_verified_timestamp + ) + VALUES (?1, ?2, ?3, ?4, ?5, ?6) + ", + ) + .bind(promotion.from_contact_id) + .bind(promotion.promotion_id as i64) + .bind(promotion.public_id) + .bind(promotion.threshold as i64) + .bind(promotion.announcement_share) + .bind(promotion.public_key_verified_timestamp) // Option maps to NULLable + .execute(&self.ws.database.pool) + .await + .map_err(TwonlyError::from)?; + + Ok(()) + } + + async fn get_other_promotions_by_public_id( + &self, + public_id: i64, + ) -> Result> { + let promotions = sqlx::query_as::<_, OtherPromotion>( + "SELECT * FROM user_discovery_other_promotions WHERE public_id = ?", + ) + .bind(public_id) + .fetch_all(&self.ws.database.pool) + .await + .map_err(TwonlyError::from)?; + Ok(promotions) + } + + async fn get_announced_user_by_public_id( + &self, + public_id: i64, + ) -> Result> { + let row = sqlx::query("SELECT * FROM user_discovery_announced_users WHERE public_id = ?") + .bind(public_id) + .fetch_optional(&self.ws.database.pool) + .await + .map_err(TwonlyError::from)?; + match row { + Some(r) => Ok(Some(AnnouncedUser { + user_id: r.get::("announced_user_id"), + public_key: r.get::, _>("announced_public_key"), + public_id: r.get::("public_id"), + })), + None => Ok(None), + } + } + + async fn push_new_user_relation( + &self, + from_contact_id: UserID, + announced_user: AnnouncedUser, + public_key_verified_timestamp: Option, + ) -> Result<()> { + let mut tx = self + .ws + .database + .pool + .begin() + .await + .map_err(TwonlyError::from)?; + + sqlx::query( + r" + INSERT INTO user_discovery_announced_users (announced_user_id, announced_public_key, public_id) + VALUES (?1, ?2, ?3) + ON CONFLICT(announced_user_id) DO NOTHING + ") + .bind(announced_user.user_id) + .bind(announced_user.public_key) + .bind(announced_user.public_id) + .execute(&mut *tx) + .await.map_err(TwonlyError::from)?; + + if from_contact_id != announced_user.user_id { + tracing::debug!( + "INSERTING THAT {} KNOWS {}", + from_contact_id, + announced_user.user_id + ); + sqlx::query( + r"INSERT INTO user_discovery_user_relations ( + announced_user_id, + from_contact_id, + public_key_verified_timestamp + ) + VALUES (?1, ?2, ?3) + ON CONFLICT(announced_user_id, from_contact_id) DO UPDATE SET + public_key_verified_timestamp = excluded.public_key_verified_timestamp + ", + ) + .bind(announced_user.user_id) + .bind(from_contact_id) + .bind(public_key_verified_timestamp) + .execute(&mut *tx) + .await + .map_err(TwonlyError::from)?; + } + + tx.commit().await.map_err(TwonlyError::from)?; + + Ok(()) + } + + async fn get_all_announced_users( + &self, + ) -> Result)>>> { + let rows = sqlx::query( + r#" + SELECT + u.announced_user_id, + u.announced_public_key, + u.public_id, + r.from_contact_id, + r.public_key_verified_timestamp + FROM user_discovery_announced_users u + LEFT JOIN user_discovery_user_relations r + ON u.announced_user_id = r.announced_user_id + ORDER BY u.announced_user_id + "#, + ) + .fetch_all(&self.ws.database.pool) + .await + .map_err(TwonlyError::from)?; + + let mut map: HashMap)>> = HashMap::new(); + + for row in rows { + let announced_user = AnnouncedUser { + user_id: row.get::("announced_user_id"), + public_key: row.get::, _>("announced_public_key"), + public_id: row.get::("public_id"), + }; + + let relations_list = map.entry(announced_user).or_insert_with(Vec::new); + + // SQLX returns NULL for columns in a LEFT JOIN where no match is found. + if let Ok(Some(contact_id)) = row.try_get::, _>("from_contact_id") { + let timestamp = row.get::, _>("public_key_verified_timestamp"); + relations_list.push((contact_id, timestamp)); + } + } + + Ok(map) + } + + async fn get_contact_version(&self, contact_id: UserID) -> Result>> { + let version: Option> = + sqlx::query_scalar("SELECT user_discovery_version FROM contacts WHERE user_id = ?") + .bind(contact_id) + .fetch_optional(&self.ws.database.pool) + .await + .map_err(TwonlyError::from)?; + + Ok(version) + } + + async fn set_contact_version(&self, contact_id: UserID, update: Vec) -> Result<()> { + sqlx::query("UPDATE contacts SET user_discovery_version = ? WHERE user_id = ?") + .bind(update) + .bind(contact_id) + .execute(&self.ws.database.pool) + .await + .map_err(TwonlyError::from)?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::user_discovery_store::UserDiscoveryDatabaseStore; + use protocols::user_discovery::tests::test_initialize_user_discovery; + + #[tokio::test] + async fn test_initialize_user_discovery_database_store() { + let _ = pretty_env_logger::try_init(); + test_initialize_user_discovery::().await; + } +} diff --git a/rust/core/src/utils.rs b/rust/core/src/utils.rs new file mode 100644 index 00000000..7ec8da6d --- /dev/null +++ b/rust/core/src/utils.rs @@ -0,0 +1,22 @@ +use parking_lot::{RwLock, RwLockReadGuard}; +use std::sync::Arc; + +#[derive(Default, Clone)] +pub(crate) struct Shared(Arc>); +impl Shared +where + T: Clone, +{ + pub(crate) fn new(value: T) -> Self { + Self(Arc::new(RwLock::new(value))) + } + pub(crate) fn get(&self) -> RwLockReadGuard<'_, T> { + self.0.read() + } + pub(crate) fn cloned(&self) -> T { + self.0.read().clone() + } + pub(crate) fn set(&self, value: T) { + *self.0.write() = value; + } +} diff --git a/rust/core/tests/testing.db b/rust/core/tests/testing.db index df0d8a5baf3e0f4458a74ca7baa6b4a04e138e4c..8f6fbb2e942fc8ef7853bb86f92fb6c7c2aa3a85 100644 GIT binary patch delta 2108 zcmah~U2NM_7`-=6?6^tlma#aZP3vaumb7a#RG~_ngqlvF>YBBqw4e$hH%%PXYGSvs zvrNgm38ClEs7foe~@A@(vMq^V3oXyR{NJ4@0yQLtpk z_nz=xL$W0dd#pcC%y&5o73&;5g$73iZ&zR<( zd<$5xv%vlp{+<18Y#BR?kr;<~=EiOR`a3 ziinrFZ@&)h z7<3finMa-ZVK{sXGIO`!nU=n$p8y5#0qUUnm*$ThF-I$TVEvq2C(c&s=nfYY1(Zi4pv;TxnJo{w{joX&%f@sY5M$VfF4UFWBQf$1PK9T*7(8BY!F zVZ7?03}ed5o4g|;3UW9ivpVPfKbPTceE-W=AqA0>OoO?M-?abzDm*mh88}yf%p?EJ z;TDaK{=PG8c9O&rX#U4>=-9E{x9yO3$xZ75v6RcaNW?O!lLS391hd7?4Vxh$LvT{v z$-Zg^bz=|li_4%d8LvGC#Q8I`d;bA>E&_d!(CU} z*n_-)TwG3+*r)#|z?&U7LD1vlaO;J-gbnqK)t)opry8?1L~FcbNKRJgix=BgE^fQX z(~M^+HIF`Nv}4C@Xe2Kn11yMfg}LesgatuN2@x*A2{Nm1tU;l2I$Lox7iDEW!AWvB zv81$p(BairKH_ODskFC6kI#B=Ix$*LXI+OR7cYKRH7ZxbC$pX|-BerW>uFpaY*6?y z7<{}^PeXmHD{1PMl!~$%rrBS0q@bB1lGePIuS{;!+L>d~i>U{%!A0o1$+Y|j)Y#52 delta 524 zcmZp8z}3*eF+o~YoPmKs0f=FMAIM;Vaey=<5OYs#lou6e(Chud3gj{Ie*?)&@c-uj zwpmc2m0y;N2gv7S;RTZH{J{+T&-pL#Z{?rE-^!oEAH1>AmcL${jgJ9j69)vaq!%S7 zr)J*1dQqGeRU)k@F)te=AZK`s9qnqMS^y z9#KX;RI`%ulfZT}pqiDKlL>LuCIzMhk<|<=%u^Y79Br4vQHT5*9NW2&i*xW)NWf#lU}*XD3ew_d@PCE_u#V9J|@)a3rzGvj?&S zu|8n@#Ui}1@e<>9v0}!ZY#gBQ0Ahyi=PMcc8Mh18GQMZp{ACUg^W> = - std::sync::OnceLock::new(); - /// Type of the user id, this must be consistent with the user id defined in /// the types.proto pub type UserID = i64; @@ -29,13 +26,13 @@ struct UserDiscoveryConfig { /// The number of required shares to get the secret threshold: u8, /// Currently limited to <= 255 as GF 256 is used - total_number_of_shares: usize, + total_number_of_shares: u8, /// Version of announcements announcement_version: u32, /// Version of promotions promotion_version: u32, /// This is a random public_id associated with a single announcement. - public_id: u64, + public_id: i64, /// Verification shares verification_shares: Vec>, // The users' id: @@ -77,15 +74,15 @@ impl UserDiscovery, ) -> Result<()> { - let mut config = match self.store.get_config() { + let mut config = match self.store.get_config().await { Ok(config) => { - let mut config: UserDiscoveryConfig = from_bytes(&config)?; + let mut config: UserDiscoveryConfig = serde_json::from_str(&config)?; config.threshold = threshold; config } @@ -104,15 +101,19 @@ impl UserDiscovery UserDiscovery)` - The current version of the user discovery /// * `Err(UserDiscoveryError)` - If there where errors in the store. /// - pub fn get_current_version(&self) -> Result> { - let config = self.get_config()?; + pub async fn get_current_version(&self) -> Result> { + let config = self.get_config().await?; Ok(UserDiscoveryVersion { announcement: config.announcement_version, promotion: config.promotion_version, @@ -148,10 +149,10 @@ impl UserDiscovery)>>)` - All connections the user has discovered /// * `Err(UserDiscoveryError)` - If there where erros in the store. /// - pub fn get_all_announced_users( + pub async fn get_all_announced_users( &self, ) -> Result)>>> { - self.store.get_all_announced_users() + self.store.get_all_announced_users().await } /// @@ -167,7 +168,7 @@ impl UserDiscovery>)` - The new user discovery messages /// * `Err(UserDiscoveryError)` - If there where errors in the store or if the received version is invalid. /// - pub fn get_new_messages( + pub async fn get_new_messages( &self, contact_id: UserID, received_version: &[u8], @@ -175,7 +176,7 @@ impl UserDiscovery UserDiscovery UserDiscovery UserDiscovery Result { + pub async fn should_request_new_messages( + &self, + contact_id: UserID, + version: &[u8], + ) -> Result { let received_version = UserDiscoveryVersion::decode(version)?; - let stored_version = match self.store.get_contact_version(contact_id)? { + let stored_version = match self.store.get_contact_version(contact_id).await? { Some(buf) => UserDiscoveryVersion::decode(buf.as_slice())?, None => UserDiscoveryVersion { announcement: 0, promotion: 0, }, }; + tracing::debug!( + received.announcement = %received_version.announcement, + received.promotion = %received_version.promotion, + stored.announcement = %stored_version.announcement, + stored.promotion = %stored_version.promotion, + "Comparing version numbers" + ); Ok(received_version.announcement > stored_version.announcement || received_version.promotion > stored_version.promotion) } - #[cfg(test)] - pub(crate) fn get_contact_version(&self, contact_id: UserID) -> Result>> { - self.store.get_contact_version(contact_id) + pub(crate) async fn get_contact_version(&self, contact_id: UserID) -> Result>> { + self.store.get_contact_version(contact_id).await } /// Returns the latest version for this discovery. /// Before calling this function the application must sure that contact_id is qualified to be announced. - pub fn handle_user_discovery_messages( + pub async fn handle_user_discovery_messages( &self, contact_id: UserID, messages: Vec>, @@ -264,22 +269,25 @@ impl UserDiscovery UserDiscovery> = dealer - .take(config.total_number_of_shares) + .take(config.total_number_of_shares as usize) .map(|x| Vec::from(&x)) .collect(); @@ -325,16 +333,16 @@ impl UserDiscovery Result { - Ok(from_bytes(&self.store.get_config()?)?) + async fn get_config(&self) -> Result { + Ok(serde_json::from_str(&self.store.get_config().await?)?) } - fn handle_user_discovery_announcement( + async fn handle_user_discovery_announcement( &self, contact_id: UserID, uda: UserDiscoveryAnnouncement, @@ -378,27 +386,34 @@ impl UserDiscovery UserDiscovery UserDiscovery UserDiscovery Result<()> { tracing::debug!("Received a new UDP with public_id = {}.", &udp.public_id); - self.store.store_other_promotion(OtherPromotion { - from_contact_id, - promotion_id: udp.promotion_id, - threshold: udp.threshold as u8, - public_id: udp.public_id, - announcement_share: udp.announcement_share, - public_key_verified_timestamp: udp.public_key_verified_timestamp, - })?; + self.store + .store_other_promotion(OtherPromotion { + from_contact_id, + promotion_id: udp.promotion_id, + threshold: udp.threshold as u8, + public_id: udp.public_id, + announcement_share: udp.announcement_share, + public_key_verified_timestamp: udp.public_key_verified_timestamp, + }) + .await?; - if let Some(contact) = self.store.get_announced_user_by_public_id(udp.public_id)? { + if let Some(contact) = self + .store + .get_announced_user_by_public_id(udp.public_id) + .await? + { tracing::debug!( "NEW PROMOTION 2: {} knows {}", from_contact_id, contact.user_id ); // The user is already known, just propagate the relation ship - self.store.push_new_user_relation( - from_contact_id, - contact, - udp.public_key_verified_timestamp, - )?; + self.store + .push_new_user_relation(from_contact_id, contact, udp.public_key_verified_timestamp) + .await?; return Ok(()); } - let promotions = self.store.get_other_promotions_by_public_id(udp.public_id); + let promotions = self + .store + .get_other_promotions_by_public_id(udp.public_id) + .await?; if promotions.len() < udp.threshold as usize { tracing::debug!( @@ -507,11 +533,15 @@ impl UserDiscovery UserDiscovery UserDiscovery Self { Self { threshold: 2, - total_number_of_shares: 255, + total_number_of_shares: u8::MAX, announcement_version: 0, promotion_version: 0, verification_shares: vec![], @@ -566,271 +598,3 @@ impl Default for UserDiscoveryConfig { } } } - -#[cfg(test)] -mod tests { - - use std::collections::{HashMap, HashSet}; - use std::vec; - - use crate::user_discovery::stores::InMemoryStore; - use crate::user_discovery::traits::tests::TestingUtils; - use crate::user_discovery::{ - UserDiscovery, UserDiscoveryVersion, UserID, TRANSMITTED_NETWORK_BYTES, - }; - use prost::Message; - - fn get_version_bytes(announcement: u32, promotion: u32) -> Vec { - UserDiscoveryVersion { - announcement, - promotion, - } - .encode_to_vec() - } - - fn get_ud(user_id: usize) -> UserDiscovery { - let store = InMemoryStore::default(); - let ud = UserDiscovery::new(store.to_owned(), TestingUtils::default()).unwrap(); - - ud.initialize_or_update(2, user_id as UserID, vec![user_id as u8; 32]) - .unwrap(); - - let version = ud.get_current_version().unwrap(); - - assert_eq!(version, get_version_bytes(1, 0)); - ud - } - - fn assert_new_messages( - from: (usize, &UserDiscovery), - to: (usize, &UserDiscovery), - has_new_messages: bool, - ) { - // From sends a message with his current version to To - let to_received_version = &from.1.get_current_version().unwrap(); - assert_eq!( - to.1.should_request_new_messages(from.0 as UserID, to_received_version) - .unwrap(), - has_new_messages - ); - } - - fn request_and_handle_messages( - from: (usize, &UserDiscovery), - to: (usize, &UserDiscovery), - messages_count: usize, - ) { - // From sends a message with his current version to To - let to_received_version = &from.1.get_current_version().unwrap(); - assert_eq!( - to.1.should_request_new_messages(from.0 as UserID, to_received_version) - .unwrap(), - true - ); - - // As To has a older version stored he sends a request to From: Give me all messages since version. - let from_request_version_from_to = - to.1.get_contact_version(from.0 as UserID) - .unwrap() - .unwrap_or(get_version_bytes(0, 0)); - - let new_messages = from - .1 - .get_new_messages(to.0 as UserID, &from_request_version_from_to) - .unwrap(); - - assert!(new_messages.len() <= messages_count); - - to.1.handle_user_discovery_messages(from.0 as UserID, new_messages) - .unwrap(); - - assert_eq!( - to.1.should_request_new_messages( - from.0 as UserID, - &from.1.get_current_version().unwrap() - ) - .unwrap(), - false - ); - } - - const ALICE: usize = 0; - const BOB: usize = 1; - const CHARLIE: usize = 2; - const DAVID: usize = 3; - const FRANK: usize = 4; - const TEST_USER_COUNT: usize = 5; - struct TestUsers { - names: [&'static str; TEST_USER_COUNT], - friends: [Vec; TEST_USER_COUNT], - uds: Vec>, - } - - impl TestUsers { - fn get() -> Self { - let names = ["ALICE", "BOB", "CHARLIE", "DAVID", "FRANK"]; - let mut uds = vec![]; - for index in 0..names.len() { - uds.push(get_ud(index)); - } - let friends = [ - vec![BOB, CHARLIE], - vec![ALICE, CHARLIE, DAVID], - vec![ALICE, BOB, DAVID, FRANK], - vec![BOB, CHARLIE], - vec![CHARLIE], - ]; - Self { - names, - uds, - friends, - } - } - } - - #[test] - fn test_initialize_user_discovery() { - let _ = pretty_env_logger::try_init(); - let _ = TRANSMITTED_NETWORK_BYTES.get_or_init(|| std::sync::Mutex::new(0)); - - let users = TestUsers::get(); - - fn to_all_friends(from: usize, message_count: usize, users: &TestUsers) { - for friend in &users.friends[from] { - tracing::debug!("From {} to {}", users.names[from], users.names[*friend]); - - if message_count == 0 { - assert_new_messages( - (from, &users.uds[from]), - (*friend, &users.uds[*friend]), - false, - ); - } else { - request_and_handle_messages( - (from, &users.uds[from]), - (*friend, &users.uds[*friend]), - message_count, - ); - } - } - } - - let message_flows = [ - // ALICE: own announcement sending to BOB and CHARLIE - (ALICE, 1), - // BOB: own announcement + promotion for ALICE - (BOB, 2), - // BOBs version should not have any new messages for his friends - (BOB, 0), - // ALICE: promotion for BOB - (ALICE, 1), - // CHARLIE: own announcement + promotion for ALICE, BOB - (CHARLIE, 3), - // DAVID: own announcement + promotion for BOB, CHARLIE - (DAVID, 3), - // BOB: promotion for CHARLIE, DAVID - (BOB, 2), - // CHARLIE: promotion for DAVID - (CHARLIE, 1), - // FRANK: own announcement + promotion for CHARLIE - (FRANK, 2), - // CHARLIE: promotion for FRANK - (CHARLIE, 1), - // ALICE: promotion for CHARLIE - (ALICE, 1), - ]; - - for (i, (from, count)) in message_flows.into_iter().enumerate() { - tracing::debug!("MESSAGE FLOW: {i}"); - to_all_friends(from, count, &users); - } - - tracing::debug!("Now all users should have the newest version."); - - for from in 0..TEST_USER_COUNT { - for to in &users.friends[from] { - tracing::debug!( - "Does {} has open messages for {}?", - &users.names[from], - &users.names[*to] - ); - assert_new_messages((from, &users.uds[from]), (*to, &users.uds[*to]), false); - } - } - - tracing::debug!("Test if all exchanges where successful."); - - let announced_users_expected = [ - // ALICE should now know that BOB and CHARLIE, BOB and DAVID and CHARLIE and DAVID are friends. - // Alice should also have one protected share from Frank. - ( - ALICE, - vec![ - (BOB, vec![CHARLIE]), // ALICE knows Bob and that CHARLIE is connected with BOB - (CHARLIE, vec![BOB]), // ALICE knows CHARLIE and that BOB is connected with CHARLIE - (DAVID, vec![BOB, CHARLIE]), // ALICE knows DAVID and that BOB and CHARLIE are connected with DAVID - ], - ), - ( - BOB, - vec![ - (ALICE, vec![CHARLIE]), - (CHARLIE, vec![ALICE, DAVID]), - (DAVID, vec![CHARLIE]), - ], - ), - ( - CHARLIE, - vec![ - (ALICE, vec![BOB]), - (BOB, vec![ALICE, DAVID]), - (DAVID, vec![BOB]), - (FRANK, vec![]), - ], - ), - ( - DAVID, - vec![ - (ALICE, vec![BOB, CHARLIE]), - (BOB, vec![CHARLIE]), - (CHARLIE, vec![BOB]), - ], - ), - (FRANK, vec![(CHARLIE, vec![])]), - ]; - - for (user, announcements) in announced_users_expected { - let announced_users2 = users.uds[user].get_all_announced_users().unwrap(); - let mut announced_users = HashMap::new(); - for a in announced_users2 { - announced_users.insert(a.0.user_id, a.1.iter().map(|x| x.0).collect::>()); - } - tracing::debug!("{} knows now: {}", users.names[user], announced_users.len()); - assert_eq!(announced_users.len(), announcements.len()); - for (contact_id, announced_users_expected) in announcements { - let announced_users = announced_users.get(&(contact_id as i64)).unwrap(); - tracing::debug!( - "{} knows now that {} has the following friends: {}", - users.names[user], - users.names[contact_id], - announced_users - .iter() - .map(|x| users.names[*x as usize]) - .collect::>() - .join(", ") - ); - let announced_users: HashSet = announced_users.iter().cloned().collect(); - let announced_users_expected: HashSet = announced_users_expected - .iter() - .cloned() - .map(|x| x as i64) - .collect(); - assert_eq!(announced_users, announced_users_expected); - } - } - - let count = TRANSMITTED_NETWORK_BYTES.get().unwrap().lock().unwrap(); - - tracing::info!("Transmitted a total of {} bytes.", *count); - } -} diff --git a/rust/protocols/src/user_discovery/error.rs b/rust/protocols/src/user_discovery/error.rs index 7ef9b105..9cc234a0 100644 --- a/rust/protocols/src/user_discovery/error.rs +++ b/rust/protocols/src/user_discovery/error.rs @@ -18,7 +18,10 @@ pub enum UserDiscoveryError { NotInitialized, #[error("`{0}`")] - PostcardError(#[from] postcard::Error), + JsonError(#[from] serde_json::Error), + + #[error("`{0}`")] + IoError(#[from] std::io::Error), #[error("error while calculating shamirs secret shares: `{0}`")] ShamirsSecret(String), diff --git a/rust/protocols/src/user_discovery/stores/in_memory_store.rs b/rust/protocols/src/user_discovery/stores/in_memory_store.rs index 4cf8d312..e1befe8e 100644 --- a/rust/protocols/src/user_discovery/stores/in_memory_store.rs +++ b/rust/protocols/src/user_discovery/stores/in_memory_store.rs @@ -6,7 +6,7 @@ use std::sync::{Arc, Mutex}; #[derive(Default)] pub(crate) struct Storage { - config: Option>, + config: Option, unused_shares: Vec>, used_shares: HashMap>, contact_versions: HashMap>, @@ -27,24 +27,27 @@ impl InMemoryStore { } impl UserDiscoveryStore for InMemoryStore { - fn get_config(&self) -> Result> { + async fn new() -> Self { + Self::default() + } + async fn get_config(&self) -> Result { if let Some(storage) = self.storage().config.clone() { return Ok(storage); } Err(UserDiscoveryError::NotInitialized) } - fn update_config(&self, update: Vec) -> Result<()> { + async fn update_config(&self, update: String) -> Result<()> { self.storage().config = Some(update); Ok(()) } - fn set_shares(&self, shares: Vec>) -> Result<()> { + async fn set_shares(&self, shares: Vec>) -> Result<()> { self.storage().unused_shares = shares; Ok(()) } - fn get_share_for_contact(&self, contact_id: UserID) -> Result> { + async fn get_share_for_contact(&self, contact_id: UserID) -> Result> { let mut storage = self.storage(); if let Some(share) = storage.used_shares.get(&contact_id) { return Ok(share.to_vec()); @@ -56,16 +59,16 @@ impl UserDiscoveryStore for InMemoryStore { Err(UserDiscoveryError::NoSharesLeft) } - fn get_contact_version(&self, contact_id: UserID) -> Result>> { + async fn get_contact_version(&self, contact_id: UserID) -> Result>> { Ok(self.storage().contact_versions.get(&contact_id).cloned()) } - fn set_contact_version(&self, contact_id: UserID, update: Vec) -> Result<()> { + async fn set_contact_version(&self, contact_id: UserID, update: Vec) -> Result<()> { self.storage().contact_versions.insert(contact_id, update); Ok(()) } - fn push_own_promotion( + async fn push_own_promotion( &self, contact_id: UserID, version: u32, @@ -80,7 +83,7 @@ impl UserDiscoveryStore for InMemoryStore { Ok(()) } - fn get_own_promotions_after_version(&self, version: u32) -> Result>> { + async fn get_own_promotions_after_version(&self, version: u32) -> Result>> { let storage = self.storage(); let elements = storage.own_promotions[(version as usize)..] .into_iter() @@ -89,21 +92,28 @@ impl UserDiscoveryStore for InMemoryStore { Ok(elements) } - fn store_other_promotion(&self, promotion: OtherPromotion) -> Result<()> { + async fn store_other_promotion(&self, promotion: OtherPromotion) -> Result<()> { self.storage().other_promotions.push(promotion); Ok(()) } - fn get_other_promotions_by_public_id(&self, public_id: u64) -> Vec { - self.storage() + async fn get_other_promotions_by_public_id( + &self, + public_id: i64, + ) -> Result> { + Ok(self + .storage() .other_promotions .iter() .filter(|other| other.public_id == public_id) .map(OtherPromotion::to_owned) - .collect() + .collect()) } - fn get_announced_user_by_public_id(&self, public_id: u64) -> Result> { + async fn get_announced_user_by_public_id( + &self, + public_id: i64, + ) -> Result> { Ok(self .storage() .announced_users @@ -112,13 +122,13 @@ impl UserDiscoveryStore for InMemoryStore { .map(|u| u.0.to_owned())) } - fn get_all_announced_users( + async fn get_all_announced_users( &self, ) -> Result)>>> { Ok(self.storage().announced_users.clone()) } - fn push_new_user_relation( + async fn push_new_user_relation( &self, from_contact_id: UserID, announced_user: AnnouncedUser, diff --git a/rust/protocols/src/user_discovery/tests.rs b/rust/protocols/src/user_discovery/tests.rs new file mode 100644 index 00000000..58b957af --- /dev/null +++ b/rust/protocols/src/user_discovery/tests.rs @@ -0,0 +1,272 @@ +use crate::user_discovery::traits::tests::TestingUtils; +use crate::user_discovery::{UserDiscovery, UserDiscoveryStore, UserDiscoveryVersion, UserID}; +use prost::Message; +use std::collections::{HashMap, HashSet}; +use std::vec; + +fn get_version_bytes(announcement: u32, promotion: u32) -> Vec { + UserDiscoveryVersion { + announcement, + promotion, + } + .encode_to_vec() +} + +async fn get_ud(user_id: usize) -> UserDiscovery { + let store = S::new().await; + let ud = UserDiscovery::new(store.to_owned(), TestingUtils::default()).unwrap(); + + ud.initialize_or_update(2, user_id as UserID, vec![user_id as u8; 32]) + .await + .unwrap(); + + let version = ud.get_current_version().await.unwrap(); + + assert_eq!(version, get_version_bytes(1, 0)); + ud +} + +async fn assert_new_messages( + from: (usize, &UserDiscovery), + to: (usize, &UserDiscovery), + has_new_messages: bool, +) { + // From sends a message with his current version to To + let to_received_version = &from.1.get_current_version().await.unwrap(); + assert_eq!( + to.1.should_request_new_messages(from.0 as UserID, to_received_version) + .await + .unwrap(), + has_new_messages + ); +} + +async fn request_and_handle_messages( + from: (usize, &UserDiscovery), + to: (usize, &UserDiscovery), + messages_count: usize, +) { + // From sends a message with his current version to To + let to_received_version = &from.1.get_current_version().await.unwrap(); + assert_eq!( + to.1.should_request_new_messages(from.0 as UserID, to_received_version) + .await + .unwrap(), + true + ); + + // As To has a older version stored he sends a request to From: Give me all messages since version. + let from_request_version_from_to = + to.1.get_contact_version(from.0 as UserID) + .await + .unwrap() + .unwrap_or(get_version_bytes(0, 0)); + + let new_messages = from + .1 + .get_new_messages(to.0 as UserID, &from_request_version_from_to) + .await + .unwrap(); + + assert!(new_messages.len() <= messages_count); + + to.1.handle_user_discovery_messages(from.0 as UserID, new_messages) + .await + .unwrap(); + + assert_eq!( + to.1.should_request_new_messages( + from.0 as UserID, + &from.1.get_current_version().await.unwrap() + ) + .await + .unwrap(), + false + ); +} + +const ALICE: usize = 0; +const BOB: usize = 1; +const CHARLIE: usize = 2; +const DAVID: usize = 3; +const FRANK: usize = 4; +const TEST_USER_COUNT: usize = 5; +struct TestUsers { + names: [&'static str; TEST_USER_COUNT], + friends: [Vec; TEST_USER_COUNT], + uds: Vec>, +} + +impl TestUsers { + async fn get() -> Self { + let names = ["ALICE", "BOB", "CHARLIE", "DAVID", "FRANK"]; + let mut uds = vec![]; + for index in 0..names.len() { + uds.push(get_ud(index).await); + } + let friends = [ + vec![BOB, CHARLIE], + vec![ALICE, CHARLIE, DAVID], + vec![ALICE, BOB, DAVID, FRANK], + vec![BOB, CHARLIE], + vec![CHARLIE], + ]; + Self { + names, + uds, + friends, + } + } +} + +pub async fn test_initialize_user_discovery() { + #[cfg(test)] + let _ = pretty_env_logger::try_init(); + + let users = TestUsers::::get().await; + + async fn to_all_friends( + from: usize, + message_count: usize, + users: &TestUsers, + ) { + for friend in &users.friends[from] { + tracing::debug!("From {} to {}", users.names[from], users.names[*friend]); + + if message_count == 0 { + assert_new_messages( + (from, &users.uds[from]), + (*friend, &users.uds[*friend]), + false, + ) + .await; + } else { + request_and_handle_messages( + (from, &users.uds[from]), + (*friend, &users.uds[*friend]), + message_count, + ) + .await; + } + } + } + + let message_flows = [ + // ALICE: own announcement sending to BOB and CHARLIE + (ALICE, 1), + // BOB: own announcement + promotion for ALICE + (BOB, 2), + // BOBs version should not have any new messages for his friends + (BOB, 0), + // ALICE: promotion for BOB + (ALICE, 1), + // CHARLIE: own announcement + promotion for ALICE, BOB + (CHARLIE, 3), + // DAVID: own announcement + promotion for BOB, CHARLIE + (DAVID, 3), + // BOB: promotion for CHARLIE, DAVID + (BOB, 2), + // CHARLIE: promotion for DAVID + (CHARLIE, 1), + // FRANK: own announcement + promotion for CHARLIE + (FRANK, 2), + // CHARLIE: promotion for FRANK + (CHARLIE, 1), + // ALICE: promotion for CHARLIE + (ALICE, 1), + ]; + + for (i, (from, count)) in message_flows.into_iter().enumerate() { + tracing::debug!("MESSAGE FLOW: {i}"); + to_all_friends(from, count, &users).await; + } + + tracing::debug!("Now all users should have the newest version."); + + for from in 0..TEST_USER_COUNT { + for to in &users.friends[from] { + tracing::debug!( + "Does {} has open messages for {}?", + &users.names[from], + &users.names[*to] + ); + assert_new_messages((from, &users.uds[from]), (*to, &users.uds[*to]), false).await; + } + } + + tracing::debug!("Test if all exchanges where successful."); + + let announced_users_expected = [ + // ALICE should now know that BOB and CHARLIE, BOB and DAVID and CHARLIE and DAVID are friends. + // Alice should also have one protected share from Frank. + ( + ALICE, + vec![ + (BOB, vec![CHARLIE]), // ALICE knows Bob and that CHARLIE is connected with BOB + (CHARLIE, vec![BOB]), // ALICE knows CHARLIE and that BOB is connected with CHARLIE + (DAVID, vec![BOB, CHARLIE]), // ALICE knows DAVID and that BOB and CHARLIE are connected with DAVID + ], + ), + ( + BOB, + vec![ + (ALICE, vec![CHARLIE]), + (CHARLIE, vec![ALICE, DAVID]), + (DAVID, vec![CHARLIE]), + ], + ), + ( + CHARLIE, + vec![ + (ALICE, vec![BOB]), + (BOB, vec![ALICE, DAVID]), + (DAVID, vec![BOB]), + (FRANK, vec![]), + ], + ), + ( + DAVID, + vec![ + (ALICE, vec![BOB, CHARLIE]), + (BOB, vec![CHARLIE]), + (CHARLIE, vec![BOB]), + ], + ), + (FRANK, vec![(CHARLIE, vec![])]), + ]; + + for (user, announcements) in announced_users_expected { + let announced_users2 = users.uds[user].get_all_announced_users().await.unwrap(); + let mut announced_users = HashMap::new(); + for a in announced_users2 { + announced_users.insert(a.0.user_id, a.1.iter().map(|x| x.0).collect::>()); + } + tracing::debug!("{} knows now: {}", users.names[user], announced_users.len()); + assert_eq!(announced_users.len(), announcements.len()); + for (contact_id, announced_users_expected) in announcements { + let announced_users = announced_users.get(&(contact_id as i64)).unwrap(); + tracing::debug!( + "{} knows now that {} has the following friends: {}", + users.names[user], + users.names[contact_id], + announced_users + .iter() + .map(|x| users.names[*x as usize]) + .collect::>() + .join(", ") + ); + let announced_users: HashSet = announced_users.iter().cloned().collect(); + let announced_users_expected: HashSet = announced_users_expected + .iter() + .cloned() + .map(|x| x as i64) + .collect(); + assert_eq!(announced_users, announced_users_expected); + } + } +} + +#[tokio::test] +async fn test_initialize_user_discovery_in_memory_store() { + test_initialize_user_discovery::().await; +} diff --git a/rust/protocols/src/user_discovery/traits.rs b/rust/protocols/src/user_discovery/traits.rs index 8646d1f1..8e88573a 100644 --- a/rust/protocols/src/user_discovery/traits.rs +++ b/rust/protocols/src/user_discovery/traits.rs @@ -2,11 +2,12 @@ use std::collections::HashMap; use crate::user_discovery::error::Result; use crate::user_discovery::UserID; +use std::future::Future; -#[derive(Clone)] +#[derive(Clone, sqlx::FromRow)] pub struct OtherPromotion { pub promotion_id: u32, - pub public_id: u64, + pub public_id: i64, pub from_contact_id: UserID, pub threshold: u8, pub announcement_share: Vec, @@ -17,62 +18,97 @@ pub struct OtherPromotion { pub struct AnnouncedUser { pub user_id: UserID, pub public_key: Vec, - pub public_id: u64, + pub public_id: i64, } pub trait UserDiscoveryStore { - fn get_config(&self) -> Result>; - fn update_config(&self, update: Vec) -> Result<()>; - fn set_shares(&self, shares: Vec>) -> Result<()>; + fn new() -> impl std::future::Future + Send; + fn get_config(&self) -> impl Future> + Send; + fn update_config(&self, update: String) -> impl Future> + Send; + fn set_shares(&self, shares: Vec>) -> impl Future> + Send; - fn get_share_for_contact(&self, contact_id: UserID) -> Result>; + fn get_share_for_contact( + &self, + contact_id: UserID, + ) -> impl Future>> + Send; fn push_own_promotion( &self, contact_id: UserID, version: u32, promotion: Vec, - ) -> Result<()>; + ) -> impl Future> + Send; - fn get_own_promotions_after_version(&self, version: u32) -> Result>>; + fn get_own_promotions_after_version( + &self, + version: u32, + ) -> impl Future>>> + Send; - fn store_other_promotion(&self, promotion: OtherPromotion) -> Result<()>; - fn get_other_promotions_by_public_id(&self, public_id: u64) -> Vec; + fn store_other_promotion( + &self, + promotion: OtherPromotion, + ) -> impl Future> + Send; + fn get_other_promotions_by_public_id( + &self, + public_id: i64, + ) -> impl Future>> + Send; - fn get_announced_user_by_public_id(&self, public_id: u64) -> Result>; + fn get_announced_user_by_public_id( + &self, + public_id: i64, + ) -> impl Future>> + Send; fn push_new_user_relation( &self, from_contact_id: UserID, announced_user: AnnouncedUser, public_key_verified_timestamp: Option, - ) -> Result<()>; + ) -> impl Future> + Send; - fn get_all_announced_users(&self) - -> Result)>>>; + fn get_all_announced_users( + &self, + ) -> impl Future)>>>> + Send; - fn get_contact_version(&self, contact_id: UserID) -> Result>>; - fn set_contact_version(&self, contact_id: UserID, update: Vec) -> Result<()>; + fn get_contact_version( + &self, + contact_id: UserID, + ) -> impl Future>>> + Send; + fn set_contact_version( + &self, + contact_id: UserID, + update: Vec, + ) -> impl Future> + Send; } pub trait UserDiscoveryUtils { - fn sign_data(&self, input_data: &[u8]) -> Result>; - fn verify_signature(&self, input_data: &[u8], pubkey: &[u8], signature: &[u8]) -> Result; - fn verify_stored_pubkey(&self, from_contact_id: UserID, pubkey: &[u8]) -> Result; + fn sign_data(&self, input_data: &[u8]) -> impl Future>> + Send; + fn verify_signature( + &self, + input_data: &[u8], + pubkey: &[u8], + signature: &[u8], + ) -> impl Future> + Send; + fn verify_stored_pubkey( + &self, + from_contact_id: UserID, + pubkey: &[u8], + ) -> impl Future> + Send; } -#[cfg(test)] pub(crate) mod tests { use crate::user_discovery::traits::UserDiscoveryUtils; #[derive(Default)] pub(crate) struct TestingUtils {} impl UserDiscoveryUtils for TestingUtils { - fn sign_data(&self, _input_data: &[u8]) -> crate::user_discovery::error::Result> { + async fn sign_data( + &self, + _input_data: &[u8], + ) -> crate::user_discovery::error::Result> { Ok(vec![0; 64]) } - fn verify_signature( + async fn verify_signature( &self, _data: &[u8], _pubkey: &[u8], @@ -81,7 +117,7 @@ pub(crate) mod tests { Ok(true) } - fn verify_stored_pubkey( + async fn verify_stored_pubkey( &self, _from_contact_id: crate::user_discovery::UserID, _pubkey: &[u8], diff --git a/rust/protocols/src/user_discovery/types.proto b/rust/protocols/src/user_discovery/types.proto index 50dc1ccc..7df0cc63 100644 --- a/rust/protocols/src/user_discovery/types.proto +++ b/rust/protocols/src/user_discovery/types.proto @@ -15,7 +15,7 @@ message UserDiscoveryMessage { optional UserDiscoveryRecall user_discovery_recall = 4; message UserDiscoveryAnnouncement { - uint64 public_id = 1; + int64 public_id = 1; uint32 threshold = 2; bytes announcement_share = 4; repeated bytes verification_shares = 6; @@ -23,7 +23,7 @@ message UserDiscoveryMessage { message UserDiscoveryPromotion { uint32 promotion_id = 1; - uint64 public_id = 2; + int64 public_id = 2; uint32 threshold = 3; bytes announcement_share = 5; @@ -31,9 +31,9 @@ message UserDiscoveryMessage { message AnnouncementShareDecrypted { message SignedData { - uint64 public_id = 1; - int64 user_id = 2; - bytes public_key = 3; + int64 public_id = 1; + int64 user_id = 2; + bytes public_key = 3; } SignedData signed_data = 1; bytes signature = 2; diff --git a/test/drift/twonly_db/generated/schema.dart b/test/drift/twonly_db/generated/schema.dart index 60e4f107..49f49d7b 100644 --- a/test/drift/twonly_db/generated/schema.dart +++ b/test/drift/twonly_db/generated/schema.dart @@ -15,6 +15,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 @@ -42,10 +43,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_db/generated/schema_v12.dart b/test/drift/twonly_db/generated/schema_v12.dart new file mode 100644 index 00000000..9d5c1ee4 --- /dev/null +++ b/test/drift/twonly_db/generated/schema_v12.dart @@ -0,0 +1,9358 @@ +// dart format width=80 +import 'dart:typed_data' as i2; +// GENERATED BY drift_dev, DO NOT MODIFY. +// ignore_for_file: type=lint,unused_import +// +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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn username = GeneratedColumn( + 'username', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn displayName = GeneratedColumn( + 'display_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn nickName = GeneratedColumn( + 'nick_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn avatarSvgCompressed = + GeneratedColumn( + 'avatar_svg_compressed', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn senderProfileCounter = GeneratedColumn( + 'sender_profile_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn accepted = GeneratedColumn( + 'accepted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (accepted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deletedByUser = GeneratedColumn( + 'deleted_by_user', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (deleted_by_user IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn requested = GeneratedColumn( + 'requested', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (requested IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn blocked = GeneratedColumn( + 'blocked', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (blocked IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn verified = GeneratedColumn( + 'verified', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (verified IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn accountDeleted = GeneratedColumn( + 'account_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (account_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn userDiscoveryVersion = + GeneratedColumn( + 'user_discovery_version', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + userId, + username, + displayName, + nickName, + avatarSvgCompressed, + senderProfileCounter, + accepted, + deletedByUser, + requested, + blocked, + verified, + accountDeleted, + createdAt, + userDiscoveryVersion, + ]; + @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'], + ), + avatarSvgCompressed: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}avatar_svg_compressed'], + ), + senderProfileCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_profile_counter'], + )!, + accepted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}accepted'], + )!, + deletedByUser: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}deleted_by_user'], + )!, + requested: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}requested'], + )!, + blocked: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}blocked'], + )!, + verified: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}verified'], + )!, + accountDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}account_deleted'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + userDiscoveryVersion: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}user_discovery_version'], + ), + ); + } + + @override + Contacts createAlias(String alias) { + return Contacts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(user_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ContactsData extends DataClass implements Insertable { + final int userId; + final String username; + final String? displayName; + final String? nickName; + final i2.Uint8List? avatarSvgCompressed; + final int senderProfileCounter; + final int accepted; + final int deletedByUser; + final int requested; + final int blocked; + final int verified; + final int accountDeleted; + final int createdAt; + final i2.Uint8List? userDiscoveryVersion; + const ContactsData({ + required this.userId, + required this.username, + this.displayName, + this.nickName, + this.avatarSvgCompressed, + required this.senderProfileCounter, + required this.accepted, + required this.deletedByUser, + required this.requested, + required this.blocked, + required this.verified, + required this.accountDeleted, + required this.createdAt, + this.userDiscoveryVersion, + }); + @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 || avatarSvgCompressed != null) { + map['avatar_svg_compressed'] = Variable( + avatarSvgCompressed, + ); + } + map['sender_profile_counter'] = Variable(senderProfileCounter); + map['accepted'] = Variable(accepted); + map['deleted_by_user'] = Variable(deletedByUser); + map['requested'] = Variable(requested); + map['blocked'] = Variable(blocked); + map['verified'] = Variable(verified); + map['account_deleted'] = Variable(accountDeleted); + map['created_at'] = Variable(createdAt); + if (!nullToAbsent || userDiscoveryVersion != null) { + map['user_discovery_version'] = Variable( + userDiscoveryVersion, + ); + } + 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), + avatarSvgCompressed: avatarSvgCompressed == null && nullToAbsent + ? const Value.absent() + : Value(avatarSvgCompressed), + senderProfileCounter: Value(senderProfileCounter), + accepted: Value(accepted), + deletedByUser: Value(deletedByUser), + requested: Value(requested), + blocked: Value(blocked), + verified: Value(verified), + accountDeleted: Value(accountDeleted), + createdAt: Value(createdAt), + userDiscoveryVersion: userDiscoveryVersion == null && nullToAbsent + ? const Value.absent() + : Value(userDiscoveryVersion), + ); + } + + 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']), + avatarSvgCompressed: serializer.fromJson( + json['avatarSvgCompressed'], + ), + senderProfileCounter: serializer.fromJson( + json['senderProfileCounter'], + ), + accepted: serializer.fromJson(json['accepted']), + deletedByUser: serializer.fromJson(json['deletedByUser']), + requested: serializer.fromJson(json['requested']), + blocked: serializer.fromJson(json['blocked']), + verified: serializer.fromJson(json['verified']), + accountDeleted: serializer.fromJson(json['accountDeleted']), + createdAt: serializer.fromJson(json['createdAt']), + userDiscoveryVersion: serializer.fromJson( + json['userDiscoveryVersion'], + ), + ); + } + @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), + 'avatarSvgCompressed': serializer.toJson( + avatarSvgCompressed, + ), + 'senderProfileCounter': serializer.toJson(senderProfileCounter), + 'accepted': serializer.toJson(accepted), + 'deletedByUser': serializer.toJson(deletedByUser), + 'requested': serializer.toJson(requested), + 'blocked': serializer.toJson(blocked), + 'verified': serializer.toJson(verified), + 'accountDeleted': serializer.toJson(accountDeleted), + 'createdAt': serializer.toJson(createdAt), + 'userDiscoveryVersion': serializer.toJson( + userDiscoveryVersion, + ), + }; + } + + ContactsData copyWith({ + int? userId, + String? username, + Value displayName = const Value.absent(), + Value nickName = const Value.absent(), + Value avatarSvgCompressed = const Value.absent(), + int? senderProfileCounter, + int? accepted, + int? deletedByUser, + int? requested, + int? blocked, + int? verified, + int? accountDeleted, + int? createdAt, + Value userDiscoveryVersion = const Value.absent(), + }) => ContactsData( + userId: userId ?? this.userId, + username: username ?? this.username, + displayName: displayName.present ? displayName.value : this.displayName, + nickName: nickName.present ? nickName.value : this.nickName, + avatarSvgCompressed: avatarSvgCompressed.present + ? avatarSvgCompressed.value + : this.avatarSvgCompressed, + senderProfileCounter: senderProfileCounter ?? this.senderProfileCounter, + accepted: accepted ?? this.accepted, + deletedByUser: deletedByUser ?? this.deletedByUser, + requested: requested ?? this.requested, + blocked: blocked ?? this.blocked, + verified: verified ?? this.verified, + accountDeleted: accountDeleted ?? this.accountDeleted, + createdAt: createdAt ?? this.createdAt, + userDiscoveryVersion: userDiscoveryVersion.present + ? userDiscoveryVersion.value + : this.userDiscoveryVersion, + ); + 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, + avatarSvgCompressed: data.avatarSvgCompressed.present + ? data.avatarSvgCompressed.value + : this.avatarSvgCompressed, + senderProfileCounter: data.senderProfileCounter.present + ? data.senderProfileCounter.value + : this.senderProfileCounter, + accepted: data.accepted.present ? data.accepted.value : this.accepted, + deletedByUser: data.deletedByUser.present + ? data.deletedByUser.value + : this.deletedByUser, + 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, + accountDeleted: data.accountDeleted.present + ? data.accountDeleted.value + : this.accountDeleted, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + userDiscoveryVersion: data.userDiscoveryVersion.present + ? data.userDiscoveryVersion.value + : this.userDiscoveryVersion, + ); + } + + @override + String toString() { + return (StringBuffer('ContactsData(') + ..write('userId: $userId, ') + ..write('username: $username, ') + ..write('displayName: $displayName, ') + ..write('nickName: $nickName, ') + ..write('avatarSvgCompressed: $avatarSvgCompressed, ') + ..write('senderProfileCounter: $senderProfileCounter, ') + ..write('accepted: $accepted, ') + ..write('deletedByUser: $deletedByUser, ') + ..write('requested: $requested, ') + ..write('blocked: $blocked, ') + ..write('verified: $verified, ') + ..write('accountDeleted: $accountDeleted, ') + ..write('createdAt: $createdAt, ') + ..write('userDiscoveryVersion: $userDiscoveryVersion') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + userId, + username, + displayName, + nickName, + $driftBlobEquality.hash(avatarSvgCompressed), + senderProfileCounter, + accepted, + deletedByUser, + requested, + blocked, + verified, + accountDeleted, + createdAt, + $driftBlobEquality.hash(userDiscoveryVersion), + ); + @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 && + $driftBlobEquality.equals( + other.avatarSvgCompressed, + this.avatarSvgCompressed, + ) && + other.senderProfileCounter == this.senderProfileCounter && + other.accepted == this.accepted && + other.deletedByUser == this.deletedByUser && + other.requested == this.requested && + other.blocked == this.blocked && + other.verified == this.verified && + other.accountDeleted == this.accountDeleted && + other.createdAt == this.createdAt && + $driftBlobEquality.equals( + other.userDiscoveryVersion, + this.userDiscoveryVersion, + )); +} + +class ContactsCompanion extends UpdateCompanion { + final Value userId; + final Value username; + final Value displayName; + final Value nickName; + final Value avatarSvgCompressed; + final Value senderProfileCounter; + final Value accepted; + final Value deletedByUser; + final Value requested; + final Value blocked; + final Value verified; + final Value accountDeleted; + final Value createdAt; + final Value userDiscoveryVersion; + const ContactsCompanion({ + this.userId = const Value.absent(), + this.username = const Value.absent(), + this.displayName = const Value.absent(), + this.nickName = const Value.absent(), + this.avatarSvgCompressed = const Value.absent(), + this.senderProfileCounter = const Value.absent(), + this.accepted = const Value.absent(), + this.deletedByUser = const Value.absent(), + this.requested = const Value.absent(), + this.blocked = const Value.absent(), + this.verified = const Value.absent(), + this.accountDeleted = const Value.absent(), + this.createdAt = const Value.absent(), + this.userDiscoveryVersion = const Value.absent(), + }); + ContactsCompanion.insert({ + this.userId = const Value.absent(), + required String username, + this.displayName = const Value.absent(), + this.nickName = const Value.absent(), + this.avatarSvgCompressed = const Value.absent(), + this.senderProfileCounter = const Value.absent(), + this.accepted = const Value.absent(), + this.deletedByUser = const Value.absent(), + this.requested = const Value.absent(), + this.blocked = const Value.absent(), + this.verified = const Value.absent(), + this.accountDeleted = const Value.absent(), + this.createdAt = const Value.absent(), + this.userDiscoveryVersion = const Value.absent(), + }) : username = Value(username); + static Insertable custom({ + Expression? userId, + Expression? username, + Expression? displayName, + Expression? nickName, + Expression? avatarSvgCompressed, + Expression? senderProfileCounter, + Expression? accepted, + Expression? deletedByUser, + Expression? requested, + Expression? blocked, + Expression? verified, + Expression? accountDeleted, + Expression? createdAt, + Expression? userDiscoveryVersion, + }) { + 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 (avatarSvgCompressed != null) + 'avatar_svg_compressed': avatarSvgCompressed, + if (senderProfileCounter != null) + 'sender_profile_counter': senderProfileCounter, + if (accepted != null) 'accepted': accepted, + if (deletedByUser != null) 'deleted_by_user': deletedByUser, + if (requested != null) 'requested': requested, + if (blocked != null) 'blocked': blocked, + if (verified != null) 'verified': verified, + if (accountDeleted != null) 'account_deleted': accountDeleted, + if (createdAt != null) 'created_at': createdAt, + if (userDiscoveryVersion != null) + 'user_discovery_version': userDiscoveryVersion, + }); + } + + ContactsCompanion copyWith({ + Value? userId, + Value? username, + Value? displayName, + Value? nickName, + Value? avatarSvgCompressed, + Value? senderProfileCounter, + Value? accepted, + Value? deletedByUser, + Value? requested, + Value? blocked, + Value? verified, + Value? accountDeleted, + Value? createdAt, + Value? userDiscoveryVersion, + }) { + return ContactsCompanion( + userId: userId ?? this.userId, + username: username ?? this.username, + displayName: displayName ?? this.displayName, + nickName: nickName ?? this.nickName, + avatarSvgCompressed: avatarSvgCompressed ?? this.avatarSvgCompressed, + senderProfileCounter: senderProfileCounter ?? this.senderProfileCounter, + accepted: accepted ?? this.accepted, + deletedByUser: deletedByUser ?? this.deletedByUser, + requested: requested ?? this.requested, + blocked: blocked ?? this.blocked, + verified: verified ?? this.verified, + accountDeleted: accountDeleted ?? this.accountDeleted, + createdAt: createdAt ?? this.createdAt, + userDiscoveryVersion: userDiscoveryVersion ?? this.userDiscoveryVersion, + ); + } + + @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 (avatarSvgCompressed.present) { + map['avatar_svg_compressed'] = Variable( + avatarSvgCompressed.value, + ); + } + if (senderProfileCounter.present) { + map['sender_profile_counter'] = Variable(senderProfileCounter.value); + } + if (accepted.present) { + map['accepted'] = Variable(accepted.value); + } + if (deletedByUser.present) { + map['deleted_by_user'] = Variable(deletedByUser.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 (accountDeleted.present) { + map['account_deleted'] = Variable(accountDeleted.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (userDiscoveryVersion.present) { + map['user_discovery_version'] = Variable( + userDiscoveryVersion.value, + ); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ContactsCompanion(') + ..write('userId: $userId, ') + ..write('username: $username, ') + ..write('displayName: $displayName, ') + ..write('nickName: $nickName, ') + ..write('avatarSvgCompressed: $avatarSvgCompressed, ') + ..write('senderProfileCounter: $senderProfileCounter, ') + ..write('accepted: $accepted, ') + ..write('deletedByUser: $deletedByUser, ') + ..write('requested: $requested, ') + ..write('blocked: $blocked, ') + ..write('verified: $verified, ') + ..write('accountDeleted: $accountDeleted, ') + ..write('createdAt: $createdAt, ') + ..write('userDiscoveryVersion: $userDiscoveryVersion') + ..write(')')) + .toString(); + } +} + +class Groups extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Groups(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isGroupAdmin = GeneratedColumn( + 'is_group_admin', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_group_admin IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn isDirectChat = GeneratedColumn( + 'is_direct_chat', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_direct_chat IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn pinned = GeneratedColumn( + 'pinned', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (pinned IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn archived = GeneratedColumn( + 'archived', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (archived IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn joinedGroup = GeneratedColumn( + 'joined_group', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (joined_group IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn leftGroup = GeneratedColumn( + 'left_group', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (left_group IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deletedContent = GeneratedColumn( + 'deleted_content', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (deleted_content IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stateVersionId = GeneratedColumn( + 'state_version_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stateEncryptionKey = + GeneratedColumn( + 'state_encryption_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn myGroupPrivateKey = + GeneratedColumn( + 'my_group_private_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn groupName = GeneratedColumn( + 'group_name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn draftMessage = GeneratedColumn( + 'draft_message', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn totalMediaCounter = GeneratedColumn( + 'total_media_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn alsoBestFriend = GeneratedColumn( + 'also_best_friend', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (also_best_friend IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deleteMessagesAfterMilliseconds = + GeneratedColumn( + 'delete_messages_after_milliseconds', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 86400000', + defaultValue: const CustomExpression('86400000'), + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn lastMessageSend = GeneratedColumn( + 'last_message_send', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessageReceived = GeneratedColumn( + 'last_message_received', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastFlameCounterChange = GeneratedColumn( + 'last_flame_counter_change', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastFlameSync = GeneratedColumn( + 'last_flame_sync', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn flameCounter = GeneratedColumn( + 'flame_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn maxFlameCounter = GeneratedColumn( + 'max_flame_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn maxFlameCounterFrom = GeneratedColumn( + 'max_flame_counter_from', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessageExchange = GeneratedColumn( + 'last_message_exchange', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupId, + isGroupAdmin, + isDirectChat, + pinned, + archived, + joinedGroup, + leftGroup, + deletedContent, + stateVersionId, + stateEncryptionKey, + myGroupPrivateKey, + groupName, + draftMessage, + totalMediaCounter, + alsoBestFriend, + deleteMessagesAfterMilliseconds, + createdAt, + lastMessageSend, + lastMessageReceived, + lastFlameCounterChange, + lastFlameSync, + flameCounter, + maxFlameCounter, + maxFlameCounterFrom, + lastMessageExchange, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'groups'; + @override + Set get $primaryKey => {groupId}; + @override + GroupsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupsData( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + isGroupAdmin: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_group_admin'], + )!, + isDirectChat: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_direct_chat'], + )!, + pinned: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}pinned'], + )!, + archived: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}archived'], + )!, + joinedGroup: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}joined_group'], + )!, + leftGroup: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}left_group'], + )!, + deletedContent: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}deleted_content'], + )!, + stateVersionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}state_version_id'], + )!, + stateEncryptionKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}state_encryption_key'], + ), + myGroupPrivateKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}my_group_private_key'], + ), + groupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_name'], + )!, + draftMessage: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}draft_message'], + ), + totalMediaCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}total_media_counter'], + )!, + alsoBestFriend: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}also_best_friend'], + )!, + deleteMessagesAfterMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}delete_messages_after_milliseconds'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + lastMessageSend: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_send'], + ), + lastMessageReceived: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_received'], + ), + lastFlameCounterChange: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_flame_counter_change'], + ), + lastFlameSync: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_flame_sync'], + ), + flameCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}flame_counter'], + )!, + maxFlameCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}max_flame_counter'], + )!, + maxFlameCounterFrom: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}max_flame_counter_from'], + ), + lastMessageExchange: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_exchange'], + )!, + ); + } + + @override + Groups createAlias(String alias) { + return Groups(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(group_id)']; + @override + bool get dontWriteConstraints => true; +} + +class GroupsData extends DataClass implements Insertable { + final String groupId; + final int isGroupAdmin; + final int isDirectChat; + final int pinned; + final int archived; + final int joinedGroup; + final int leftGroup; + final int deletedContent; + final int stateVersionId; + final i2.Uint8List? stateEncryptionKey; + final i2.Uint8List? myGroupPrivateKey; + final String groupName; + final String? draftMessage; + final int totalMediaCounter; + final int alsoBestFriend; + final int deleteMessagesAfterMilliseconds; + final int createdAt; + final int? lastMessageSend; + final int? lastMessageReceived; + final int? lastFlameCounterChange; + final int? lastFlameSync; + final int flameCounter; + final int maxFlameCounter; + final int? maxFlameCounterFrom; + final int lastMessageExchange; + const GroupsData({ + required this.groupId, + required this.isGroupAdmin, + required this.isDirectChat, + required this.pinned, + required this.archived, + required this.joinedGroup, + required this.leftGroup, + required this.deletedContent, + required this.stateVersionId, + this.stateEncryptionKey, + this.myGroupPrivateKey, + required this.groupName, + this.draftMessage, + required this.totalMediaCounter, + required this.alsoBestFriend, + required this.deleteMessagesAfterMilliseconds, + required this.createdAt, + this.lastMessageSend, + this.lastMessageReceived, + this.lastFlameCounterChange, + this.lastFlameSync, + required this.flameCounter, + required this.maxFlameCounter, + this.maxFlameCounterFrom, + required this.lastMessageExchange, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['is_group_admin'] = Variable(isGroupAdmin); + map['is_direct_chat'] = Variable(isDirectChat); + map['pinned'] = Variable(pinned); + map['archived'] = Variable(archived); + map['joined_group'] = Variable(joinedGroup); + map['left_group'] = Variable(leftGroup); + map['deleted_content'] = Variable(deletedContent); + map['state_version_id'] = Variable(stateVersionId); + if (!nullToAbsent || stateEncryptionKey != null) { + map['state_encryption_key'] = Variable(stateEncryptionKey); + } + if (!nullToAbsent || myGroupPrivateKey != null) { + map['my_group_private_key'] = Variable(myGroupPrivateKey); + } + map['group_name'] = Variable(groupName); + if (!nullToAbsent || draftMessage != null) { + map['draft_message'] = Variable(draftMessage); + } + map['total_media_counter'] = Variable(totalMediaCounter); + map['also_best_friend'] = Variable(alsoBestFriend); + map['delete_messages_after_milliseconds'] = Variable( + deleteMessagesAfterMilliseconds, + ); + map['created_at'] = Variable(createdAt); + 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['flame_counter'] = Variable(flameCounter); + map['max_flame_counter'] = Variable(maxFlameCounter); + if (!nullToAbsent || maxFlameCounterFrom != null) { + map['max_flame_counter_from'] = Variable(maxFlameCounterFrom); + } + map['last_message_exchange'] = Variable(lastMessageExchange); + return map; + } + + GroupsCompanion toCompanion(bool nullToAbsent) { + return GroupsCompanion( + groupId: Value(groupId), + isGroupAdmin: Value(isGroupAdmin), + isDirectChat: Value(isDirectChat), + pinned: Value(pinned), + archived: Value(archived), + joinedGroup: Value(joinedGroup), + leftGroup: Value(leftGroup), + deletedContent: Value(deletedContent), + stateVersionId: Value(stateVersionId), + stateEncryptionKey: stateEncryptionKey == null && nullToAbsent + ? const Value.absent() + : Value(stateEncryptionKey), + myGroupPrivateKey: myGroupPrivateKey == null && nullToAbsent + ? const Value.absent() + : Value(myGroupPrivateKey), + groupName: Value(groupName), + draftMessage: draftMessage == null && nullToAbsent + ? const Value.absent() + : Value(draftMessage), + totalMediaCounter: Value(totalMediaCounter), + alsoBestFriend: Value(alsoBestFriend), + deleteMessagesAfterMilliseconds: Value(deleteMessagesAfterMilliseconds), + createdAt: Value(createdAt), + 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), + flameCounter: Value(flameCounter), + maxFlameCounter: Value(maxFlameCounter), + maxFlameCounterFrom: maxFlameCounterFrom == null && nullToAbsent + ? const Value.absent() + : Value(maxFlameCounterFrom), + lastMessageExchange: Value(lastMessageExchange), + ); + } + + factory GroupsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupsData( + groupId: serializer.fromJson(json['groupId']), + isGroupAdmin: serializer.fromJson(json['isGroupAdmin']), + isDirectChat: serializer.fromJson(json['isDirectChat']), + pinned: serializer.fromJson(json['pinned']), + archived: serializer.fromJson(json['archived']), + joinedGroup: serializer.fromJson(json['joinedGroup']), + leftGroup: serializer.fromJson(json['leftGroup']), + deletedContent: serializer.fromJson(json['deletedContent']), + stateVersionId: serializer.fromJson(json['stateVersionId']), + stateEncryptionKey: serializer.fromJson( + json['stateEncryptionKey'], + ), + myGroupPrivateKey: serializer.fromJson( + json['myGroupPrivateKey'], + ), + groupName: serializer.fromJson(json['groupName']), + draftMessage: serializer.fromJson(json['draftMessage']), + totalMediaCounter: serializer.fromJson(json['totalMediaCounter']), + alsoBestFriend: serializer.fromJson(json['alsoBestFriend']), + deleteMessagesAfterMilliseconds: serializer.fromJson( + json['deleteMessagesAfterMilliseconds'], + ), + createdAt: serializer.fromJson(json['createdAt']), + lastMessageSend: serializer.fromJson(json['lastMessageSend']), + lastMessageReceived: serializer.fromJson( + json['lastMessageReceived'], + ), + lastFlameCounterChange: serializer.fromJson( + json['lastFlameCounterChange'], + ), + lastFlameSync: serializer.fromJson(json['lastFlameSync']), + flameCounter: serializer.fromJson(json['flameCounter']), + maxFlameCounter: serializer.fromJson(json['maxFlameCounter']), + maxFlameCounterFrom: serializer.fromJson( + json['maxFlameCounterFrom'], + ), + lastMessageExchange: serializer.fromJson( + json['lastMessageExchange'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'isGroupAdmin': serializer.toJson(isGroupAdmin), + 'isDirectChat': serializer.toJson(isDirectChat), + 'pinned': serializer.toJson(pinned), + 'archived': serializer.toJson(archived), + 'joinedGroup': serializer.toJson(joinedGroup), + 'leftGroup': serializer.toJson(leftGroup), + 'deletedContent': serializer.toJson(deletedContent), + 'stateVersionId': serializer.toJson(stateVersionId), + 'stateEncryptionKey': serializer.toJson( + stateEncryptionKey, + ), + 'myGroupPrivateKey': serializer.toJson(myGroupPrivateKey), + 'groupName': serializer.toJson(groupName), + 'draftMessage': serializer.toJson(draftMessage), + 'totalMediaCounter': serializer.toJson(totalMediaCounter), + 'alsoBestFriend': serializer.toJson(alsoBestFriend), + 'deleteMessagesAfterMilliseconds': serializer.toJson( + deleteMessagesAfterMilliseconds, + ), + 'createdAt': serializer.toJson(createdAt), + 'lastMessageSend': serializer.toJson(lastMessageSend), + 'lastMessageReceived': serializer.toJson(lastMessageReceived), + 'lastFlameCounterChange': serializer.toJson(lastFlameCounterChange), + 'lastFlameSync': serializer.toJson(lastFlameSync), + 'flameCounter': serializer.toJson(flameCounter), + 'maxFlameCounter': serializer.toJson(maxFlameCounter), + 'maxFlameCounterFrom': serializer.toJson(maxFlameCounterFrom), + 'lastMessageExchange': serializer.toJson(lastMessageExchange), + }; + } + + GroupsData copyWith({ + String? groupId, + int? isGroupAdmin, + int? isDirectChat, + int? pinned, + int? archived, + int? joinedGroup, + int? leftGroup, + int? deletedContent, + int? stateVersionId, + Value stateEncryptionKey = const Value.absent(), + Value myGroupPrivateKey = const Value.absent(), + String? groupName, + Value draftMessage = const Value.absent(), + int? totalMediaCounter, + int? alsoBestFriend, + int? deleteMessagesAfterMilliseconds, + int? createdAt, + Value lastMessageSend = const Value.absent(), + Value lastMessageReceived = const Value.absent(), + Value lastFlameCounterChange = const Value.absent(), + Value lastFlameSync = const Value.absent(), + int? flameCounter, + int? maxFlameCounter, + Value maxFlameCounterFrom = const Value.absent(), + int? lastMessageExchange, + }) => GroupsData( + groupId: groupId ?? this.groupId, + isGroupAdmin: isGroupAdmin ?? this.isGroupAdmin, + isDirectChat: isDirectChat ?? this.isDirectChat, + pinned: pinned ?? this.pinned, + archived: archived ?? this.archived, + joinedGroup: joinedGroup ?? this.joinedGroup, + leftGroup: leftGroup ?? this.leftGroup, + deletedContent: deletedContent ?? this.deletedContent, + stateVersionId: stateVersionId ?? this.stateVersionId, + stateEncryptionKey: stateEncryptionKey.present + ? stateEncryptionKey.value + : this.stateEncryptionKey, + myGroupPrivateKey: myGroupPrivateKey.present + ? myGroupPrivateKey.value + : this.myGroupPrivateKey, + groupName: groupName ?? this.groupName, + draftMessage: draftMessage.present ? draftMessage.value : this.draftMessage, + totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter, + alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + deleteMessagesAfterMilliseconds ?? this.deleteMessagesAfterMilliseconds, + createdAt: createdAt ?? this.createdAt, + 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, + flameCounter: flameCounter ?? this.flameCounter, + maxFlameCounter: maxFlameCounter ?? this.maxFlameCounter, + maxFlameCounterFrom: maxFlameCounterFrom.present + ? maxFlameCounterFrom.value + : this.maxFlameCounterFrom, + lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, + ); + GroupsData copyWithCompanion(GroupsCompanion data) { + return GroupsData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + isGroupAdmin: data.isGroupAdmin.present + ? data.isGroupAdmin.value + : this.isGroupAdmin, + isDirectChat: data.isDirectChat.present + ? data.isDirectChat.value + : this.isDirectChat, + pinned: data.pinned.present ? data.pinned.value : this.pinned, + archived: data.archived.present ? data.archived.value : this.archived, + joinedGroup: data.joinedGroup.present + ? data.joinedGroup.value + : this.joinedGroup, + leftGroup: data.leftGroup.present ? data.leftGroup.value : this.leftGroup, + deletedContent: data.deletedContent.present + ? data.deletedContent.value + : this.deletedContent, + stateVersionId: data.stateVersionId.present + ? data.stateVersionId.value + : this.stateVersionId, + stateEncryptionKey: data.stateEncryptionKey.present + ? data.stateEncryptionKey.value + : this.stateEncryptionKey, + myGroupPrivateKey: data.myGroupPrivateKey.present + ? data.myGroupPrivateKey.value + : this.myGroupPrivateKey, + groupName: data.groupName.present ? data.groupName.value : this.groupName, + draftMessage: data.draftMessage.present + ? data.draftMessage.value + : this.draftMessage, + totalMediaCounter: data.totalMediaCounter.present + ? data.totalMediaCounter.value + : this.totalMediaCounter, + alsoBestFriend: data.alsoBestFriend.present + ? data.alsoBestFriend.value + : this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + data.deleteMessagesAfterMilliseconds.present + ? data.deleteMessagesAfterMilliseconds.value + : this.deleteMessagesAfterMilliseconds, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + 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, + flameCounter: data.flameCounter.present + ? data.flameCounter.value + : this.flameCounter, + maxFlameCounter: data.maxFlameCounter.present + ? data.maxFlameCounter.value + : this.maxFlameCounter, + maxFlameCounterFrom: data.maxFlameCounterFrom.present + ? data.maxFlameCounterFrom.value + : this.maxFlameCounterFrom, + lastMessageExchange: data.lastMessageExchange.present + ? data.lastMessageExchange.value + : this.lastMessageExchange, + ); + } + + @override + String toString() { + return (StringBuffer('GroupsData(') + ..write('groupId: $groupId, ') + ..write('isGroupAdmin: $isGroupAdmin, ') + ..write('isDirectChat: $isDirectChat, ') + ..write('pinned: $pinned, ') + ..write('archived: $archived, ') + ..write('joinedGroup: $joinedGroup, ') + ..write('leftGroup: $leftGroup, ') + ..write('deletedContent: $deletedContent, ') + ..write('stateVersionId: $stateVersionId, ') + ..write('stateEncryptionKey: $stateEncryptionKey, ') + ..write('myGroupPrivateKey: $myGroupPrivateKey, ') + ..write('groupName: $groupName, ') + ..write('draftMessage: $draftMessage, ') + ..write('totalMediaCounter: $totalMediaCounter, ') + ..write('alsoBestFriend: $alsoBestFriend, ') + ..write( + 'deleteMessagesAfterMilliseconds: $deleteMessagesAfterMilliseconds, ', + ) + ..write('createdAt: $createdAt, ') + ..write('lastMessageSend: $lastMessageSend, ') + ..write('lastMessageReceived: $lastMessageReceived, ') + ..write('lastFlameCounterChange: $lastFlameCounterChange, ') + ..write('lastFlameSync: $lastFlameSync, ') + ..write('flameCounter: $flameCounter, ') + ..write('maxFlameCounter: $maxFlameCounter, ') + ..write('maxFlameCounterFrom: $maxFlameCounterFrom, ') + ..write('lastMessageExchange: $lastMessageExchange') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hashAll([ + groupId, + isGroupAdmin, + isDirectChat, + pinned, + archived, + joinedGroup, + leftGroup, + deletedContent, + stateVersionId, + $driftBlobEquality.hash(stateEncryptionKey), + $driftBlobEquality.hash(myGroupPrivateKey), + groupName, + draftMessage, + totalMediaCounter, + alsoBestFriend, + deleteMessagesAfterMilliseconds, + createdAt, + lastMessageSend, + lastMessageReceived, + lastFlameCounterChange, + lastFlameSync, + flameCounter, + maxFlameCounter, + maxFlameCounterFrom, + lastMessageExchange, + ]); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupsData && + other.groupId == this.groupId && + other.isGroupAdmin == this.isGroupAdmin && + other.isDirectChat == this.isDirectChat && + other.pinned == this.pinned && + other.archived == this.archived && + other.joinedGroup == this.joinedGroup && + other.leftGroup == this.leftGroup && + other.deletedContent == this.deletedContent && + other.stateVersionId == this.stateVersionId && + $driftBlobEquality.equals( + other.stateEncryptionKey, + this.stateEncryptionKey, + ) && + $driftBlobEquality.equals( + other.myGroupPrivateKey, + this.myGroupPrivateKey, + ) && + other.groupName == this.groupName && + other.draftMessage == this.draftMessage && + other.totalMediaCounter == this.totalMediaCounter && + other.alsoBestFriend == this.alsoBestFriend && + other.deleteMessagesAfterMilliseconds == + this.deleteMessagesAfterMilliseconds && + other.createdAt == this.createdAt && + other.lastMessageSend == this.lastMessageSend && + other.lastMessageReceived == this.lastMessageReceived && + other.lastFlameCounterChange == this.lastFlameCounterChange && + other.lastFlameSync == this.lastFlameSync && + other.flameCounter == this.flameCounter && + other.maxFlameCounter == this.maxFlameCounter && + other.maxFlameCounterFrom == this.maxFlameCounterFrom && + other.lastMessageExchange == this.lastMessageExchange); +} + +class GroupsCompanion extends UpdateCompanion { + final Value groupId; + final Value isGroupAdmin; + final Value isDirectChat; + final Value pinned; + final Value archived; + final Value joinedGroup; + final Value leftGroup; + final Value deletedContent; + final Value stateVersionId; + final Value stateEncryptionKey; + final Value myGroupPrivateKey; + final Value groupName; + final Value draftMessage; + final Value totalMediaCounter; + final Value alsoBestFriend; + final Value deleteMessagesAfterMilliseconds; + final Value createdAt; + final Value lastMessageSend; + final Value lastMessageReceived; + final Value lastFlameCounterChange; + final Value lastFlameSync; + final Value flameCounter; + final Value maxFlameCounter; + final Value maxFlameCounterFrom; + final Value lastMessageExchange; + final Value rowid; + const GroupsCompanion({ + this.groupId = const Value.absent(), + this.isGroupAdmin = const Value.absent(), + this.isDirectChat = const Value.absent(), + this.pinned = const Value.absent(), + this.archived = const Value.absent(), + this.joinedGroup = const Value.absent(), + this.leftGroup = const Value.absent(), + this.deletedContent = const Value.absent(), + this.stateVersionId = const Value.absent(), + this.stateEncryptionKey = const Value.absent(), + this.myGroupPrivateKey = const Value.absent(), + this.groupName = const Value.absent(), + this.draftMessage = const Value.absent(), + this.totalMediaCounter = const Value.absent(), + this.alsoBestFriend = const Value.absent(), + this.deleteMessagesAfterMilliseconds = const Value.absent(), + this.createdAt = const Value.absent(), + this.lastMessageSend = const Value.absent(), + this.lastMessageReceived = const Value.absent(), + this.lastFlameCounterChange = const Value.absent(), + this.lastFlameSync = const Value.absent(), + this.flameCounter = const Value.absent(), + this.maxFlameCounter = const Value.absent(), + this.maxFlameCounterFrom = const Value.absent(), + this.lastMessageExchange = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupsCompanion.insert({ + required String groupId, + this.isGroupAdmin = const Value.absent(), + this.isDirectChat = const Value.absent(), + this.pinned = const Value.absent(), + this.archived = const Value.absent(), + this.joinedGroup = const Value.absent(), + this.leftGroup = const Value.absent(), + this.deletedContent = const Value.absent(), + this.stateVersionId = const Value.absent(), + this.stateEncryptionKey = const Value.absent(), + this.myGroupPrivateKey = const Value.absent(), + required String groupName, + this.draftMessage = const Value.absent(), + this.totalMediaCounter = const Value.absent(), + this.alsoBestFriend = const Value.absent(), + this.deleteMessagesAfterMilliseconds = const Value.absent(), + this.createdAt = const Value.absent(), + this.lastMessageSend = const Value.absent(), + this.lastMessageReceived = const Value.absent(), + this.lastFlameCounterChange = const Value.absent(), + this.lastFlameSync = const Value.absent(), + this.flameCounter = const Value.absent(), + this.maxFlameCounter = const Value.absent(), + this.maxFlameCounterFrom = const Value.absent(), + this.lastMessageExchange = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + groupName = Value(groupName); + static Insertable custom({ + Expression? groupId, + Expression? isGroupAdmin, + Expression? isDirectChat, + Expression? pinned, + Expression? archived, + Expression? joinedGroup, + Expression? leftGroup, + Expression? deletedContent, + Expression? stateVersionId, + Expression? stateEncryptionKey, + Expression? myGroupPrivateKey, + Expression? groupName, + Expression? draftMessage, + Expression? totalMediaCounter, + Expression? alsoBestFriend, + Expression? deleteMessagesAfterMilliseconds, + Expression? createdAt, + Expression? lastMessageSend, + Expression? lastMessageReceived, + Expression? lastFlameCounterChange, + Expression? lastFlameSync, + Expression? flameCounter, + Expression? maxFlameCounter, + Expression? maxFlameCounterFrom, + Expression? lastMessageExchange, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (isGroupAdmin != null) 'is_group_admin': isGroupAdmin, + if (isDirectChat != null) 'is_direct_chat': isDirectChat, + if (pinned != null) 'pinned': pinned, + if (archived != null) 'archived': archived, + if (joinedGroup != null) 'joined_group': joinedGroup, + if (leftGroup != null) 'left_group': leftGroup, + if (deletedContent != null) 'deleted_content': deletedContent, + if (stateVersionId != null) 'state_version_id': stateVersionId, + if (stateEncryptionKey != null) + 'state_encryption_key': stateEncryptionKey, + if (myGroupPrivateKey != null) 'my_group_private_key': myGroupPrivateKey, + if (groupName != null) 'group_name': groupName, + if (draftMessage != null) 'draft_message': draftMessage, + if (totalMediaCounter != null) 'total_media_counter': totalMediaCounter, + if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend, + if (deleteMessagesAfterMilliseconds != null) + 'delete_messages_after_milliseconds': deleteMessagesAfterMilliseconds, + if (createdAt != null) 'created_at': createdAt, + 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 (flameCounter != null) 'flame_counter': flameCounter, + if (maxFlameCounter != null) 'max_flame_counter': maxFlameCounter, + if (maxFlameCounterFrom != null) + 'max_flame_counter_from': maxFlameCounterFrom, + if (lastMessageExchange != null) + 'last_message_exchange': lastMessageExchange, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupsCompanion copyWith({ + Value? groupId, + Value? isGroupAdmin, + Value? isDirectChat, + Value? pinned, + Value? archived, + Value? joinedGroup, + Value? leftGroup, + Value? deletedContent, + Value? stateVersionId, + Value? stateEncryptionKey, + Value? myGroupPrivateKey, + Value? groupName, + Value? draftMessage, + Value? totalMediaCounter, + Value? alsoBestFriend, + Value? deleteMessagesAfterMilliseconds, + Value? createdAt, + Value? lastMessageSend, + Value? lastMessageReceived, + Value? lastFlameCounterChange, + Value? lastFlameSync, + Value? flameCounter, + Value? maxFlameCounter, + Value? maxFlameCounterFrom, + Value? lastMessageExchange, + Value? rowid, + }) { + return GroupsCompanion( + groupId: groupId ?? this.groupId, + isGroupAdmin: isGroupAdmin ?? this.isGroupAdmin, + isDirectChat: isDirectChat ?? this.isDirectChat, + pinned: pinned ?? this.pinned, + archived: archived ?? this.archived, + joinedGroup: joinedGroup ?? this.joinedGroup, + leftGroup: leftGroup ?? this.leftGroup, + deletedContent: deletedContent ?? this.deletedContent, + stateVersionId: stateVersionId ?? this.stateVersionId, + stateEncryptionKey: stateEncryptionKey ?? this.stateEncryptionKey, + myGroupPrivateKey: myGroupPrivateKey ?? this.myGroupPrivateKey, + groupName: groupName ?? this.groupName, + draftMessage: draftMessage ?? this.draftMessage, + totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter, + alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + deleteMessagesAfterMilliseconds ?? + this.deleteMessagesAfterMilliseconds, + createdAt: createdAt ?? this.createdAt, + lastMessageSend: lastMessageSend ?? this.lastMessageSend, + lastMessageReceived: lastMessageReceived ?? this.lastMessageReceived, + lastFlameCounterChange: + lastFlameCounterChange ?? this.lastFlameCounterChange, + lastFlameSync: lastFlameSync ?? this.lastFlameSync, + flameCounter: flameCounter ?? this.flameCounter, + maxFlameCounter: maxFlameCounter ?? this.maxFlameCounter, + maxFlameCounterFrom: maxFlameCounterFrom ?? this.maxFlameCounterFrom, + lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (isGroupAdmin.present) { + map['is_group_admin'] = Variable(isGroupAdmin.value); + } + if (isDirectChat.present) { + map['is_direct_chat'] = Variable(isDirectChat.value); + } + if (pinned.present) { + map['pinned'] = Variable(pinned.value); + } + if (archived.present) { + map['archived'] = Variable(archived.value); + } + if (joinedGroup.present) { + map['joined_group'] = Variable(joinedGroup.value); + } + if (leftGroup.present) { + map['left_group'] = Variable(leftGroup.value); + } + if (deletedContent.present) { + map['deleted_content'] = Variable(deletedContent.value); + } + if (stateVersionId.present) { + map['state_version_id'] = Variable(stateVersionId.value); + } + if (stateEncryptionKey.present) { + map['state_encryption_key'] = Variable( + stateEncryptionKey.value, + ); + } + if (myGroupPrivateKey.present) { + map['my_group_private_key'] = Variable( + myGroupPrivateKey.value, + ); + } + if (groupName.present) { + map['group_name'] = Variable(groupName.value); + } + if (draftMessage.present) { + map['draft_message'] = Variable(draftMessage.value); + } + if (totalMediaCounter.present) { + map['total_media_counter'] = Variable(totalMediaCounter.value); + } + if (alsoBestFriend.present) { + map['also_best_friend'] = Variable(alsoBestFriend.value); + } + if (deleteMessagesAfterMilliseconds.present) { + map['delete_messages_after_milliseconds'] = Variable( + deleteMessagesAfterMilliseconds.value, + ); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.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 (flameCounter.present) { + map['flame_counter'] = Variable(flameCounter.value); + } + if (maxFlameCounter.present) { + map['max_flame_counter'] = Variable(maxFlameCounter.value); + } + if (maxFlameCounterFrom.present) { + map['max_flame_counter_from'] = Variable(maxFlameCounterFrom.value); + } + if (lastMessageExchange.present) { + map['last_message_exchange'] = Variable(lastMessageExchange.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GroupsCompanion(') + ..write('groupId: $groupId, ') + ..write('isGroupAdmin: $isGroupAdmin, ') + ..write('isDirectChat: $isDirectChat, ') + ..write('pinned: $pinned, ') + ..write('archived: $archived, ') + ..write('joinedGroup: $joinedGroup, ') + ..write('leftGroup: $leftGroup, ') + ..write('deletedContent: $deletedContent, ') + ..write('stateVersionId: $stateVersionId, ') + ..write('stateEncryptionKey: $stateEncryptionKey, ') + ..write('myGroupPrivateKey: $myGroupPrivateKey, ') + ..write('groupName: $groupName, ') + ..write('draftMessage: $draftMessage, ') + ..write('totalMediaCounter: $totalMediaCounter, ') + ..write('alsoBestFriend: $alsoBestFriend, ') + ..write( + 'deleteMessagesAfterMilliseconds: $deleteMessagesAfterMilliseconds, ', + ) + ..write('createdAt: $createdAt, ') + ..write('lastMessageSend: $lastMessageSend, ') + ..write('lastMessageReceived: $lastMessageReceived, ') + ..write('lastFlameCounterChange: $lastFlameCounterChange, ') + ..write('lastFlameSync: $lastFlameSync, ') + ..write('flameCounter: $flameCounter, ') + ..write('maxFlameCounter: $maxFlameCounter, ') + ..write('maxFlameCounterFrom: $maxFlameCounterFrom, ') + ..write('lastMessageExchange: $lastMessageExchange, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class MediaFiles extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MediaFiles(this.attachedDatabase, [this._alias]); + late final GeneratedColumn mediaId = GeneratedColumn( + 'media_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn uploadState = GeneratedColumn( + 'upload_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn downloadState = GeneratedColumn( + 'download_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn requiresAuthentication = GeneratedColumn( + 'requires_authentication', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (requires_authentication IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stored = GeneratedColumn( + 'stored', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK ("stored" IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn isDraftMedia = GeneratedColumn( + 'is_draft_media', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_draft_media IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn preProgressingProcess = GeneratedColumn( + 'pre_progressing_process', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn reuploadRequestedBy = + GeneratedColumn( + 'reupload_requested_by', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn displayLimitInMilliseconds = + GeneratedColumn( + 'display_limit_in_milliseconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn removeAudio = GeneratedColumn( + 'remove_audio', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL CHECK (remove_audio IN (0, 1))', + ); + late final GeneratedColumn downloadToken = + GeneratedColumn( + 'download_token', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionKey = + GeneratedColumn( + 'encryption_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionMac = + GeneratedColumn( + 'encryption_mac', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionNonce = + GeneratedColumn( + 'encryption_nonce', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn storedFileHash = + GeneratedColumn( + 'stored_file_hash', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + mediaId, + type, + uploadState, + downloadState, + requiresAuthentication, + stored, + isDraftMedia, + preProgressingProcess, + reuploadRequestedBy, + displayLimitInMilliseconds, + removeAudio, + downloadToken, + encryptionKey, + encryptionMac, + encryptionNonce, + storedFileHash, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'media_files'; + @override + Set get $primaryKey => {mediaId}; + @override + MediaFilesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MediaFilesData( + mediaId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}media_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + uploadState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}upload_state'], + ), + downloadState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}download_state'], + ), + requiresAuthentication: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}requires_authentication'], + )!, + stored: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}stored'], + )!, + isDraftMedia: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_draft_media'], + )!, + preProgressingProcess: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}pre_progressing_process'], + ), + reuploadRequestedBy: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}reupload_requested_by'], + ), + displayLimitInMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}display_limit_in_milliseconds'], + ), + removeAudio: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}remove_audio'], + ), + downloadToken: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}download_token'], + ), + encryptionKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_key'], + ), + encryptionMac: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_mac'], + ), + encryptionNonce: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_nonce'], + ), + storedFileHash: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}stored_file_hash'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + MediaFiles createAlias(String alias) { + return MediaFiles(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(media_id)']; + @override + bool get dontWriteConstraints => true; +} + +class MediaFilesData extends DataClass implements Insertable { + final String mediaId; + final String type; + final String? uploadState; + final String? downloadState; + final int requiresAuthentication; + final int stored; + final int isDraftMedia; + final int? preProgressingProcess; + final String? reuploadRequestedBy; + final int? displayLimitInMilliseconds; + final int? removeAudio; + final i2.Uint8List? downloadToken; + final i2.Uint8List? encryptionKey; + final i2.Uint8List? encryptionMac; + final i2.Uint8List? encryptionNonce; + final i2.Uint8List? storedFileHash; + final int createdAt; + const MediaFilesData({ + required this.mediaId, + required this.type, + this.uploadState, + this.downloadState, + required this.requiresAuthentication, + required this.stored, + required this.isDraftMedia, + this.preProgressingProcess, + this.reuploadRequestedBy, + this.displayLimitInMilliseconds, + this.removeAudio, + this.downloadToken, + this.encryptionKey, + this.encryptionMac, + this.encryptionNonce, + this.storedFileHash, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['media_id'] = Variable(mediaId); + map['type'] = Variable(type); + if (!nullToAbsent || uploadState != null) { + map['upload_state'] = Variable(uploadState); + } + if (!nullToAbsent || downloadState != null) { + map['download_state'] = Variable(downloadState); + } + map['requires_authentication'] = Variable(requiresAuthentication); + map['stored'] = Variable(stored); + map['is_draft_media'] = Variable(isDraftMedia); + if (!nullToAbsent || preProgressingProcess != null) { + map['pre_progressing_process'] = Variable(preProgressingProcess); + } + if (!nullToAbsent || reuploadRequestedBy != null) { + map['reupload_requested_by'] = Variable(reuploadRequestedBy); + } + if (!nullToAbsent || displayLimitInMilliseconds != null) { + map['display_limit_in_milliseconds'] = Variable( + displayLimitInMilliseconds, + ); + } + if (!nullToAbsent || removeAudio != null) { + map['remove_audio'] = Variable(removeAudio); + } + if (!nullToAbsent || downloadToken != null) { + map['download_token'] = Variable(downloadToken); + } + if (!nullToAbsent || encryptionKey != null) { + map['encryption_key'] = Variable(encryptionKey); + } + if (!nullToAbsent || encryptionMac != null) { + map['encryption_mac'] = Variable(encryptionMac); + } + if (!nullToAbsent || encryptionNonce != null) { + map['encryption_nonce'] = Variable(encryptionNonce); + } + if (!nullToAbsent || storedFileHash != null) { + map['stored_file_hash'] = Variable(storedFileHash); + } + map['created_at'] = Variable(createdAt); + return map; + } + + MediaFilesCompanion toCompanion(bool nullToAbsent) { + return MediaFilesCompanion( + mediaId: Value(mediaId), + type: Value(type), + uploadState: uploadState == null && nullToAbsent + ? const Value.absent() + : Value(uploadState), + downloadState: downloadState == null && nullToAbsent + ? const Value.absent() + : Value(downloadState), + requiresAuthentication: Value(requiresAuthentication), + stored: Value(stored), + isDraftMedia: Value(isDraftMedia), + preProgressingProcess: preProgressingProcess == null && nullToAbsent + ? const Value.absent() + : Value(preProgressingProcess), + reuploadRequestedBy: reuploadRequestedBy == null && nullToAbsent + ? const Value.absent() + : Value(reuploadRequestedBy), + displayLimitInMilliseconds: + displayLimitInMilliseconds == null && nullToAbsent + ? const Value.absent() + : Value(displayLimitInMilliseconds), + removeAudio: removeAudio == null && nullToAbsent + ? const Value.absent() + : Value(removeAudio), + downloadToken: downloadToken == null && nullToAbsent + ? const Value.absent() + : Value(downloadToken), + encryptionKey: encryptionKey == null && nullToAbsent + ? const Value.absent() + : Value(encryptionKey), + encryptionMac: encryptionMac == null && nullToAbsent + ? const Value.absent() + : Value(encryptionMac), + encryptionNonce: encryptionNonce == null && nullToAbsent + ? const Value.absent() + : Value(encryptionNonce), + storedFileHash: storedFileHash == null && nullToAbsent + ? const Value.absent() + : Value(storedFileHash), + createdAt: Value(createdAt), + ); + } + + factory MediaFilesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MediaFilesData( + mediaId: serializer.fromJson(json['mediaId']), + type: serializer.fromJson(json['type']), + uploadState: serializer.fromJson(json['uploadState']), + downloadState: serializer.fromJson(json['downloadState']), + requiresAuthentication: serializer.fromJson( + json['requiresAuthentication'], + ), + stored: serializer.fromJson(json['stored']), + isDraftMedia: serializer.fromJson(json['isDraftMedia']), + preProgressingProcess: serializer.fromJson( + json['preProgressingProcess'], + ), + reuploadRequestedBy: serializer.fromJson( + json['reuploadRequestedBy'], + ), + displayLimitInMilliseconds: serializer.fromJson( + json['displayLimitInMilliseconds'], + ), + removeAudio: serializer.fromJson(json['removeAudio']), + downloadToken: serializer.fromJson(json['downloadToken']), + encryptionKey: serializer.fromJson(json['encryptionKey']), + encryptionMac: serializer.fromJson(json['encryptionMac']), + encryptionNonce: serializer.fromJson( + json['encryptionNonce'], + ), + storedFileHash: serializer.fromJson( + json['storedFileHash'], + ), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'mediaId': serializer.toJson(mediaId), + 'type': serializer.toJson(type), + 'uploadState': serializer.toJson(uploadState), + 'downloadState': serializer.toJson(downloadState), + 'requiresAuthentication': serializer.toJson(requiresAuthentication), + 'stored': serializer.toJson(stored), + 'isDraftMedia': serializer.toJson(isDraftMedia), + 'preProgressingProcess': serializer.toJson(preProgressingProcess), + 'reuploadRequestedBy': serializer.toJson(reuploadRequestedBy), + 'displayLimitInMilliseconds': serializer.toJson( + displayLimitInMilliseconds, + ), + 'removeAudio': serializer.toJson(removeAudio), + 'downloadToken': serializer.toJson(downloadToken), + 'encryptionKey': serializer.toJson(encryptionKey), + 'encryptionMac': serializer.toJson(encryptionMac), + 'encryptionNonce': serializer.toJson(encryptionNonce), + 'storedFileHash': serializer.toJson(storedFileHash), + 'createdAt': serializer.toJson(createdAt), + }; + } + + MediaFilesData copyWith({ + String? mediaId, + String? type, + Value uploadState = const Value.absent(), + Value downloadState = const Value.absent(), + int? requiresAuthentication, + int? stored, + int? isDraftMedia, + Value preProgressingProcess = const Value.absent(), + Value reuploadRequestedBy = const Value.absent(), + Value displayLimitInMilliseconds = const Value.absent(), + Value removeAudio = const Value.absent(), + Value downloadToken = const Value.absent(), + Value encryptionKey = const Value.absent(), + Value encryptionMac = const Value.absent(), + Value encryptionNonce = const Value.absent(), + Value storedFileHash = const Value.absent(), + int? createdAt, + }) => MediaFilesData( + mediaId: mediaId ?? this.mediaId, + type: type ?? this.type, + uploadState: uploadState.present ? uploadState.value : this.uploadState, + downloadState: downloadState.present + ? downloadState.value + : this.downloadState, + requiresAuthentication: + requiresAuthentication ?? this.requiresAuthentication, + stored: stored ?? this.stored, + isDraftMedia: isDraftMedia ?? this.isDraftMedia, + preProgressingProcess: preProgressingProcess.present + ? preProgressingProcess.value + : this.preProgressingProcess, + reuploadRequestedBy: reuploadRequestedBy.present + ? reuploadRequestedBy.value + : this.reuploadRequestedBy, + displayLimitInMilliseconds: displayLimitInMilliseconds.present + ? displayLimitInMilliseconds.value + : this.displayLimitInMilliseconds, + removeAudio: removeAudio.present ? removeAudio.value : this.removeAudio, + downloadToken: downloadToken.present + ? downloadToken.value + : this.downloadToken, + encryptionKey: encryptionKey.present + ? encryptionKey.value + : this.encryptionKey, + encryptionMac: encryptionMac.present + ? encryptionMac.value + : this.encryptionMac, + encryptionNonce: encryptionNonce.present + ? encryptionNonce.value + : this.encryptionNonce, + storedFileHash: storedFileHash.present + ? storedFileHash.value + : this.storedFileHash, + createdAt: createdAt ?? this.createdAt, + ); + MediaFilesData copyWithCompanion(MediaFilesCompanion data) { + return MediaFilesData( + mediaId: data.mediaId.present ? data.mediaId.value : this.mediaId, + type: data.type.present ? data.type.value : this.type, + uploadState: data.uploadState.present + ? data.uploadState.value + : this.uploadState, + downloadState: data.downloadState.present + ? data.downloadState.value + : this.downloadState, + requiresAuthentication: data.requiresAuthentication.present + ? data.requiresAuthentication.value + : this.requiresAuthentication, + stored: data.stored.present ? data.stored.value : this.stored, + isDraftMedia: data.isDraftMedia.present + ? data.isDraftMedia.value + : this.isDraftMedia, + preProgressingProcess: data.preProgressingProcess.present + ? data.preProgressingProcess.value + : this.preProgressingProcess, + reuploadRequestedBy: data.reuploadRequestedBy.present + ? data.reuploadRequestedBy.value + : this.reuploadRequestedBy, + displayLimitInMilliseconds: data.displayLimitInMilliseconds.present + ? data.displayLimitInMilliseconds.value + : this.displayLimitInMilliseconds, + removeAudio: data.removeAudio.present + ? data.removeAudio.value + : this.removeAudio, + downloadToken: data.downloadToken.present + ? data.downloadToken.value + : this.downloadToken, + encryptionKey: data.encryptionKey.present + ? data.encryptionKey.value + : this.encryptionKey, + encryptionMac: data.encryptionMac.present + ? data.encryptionMac.value + : this.encryptionMac, + encryptionNonce: data.encryptionNonce.present + ? data.encryptionNonce.value + : this.encryptionNonce, + storedFileHash: data.storedFileHash.present + ? data.storedFileHash.value + : this.storedFileHash, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('MediaFilesData(') + ..write('mediaId: $mediaId, ') + ..write('type: $type, ') + ..write('uploadState: $uploadState, ') + ..write('downloadState: $downloadState, ') + ..write('requiresAuthentication: $requiresAuthentication, ') + ..write('stored: $stored, ') + ..write('isDraftMedia: $isDraftMedia, ') + ..write('preProgressingProcess: $preProgressingProcess, ') + ..write('reuploadRequestedBy: $reuploadRequestedBy, ') + ..write('displayLimitInMilliseconds: $displayLimitInMilliseconds, ') + ..write('removeAudio: $removeAudio, ') + ..write('downloadToken: $downloadToken, ') + ..write('encryptionKey: $encryptionKey, ') + ..write('encryptionMac: $encryptionMac, ') + ..write('encryptionNonce: $encryptionNonce, ') + ..write('storedFileHash: $storedFileHash, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + mediaId, + type, + uploadState, + downloadState, + requiresAuthentication, + stored, + isDraftMedia, + preProgressingProcess, + reuploadRequestedBy, + displayLimitInMilliseconds, + removeAudio, + $driftBlobEquality.hash(downloadToken), + $driftBlobEquality.hash(encryptionKey), + $driftBlobEquality.hash(encryptionMac), + $driftBlobEquality.hash(encryptionNonce), + $driftBlobEquality.hash(storedFileHash), + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MediaFilesData && + other.mediaId == this.mediaId && + other.type == this.type && + other.uploadState == this.uploadState && + other.downloadState == this.downloadState && + other.requiresAuthentication == this.requiresAuthentication && + other.stored == this.stored && + other.isDraftMedia == this.isDraftMedia && + other.preProgressingProcess == this.preProgressingProcess && + other.reuploadRequestedBy == this.reuploadRequestedBy && + other.displayLimitInMilliseconds == this.displayLimitInMilliseconds && + other.removeAudio == this.removeAudio && + $driftBlobEquality.equals(other.downloadToken, this.downloadToken) && + $driftBlobEquality.equals(other.encryptionKey, this.encryptionKey) && + $driftBlobEquality.equals(other.encryptionMac, this.encryptionMac) && + $driftBlobEquality.equals( + other.encryptionNonce, + this.encryptionNonce, + ) && + $driftBlobEquality.equals( + other.storedFileHash, + this.storedFileHash, + ) && + other.createdAt == this.createdAt); +} + +class MediaFilesCompanion extends UpdateCompanion { + final Value mediaId; + final Value type; + final Value uploadState; + final Value downloadState; + final Value requiresAuthentication; + final Value stored; + final Value isDraftMedia; + final Value preProgressingProcess; + final Value reuploadRequestedBy; + final Value displayLimitInMilliseconds; + final Value removeAudio; + final Value downloadToken; + final Value encryptionKey; + final Value encryptionMac; + final Value encryptionNonce; + final Value storedFileHash; + final Value createdAt; + final Value rowid; + const MediaFilesCompanion({ + this.mediaId = const Value.absent(), + this.type = const Value.absent(), + this.uploadState = const Value.absent(), + this.downloadState = const Value.absent(), + this.requiresAuthentication = const Value.absent(), + this.stored = const Value.absent(), + this.isDraftMedia = const Value.absent(), + this.preProgressingProcess = const Value.absent(), + this.reuploadRequestedBy = const Value.absent(), + this.displayLimitInMilliseconds = const Value.absent(), + this.removeAudio = const Value.absent(), + this.downloadToken = const Value.absent(), + this.encryptionKey = const Value.absent(), + this.encryptionMac = const Value.absent(), + this.encryptionNonce = const Value.absent(), + this.storedFileHash = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + MediaFilesCompanion.insert({ + required String mediaId, + required String type, + this.uploadState = const Value.absent(), + this.downloadState = const Value.absent(), + this.requiresAuthentication = const Value.absent(), + this.stored = const Value.absent(), + this.isDraftMedia = const Value.absent(), + this.preProgressingProcess = const Value.absent(), + this.reuploadRequestedBy = const Value.absent(), + this.displayLimitInMilliseconds = const Value.absent(), + this.removeAudio = const Value.absent(), + this.downloadToken = const Value.absent(), + this.encryptionKey = const Value.absent(), + this.encryptionMac = const Value.absent(), + this.encryptionNonce = const Value.absent(), + this.storedFileHash = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : mediaId = Value(mediaId), + type = Value(type); + static Insertable custom({ + Expression? mediaId, + Expression? type, + Expression? uploadState, + Expression? downloadState, + Expression? requiresAuthentication, + Expression? stored, + Expression? isDraftMedia, + Expression? preProgressingProcess, + Expression? reuploadRequestedBy, + Expression? displayLimitInMilliseconds, + Expression? removeAudio, + Expression? downloadToken, + Expression? encryptionKey, + Expression? encryptionMac, + Expression? encryptionNonce, + Expression? storedFileHash, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (mediaId != null) 'media_id': mediaId, + if (type != null) 'type': type, + if (uploadState != null) 'upload_state': uploadState, + if (downloadState != null) 'download_state': downloadState, + if (requiresAuthentication != null) + 'requires_authentication': requiresAuthentication, + if (stored != null) 'stored': stored, + if (isDraftMedia != null) 'is_draft_media': isDraftMedia, + if (preProgressingProcess != null) + 'pre_progressing_process': preProgressingProcess, + if (reuploadRequestedBy != null) + 'reupload_requested_by': reuploadRequestedBy, + if (displayLimitInMilliseconds != null) + 'display_limit_in_milliseconds': displayLimitInMilliseconds, + if (removeAudio != null) 'remove_audio': removeAudio, + if (downloadToken != null) 'download_token': downloadToken, + if (encryptionKey != null) 'encryption_key': encryptionKey, + if (encryptionMac != null) 'encryption_mac': encryptionMac, + if (encryptionNonce != null) 'encryption_nonce': encryptionNonce, + if (storedFileHash != null) 'stored_file_hash': storedFileHash, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + MediaFilesCompanion copyWith({ + Value? mediaId, + Value? type, + Value? uploadState, + Value? downloadState, + Value? requiresAuthentication, + Value? stored, + Value? isDraftMedia, + Value? preProgressingProcess, + Value? reuploadRequestedBy, + Value? displayLimitInMilliseconds, + Value? removeAudio, + Value? downloadToken, + Value? encryptionKey, + Value? encryptionMac, + Value? encryptionNonce, + Value? storedFileHash, + Value? createdAt, + Value? rowid, + }) { + return MediaFilesCompanion( + mediaId: mediaId ?? this.mediaId, + type: type ?? this.type, + uploadState: uploadState ?? this.uploadState, + downloadState: downloadState ?? this.downloadState, + requiresAuthentication: + requiresAuthentication ?? this.requiresAuthentication, + stored: stored ?? this.stored, + isDraftMedia: isDraftMedia ?? this.isDraftMedia, + preProgressingProcess: + preProgressingProcess ?? this.preProgressingProcess, + reuploadRequestedBy: reuploadRequestedBy ?? this.reuploadRequestedBy, + displayLimitInMilliseconds: + displayLimitInMilliseconds ?? this.displayLimitInMilliseconds, + removeAudio: removeAudio ?? this.removeAudio, + downloadToken: downloadToken ?? this.downloadToken, + encryptionKey: encryptionKey ?? this.encryptionKey, + encryptionMac: encryptionMac ?? this.encryptionMac, + encryptionNonce: encryptionNonce ?? this.encryptionNonce, + storedFileHash: storedFileHash ?? this.storedFileHash, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (mediaId.present) { + map['media_id'] = Variable(mediaId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (uploadState.present) { + map['upload_state'] = Variable(uploadState.value); + } + if (downloadState.present) { + map['download_state'] = Variable(downloadState.value); + } + if (requiresAuthentication.present) { + map['requires_authentication'] = Variable( + requiresAuthentication.value, + ); + } + if (stored.present) { + map['stored'] = Variable(stored.value); + } + if (isDraftMedia.present) { + map['is_draft_media'] = Variable(isDraftMedia.value); + } + if (preProgressingProcess.present) { + map['pre_progressing_process'] = Variable( + preProgressingProcess.value, + ); + } + if (reuploadRequestedBy.present) { + map['reupload_requested_by'] = Variable( + reuploadRequestedBy.value, + ); + } + if (displayLimitInMilliseconds.present) { + map['display_limit_in_milliseconds'] = Variable( + displayLimitInMilliseconds.value, + ); + } + if (removeAudio.present) { + map['remove_audio'] = Variable(removeAudio.value); + } + if (downloadToken.present) { + map['download_token'] = Variable(downloadToken.value); + } + if (encryptionKey.present) { + map['encryption_key'] = Variable(encryptionKey.value); + } + if (encryptionMac.present) { + map['encryption_mac'] = Variable(encryptionMac.value); + } + if (encryptionNonce.present) { + map['encryption_nonce'] = Variable(encryptionNonce.value); + } + if (storedFileHash.present) { + map['stored_file_hash'] = Variable(storedFileHash.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('MediaFilesCompanion(') + ..write('mediaId: $mediaId, ') + ..write('type: $type, ') + ..write('uploadState: $uploadState, ') + ..write('downloadState: $downloadState, ') + ..write('requiresAuthentication: $requiresAuthentication, ') + ..write('stored: $stored, ') + ..write('isDraftMedia: $isDraftMedia, ') + ..write('preProgressingProcess: $preProgressingProcess, ') + ..write('reuploadRequestedBy: $reuploadRequestedBy, ') + ..write('displayLimitInMilliseconds: $displayLimitInMilliseconds, ') + ..write('removeAudio: $removeAudio, ') + ..write('downloadToken: $downloadToken, ') + ..write('encryptionKey: $encryptionKey, ') + ..write('encryptionMac: $encryptionMac, ') + ..write('encryptionNonce: $encryptionNonce, ') + ..write('storedFileHash: $storedFileHash, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class Messages extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Messages(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderId = GeneratedColumn( + 'sender_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn content = GeneratedColumn( + 'content', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mediaId = GeneratedColumn( + 'media_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: + 'NULL REFERENCES media_files(media_id)ON DELETE SET NULL', + ); + late final GeneratedColumn additionalMessageData = + GeneratedColumn( + 'additional_message_data', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mediaStored = GeneratedColumn( + 'media_stored', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (media_stored IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn mediaReopened = GeneratedColumn( + 'media_reopened', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (media_reopened IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn downloadToken = + GeneratedColumn( + 'download_token', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quotesMessageId = GeneratedColumn( + 'quotes_message_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn isDeletedFromSender = GeneratedColumn( + 'is_deleted_from_sender', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (is_deleted_from_sender IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn openedAt = GeneratedColumn( + 'opened_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn openedByAll = GeneratedColumn( + 'opened_by_all', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn modifiedAt = GeneratedColumn( + 'modified_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByUser = GeneratedColumn( + 'ack_by_user', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByServer = GeneratedColumn( + 'ack_by_server', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + groupId, + messageId, + senderId, + type, + content, + mediaId, + additionalMessageData, + mediaStored, + mediaReopened, + downloadToken, + quotesMessageId, + isDeletedFromSender, + openedAt, + openedByAll, + createdAt, + modifiedAt, + ackByUser, + ackByServer, + ]; + @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( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + senderId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_id'], + ), + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + content: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}content'], + ), + mediaId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}media_id'], + ), + additionalMessageData: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}additional_message_data'], + ), + mediaStored: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_stored'], + )!, + mediaReopened: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_reopened'], + )!, + downloadToken: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}download_token'], + ), + quotesMessageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}quotes_message_id'], + ), + isDeletedFromSender: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_deleted_from_sender'], + )!, + openedAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}opened_at'], + ), + openedByAll: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}opened_by_all'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + modifiedAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}modified_at'], + ), + ackByUser: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_user'], + ), + ackByServer: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_server'], + ), + ); + } + + @override + Messages createAlias(String alias) { + return Messages(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(message_id)']; + @override + bool get dontWriteConstraints => true; +} + +class MessagesData extends DataClass implements Insertable { + final String groupId; + final String messageId; + final int? senderId; + final String type; + final String? content; + final String? mediaId; + final i2.Uint8List? additionalMessageData; + final int mediaStored; + final int mediaReopened; + final i2.Uint8List? downloadToken; + final String? quotesMessageId; + final int isDeletedFromSender; + final int? openedAt; + final int? openedByAll; + final int createdAt; + final int? modifiedAt; + final int? ackByUser; + final int? ackByServer; + const MessagesData({ + required this.groupId, + required this.messageId, + this.senderId, + required this.type, + this.content, + this.mediaId, + this.additionalMessageData, + required this.mediaStored, + required this.mediaReopened, + this.downloadToken, + this.quotesMessageId, + required this.isDeletedFromSender, + this.openedAt, + this.openedByAll, + required this.createdAt, + this.modifiedAt, + this.ackByUser, + this.ackByServer, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['message_id'] = Variable(messageId); + if (!nullToAbsent || senderId != null) { + map['sender_id'] = Variable(senderId); + } + map['type'] = Variable(type); + if (!nullToAbsent || content != null) { + map['content'] = Variable(content); + } + if (!nullToAbsent || mediaId != null) { + map['media_id'] = Variable(mediaId); + } + if (!nullToAbsent || additionalMessageData != null) { + map['additional_message_data'] = Variable( + additionalMessageData, + ); + } + map['media_stored'] = Variable(mediaStored); + map['media_reopened'] = Variable(mediaReopened); + if (!nullToAbsent || downloadToken != null) { + map['download_token'] = Variable(downloadToken); + } + if (!nullToAbsent || quotesMessageId != null) { + map['quotes_message_id'] = Variable(quotesMessageId); + } + map['is_deleted_from_sender'] = Variable(isDeletedFromSender); + if (!nullToAbsent || openedAt != null) { + map['opened_at'] = Variable(openedAt); + } + if (!nullToAbsent || openedByAll != null) { + map['opened_by_all'] = Variable(openedByAll); + } + map['created_at'] = Variable(createdAt); + if (!nullToAbsent || modifiedAt != null) { + map['modified_at'] = Variable(modifiedAt); + } + if (!nullToAbsent || ackByUser != null) { + map['ack_by_user'] = Variable(ackByUser); + } + if (!nullToAbsent || ackByServer != null) { + map['ack_by_server'] = Variable(ackByServer); + } + return map; + } + + MessagesCompanion toCompanion(bool nullToAbsent) { + return MessagesCompanion( + groupId: Value(groupId), + messageId: Value(messageId), + senderId: senderId == null && nullToAbsent + ? const Value.absent() + : Value(senderId), + type: Value(type), + content: content == null && nullToAbsent + ? const Value.absent() + : Value(content), + mediaId: mediaId == null && nullToAbsent + ? const Value.absent() + : Value(mediaId), + additionalMessageData: additionalMessageData == null && nullToAbsent + ? const Value.absent() + : Value(additionalMessageData), + mediaStored: Value(mediaStored), + mediaReopened: Value(mediaReopened), + downloadToken: downloadToken == null && nullToAbsent + ? const Value.absent() + : Value(downloadToken), + quotesMessageId: quotesMessageId == null && nullToAbsent + ? const Value.absent() + : Value(quotesMessageId), + isDeletedFromSender: Value(isDeletedFromSender), + openedAt: openedAt == null && nullToAbsent + ? const Value.absent() + : Value(openedAt), + openedByAll: openedByAll == null && nullToAbsent + ? const Value.absent() + : Value(openedByAll), + createdAt: Value(createdAt), + modifiedAt: modifiedAt == null && nullToAbsent + ? const Value.absent() + : Value(modifiedAt), + ackByUser: ackByUser == null && nullToAbsent + ? const Value.absent() + : Value(ackByUser), + ackByServer: ackByServer == null && nullToAbsent + ? const Value.absent() + : Value(ackByServer), + ); + } + + factory MessagesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessagesData( + groupId: serializer.fromJson(json['groupId']), + messageId: serializer.fromJson(json['messageId']), + senderId: serializer.fromJson(json['senderId']), + type: serializer.fromJson(json['type']), + content: serializer.fromJson(json['content']), + mediaId: serializer.fromJson(json['mediaId']), + additionalMessageData: serializer.fromJson( + json['additionalMessageData'], + ), + mediaStored: serializer.fromJson(json['mediaStored']), + mediaReopened: serializer.fromJson(json['mediaReopened']), + downloadToken: serializer.fromJson(json['downloadToken']), + quotesMessageId: serializer.fromJson(json['quotesMessageId']), + isDeletedFromSender: serializer.fromJson( + json['isDeletedFromSender'], + ), + openedAt: serializer.fromJson(json['openedAt']), + openedByAll: serializer.fromJson(json['openedByAll']), + createdAt: serializer.fromJson(json['createdAt']), + modifiedAt: serializer.fromJson(json['modifiedAt']), + ackByUser: serializer.fromJson(json['ackByUser']), + ackByServer: serializer.fromJson(json['ackByServer']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'messageId': serializer.toJson(messageId), + 'senderId': serializer.toJson(senderId), + 'type': serializer.toJson(type), + 'content': serializer.toJson(content), + 'mediaId': serializer.toJson(mediaId), + 'additionalMessageData': serializer.toJson( + additionalMessageData, + ), + 'mediaStored': serializer.toJson(mediaStored), + 'mediaReopened': serializer.toJson(mediaReopened), + 'downloadToken': serializer.toJson(downloadToken), + 'quotesMessageId': serializer.toJson(quotesMessageId), + 'isDeletedFromSender': serializer.toJson(isDeletedFromSender), + 'openedAt': serializer.toJson(openedAt), + 'openedByAll': serializer.toJson(openedByAll), + 'createdAt': serializer.toJson(createdAt), + 'modifiedAt': serializer.toJson(modifiedAt), + 'ackByUser': serializer.toJson(ackByUser), + 'ackByServer': serializer.toJson(ackByServer), + }; + } + + MessagesData copyWith({ + String? groupId, + String? messageId, + Value senderId = const Value.absent(), + String? type, + Value content = const Value.absent(), + Value mediaId = const Value.absent(), + Value additionalMessageData = const Value.absent(), + int? mediaStored, + int? mediaReopened, + Value downloadToken = const Value.absent(), + Value quotesMessageId = const Value.absent(), + int? isDeletedFromSender, + Value openedAt = const Value.absent(), + Value openedByAll = const Value.absent(), + int? createdAt, + Value modifiedAt = const Value.absent(), + Value ackByUser = const Value.absent(), + Value ackByServer = const Value.absent(), + }) => MessagesData( + groupId: groupId ?? this.groupId, + messageId: messageId ?? this.messageId, + senderId: senderId.present ? senderId.value : this.senderId, + type: type ?? this.type, + content: content.present ? content.value : this.content, + mediaId: mediaId.present ? mediaId.value : this.mediaId, + additionalMessageData: additionalMessageData.present + ? additionalMessageData.value + : this.additionalMessageData, + mediaStored: mediaStored ?? this.mediaStored, + mediaReopened: mediaReopened ?? this.mediaReopened, + downloadToken: downloadToken.present + ? downloadToken.value + : this.downloadToken, + quotesMessageId: quotesMessageId.present + ? quotesMessageId.value + : this.quotesMessageId, + isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, + openedAt: openedAt.present ? openedAt.value : this.openedAt, + openedByAll: openedByAll.present ? openedByAll.value : this.openedByAll, + createdAt: createdAt ?? this.createdAt, + modifiedAt: modifiedAt.present ? modifiedAt.value : this.modifiedAt, + ackByUser: ackByUser.present ? ackByUser.value : this.ackByUser, + ackByServer: ackByServer.present ? ackByServer.value : this.ackByServer, + ); + MessagesData copyWithCompanion(MessagesCompanion data) { + return MessagesData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + senderId: data.senderId.present ? data.senderId.value : this.senderId, + type: data.type.present ? data.type.value : this.type, + content: data.content.present ? data.content.value : this.content, + mediaId: data.mediaId.present ? data.mediaId.value : this.mediaId, + additionalMessageData: data.additionalMessageData.present + ? data.additionalMessageData.value + : this.additionalMessageData, + mediaStored: data.mediaStored.present + ? data.mediaStored.value + : this.mediaStored, + mediaReopened: data.mediaReopened.present + ? data.mediaReopened.value + : this.mediaReopened, + downloadToken: data.downloadToken.present + ? data.downloadToken.value + : this.downloadToken, + quotesMessageId: data.quotesMessageId.present + ? data.quotesMessageId.value + : this.quotesMessageId, + isDeletedFromSender: data.isDeletedFromSender.present + ? data.isDeletedFromSender.value + : this.isDeletedFromSender, + openedAt: data.openedAt.present ? data.openedAt.value : this.openedAt, + openedByAll: data.openedByAll.present + ? data.openedByAll.value + : this.openedByAll, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + modifiedAt: data.modifiedAt.present + ? data.modifiedAt.value + : this.modifiedAt, + ackByUser: data.ackByUser.present ? data.ackByUser.value : this.ackByUser, + ackByServer: data.ackByServer.present + ? data.ackByServer.value + : this.ackByServer, + ); + } + + @override + String toString() { + return (StringBuffer('MessagesData(') + ..write('groupId: $groupId, ') + ..write('messageId: $messageId, ') + ..write('senderId: $senderId, ') + ..write('type: $type, ') + ..write('content: $content, ') + ..write('mediaId: $mediaId, ') + ..write('additionalMessageData: $additionalMessageData, ') + ..write('mediaStored: $mediaStored, ') + ..write('mediaReopened: $mediaReopened, ') + ..write('downloadToken: $downloadToken, ') + ..write('quotesMessageId: $quotesMessageId, ') + ..write('isDeletedFromSender: $isDeletedFromSender, ') + ..write('openedAt: $openedAt, ') + ..write('openedByAll: $openedByAll, ') + ..write('createdAt: $createdAt, ') + ..write('modifiedAt: $modifiedAt, ') + ..write('ackByUser: $ackByUser, ') + ..write('ackByServer: $ackByServer') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupId, + messageId, + senderId, + type, + content, + mediaId, + $driftBlobEquality.hash(additionalMessageData), + mediaStored, + mediaReopened, + $driftBlobEquality.hash(downloadToken), + quotesMessageId, + isDeletedFromSender, + openedAt, + openedByAll, + createdAt, + modifiedAt, + ackByUser, + ackByServer, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessagesData && + other.groupId == this.groupId && + other.messageId == this.messageId && + other.senderId == this.senderId && + other.type == this.type && + other.content == this.content && + other.mediaId == this.mediaId && + $driftBlobEquality.equals( + other.additionalMessageData, + this.additionalMessageData, + ) && + other.mediaStored == this.mediaStored && + other.mediaReopened == this.mediaReopened && + $driftBlobEquality.equals(other.downloadToken, this.downloadToken) && + other.quotesMessageId == this.quotesMessageId && + other.isDeletedFromSender == this.isDeletedFromSender && + other.openedAt == this.openedAt && + other.openedByAll == this.openedByAll && + other.createdAt == this.createdAt && + other.modifiedAt == this.modifiedAt && + other.ackByUser == this.ackByUser && + other.ackByServer == this.ackByServer); +} + +class MessagesCompanion extends UpdateCompanion { + final Value groupId; + final Value messageId; + final Value senderId; + final Value type; + final Value content; + final Value mediaId; + final Value additionalMessageData; + final Value mediaStored; + final Value mediaReopened; + final Value downloadToken; + final Value quotesMessageId; + final Value isDeletedFromSender; + final Value openedAt; + final Value openedByAll; + final Value createdAt; + final Value modifiedAt; + final Value ackByUser; + final Value ackByServer; + final Value rowid; + const MessagesCompanion({ + this.groupId = const Value.absent(), + this.messageId = const Value.absent(), + this.senderId = const Value.absent(), + this.type = const Value.absent(), + this.content = const Value.absent(), + this.mediaId = const Value.absent(), + this.additionalMessageData = const Value.absent(), + this.mediaStored = const Value.absent(), + this.mediaReopened = const Value.absent(), + this.downloadToken = const Value.absent(), + this.quotesMessageId = const Value.absent(), + this.isDeletedFromSender = const Value.absent(), + this.openedAt = const Value.absent(), + this.openedByAll = const Value.absent(), + this.createdAt = const Value.absent(), + this.modifiedAt = const Value.absent(), + this.ackByUser = const Value.absent(), + this.ackByServer = const Value.absent(), + this.rowid = const Value.absent(), + }); + MessagesCompanion.insert({ + required String groupId, + required String messageId, + this.senderId = const Value.absent(), + required String type, + this.content = const Value.absent(), + this.mediaId = const Value.absent(), + this.additionalMessageData = const Value.absent(), + this.mediaStored = const Value.absent(), + this.mediaReopened = const Value.absent(), + this.downloadToken = const Value.absent(), + this.quotesMessageId = const Value.absent(), + this.isDeletedFromSender = const Value.absent(), + this.openedAt = const Value.absent(), + this.openedByAll = const Value.absent(), + this.createdAt = const Value.absent(), + this.modifiedAt = const Value.absent(), + this.ackByUser = const Value.absent(), + this.ackByServer = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + messageId = Value(messageId), + type = Value(type); + static Insertable custom({ + Expression? groupId, + Expression? messageId, + Expression? senderId, + Expression? type, + Expression? content, + Expression? mediaId, + Expression? additionalMessageData, + Expression? mediaStored, + Expression? mediaReopened, + Expression? downloadToken, + Expression? quotesMessageId, + Expression? isDeletedFromSender, + Expression? openedAt, + Expression? openedByAll, + Expression? createdAt, + Expression? modifiedAt, + Expression? ackByUser, + Expression? ackByServer, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (messageId != null) 'message_id': messageId, + if (senderId != null) 'sender_id': senderId, + if (type != null) 'type': type, + if (content != null) 'content': content, + if (mediaId != null) 'media_id': mediaId, + if (additionalMessageData != null) + 'additional_message_data': additionalMessageData, + if (mediaStored != null) 'media_stored': mediaStored, + if (mediaReopened != null) 'media_reopened': mediaReopened, + if (downloadToken != null) 'download_token': downloadToken, + if (quotesMessageId != null) 'quotes_message_id': quotesMessageId, + if (isDeletedFromSender != null) + 'is_deleted_from_sender': isDeletedFromSender, + if (openedAt != null) 'opened_at': openedAt, + if (openedByAll != null) 'opened_by_all': openedByAll, + if (createdAt != null) 'created_at': createdAt, + if (modifiedAt != null) 'modified_at': modifiedAt, + if (ackByUser != null) 'ack_by_user': ackByUser, + if (ackByServer != null) 'ack_by_server': ackByServer, + if (rowid != null) 'rowid': rowid, + }); + } + + MessagesCompanion copyWith({ + Value? groupId, + Value? messageId, + Value? senderId, + Value? type, + Value? content, + Value? mediaId, + Value? additionalMessageData, + Value? mediaStored, + Value? mediaReopened, + Value? downloadToken, + Value? quotesMessageId, + Value? isDeletedFromSender, + Value? openedAt, + Value? openedByAll, + Value? createdAt, + Value? modifiedAt, + Value? ackByUser, + Value? ackByServer, + Value? rowid, + }) { + return MessagesCompanion( + groupId: groupId ?? this.groupId, + messageId: messageId ?? this.messageId, + senderId: senderId ?? this.senderId, + type: type ?? this.type, + content: content ?? this.content, + mediaId: mediaId ?? this.mediaId, + additionalMessageData: + additionalMessageData ?? this.additionalMessageData, + mediaStored: mediaStored ?? this.mediaStored, + mediaReopened: mediaReopened ?? this.mediaReopened, + downloadToken: downloadToken ?? this.downloadToken, + quotesMessageId: quotesMessageId ?? this.quotesMessageId, + isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, + openedAt: openedAt ?? this.openedAt, + openedByAll: openedByAll ?? this.openedByAll, + createdAt: createdAt ?? this.createdAt, + modifiedAt: modifiedAt ?? this.modifiedAt, + ackByUser: ackByUser ?? this.ackByUser, + ackByServer: ackByServer ?? this.ackByServer, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (senderId.present) { + map['sender_id'] = Variable(senderId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (mediaId.present) { + map['media_id'] = Variable(mediaId.value); + } + if (additionalMessageData.present) { + map['additional_message_data'] = Variable( + additionalMessageData.value, + ); + } + if (mediaStored.present) { + map['media_stored'] = Variable(mediaStored.value); + } + if (mediaReopened.present) { + map['media_reopened'] = Variable(mediaReopened.value); + } + if (downloadToken.present) { + map['download_token'] = Variable(downloadToken.value); + } + if (quotesMessageId.present) { + map['quotes_message_id'] = Variable(quotesMessageId.value); + } + if (isDeletedFromSender.present) { + map['is_deleted_from_sender'] = Variable(isDeletedFromSender.value); + } + if (openedAt.present) { + map['opened_at'] = Variable(openedAt.value); + } + if (openedByAll.present) { + map['opened_by_all'] = Variable(openedByAll.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (modifiedAt.present) { + map['modified_at'] = Variable(modifiedAt.value); + } + if (ackByUser.present) { + map['ack_by_user'] = Variable(ackByUser.value); + } + if (ackByServer.present) { + map['ack_by_server'] = Variable(ackByServer.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessagesCompanion(') + ..write('groupId: $groupId, ') + ..write('messageId: $messageId, ') + ..write('senderId: $senderId, ') + ..write('type: $type, ') + ..write('content: $content, ') + ..write('mediaId: $mediaId, ') + ..write('additionalMessageData: $additionalMessageData, ') + ..write('mediaStored: $mediaStored, ') + ..write('mediaReopened: $mediaReopened, ') + ..write('downloadToken: $downloadToken, ') + ..write('quotesMessageId: $quotesMessageId, ') + ..write('isDeletedFromSender: $isDeletedFromSender, ') + ..write('openedAt: $openedAt, ') + ..write('openedByAll: $openedByAll, ') + ..write('createdAt: $createdAt, ') + ..write('modifiedAt: $modifiedAt, ') + ..write('ackByUser: $ackByUser, ') + ..write('ackByServer: $ackByServer, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class MessageHistories extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MessageHistories(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn content = GeneratedColumn( + 'content', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + id, + messageId, + contactId, + content, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'message_histories'; + @override + Set get $primaryKey => {id}; + @override + MessageHistoriesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MessageHistoriesData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + content: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}content'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + MessageHistories createAlias(String alias) { + return MessageHistories(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class MessageHistoriesData extends DataClass + implements Insertable { + final int id; + final String messageId; + final int? contactId; + final String? content; + final int createdAt; + const MessageHistoriesData({ + required this.id, + required this.messageId, + this.contactId, + this.content, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['message_id'] = Variable(messageId); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + if (!nullToAbsent || content != null) { + map['content'] = Variable(content); + } + map['created_at'] = Variable(createdAt); + return map; + } + + MessageHistoriesCompanion toCompanion(bool nullToAbsent) { + return MessageHistoriesCompanion( + id: Value(id), + messageId: Value(messageId), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + content: content == null && nullToAbsent + ? const Value.absent() + : Value(content), + createdAt: Value(createdAt), + ); + } + + factory MessageHistoriesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessageHistoriesData( + id: serializer.fromJson(json['id']), + messageId: serializer.fromJson(json['messageId']), + contactId: serializer.fromJson(json['contactId']), + content: serializer.fromJson(json['content']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'messageId': serializer.toJson(messageId), + 'contactId': serializer.toJson(contactId), + 'content': serializer.toJson(content), + 'createdAt': serializer.toJson(createdAt), + }; + } + + MessageHistoriesData copyWith({ + int? id, + String? messageId, + Value contactId = const Value.absent(), + Value content = const Value.absent(), + int? createdAt, + }) => MessageHistoriesData( + id: id ?? this.id, + messageId: messageId ?? this.messageId, + contactId: contactId.present ? contactId.value : this.contactId, + content: content.present ? content.value : this.content, + createdAt: createdAt ?? this.createdAt, + ); + MessageHistoriesData copyWithCompanion(MessageHistoriesCompanion data) { + return MessageHistoriesData( + id: data.id.present ? data.id.value : this.id, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + content: data.content.present ? data.content.value : this.content, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('MessageHistoriesData(') + ..write('id: $id, ') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('content: $content, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, messageId, contactId, content, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessageHistoriesData && + other.id == this.id && + other.messageId == this.messageId && + other.contactId == this.contactId && + other.content == this.content && + other.createdAt == this.createdAt); +} + +class MessageHistoriesCompanion extends UpdateCompanion { + final Value id; + final Value messageId; + final Value contactId; + final Value content; + final Value createdAt; + const MessageHistoriesCompanion({ + this.id = const Value.absent(), + this.messageId = const Value.absent(), + this.contactId = const Value.absent(), + this.content = const Value.absent(), + this.createdAt = const Value.absent(), + }); + MessageHistoriesCompanion.insert({ + this.id = const Value.absent(), + required String messageId, + this.contactId = const Value.absent(), + this.content = const Value.absent(), + this.createdAt = const Value.absent(), + }) : messageId = Value(messageId); + static Insertable custom({ + Expression? id, + Expression? messageId, + Expression? contactId, + Expression? content, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (messageId != null) 'message_id': messageId, + if (contactId != null) 'contact_id': contactId, + if (content != null) 'content': content, + if (createdAt != null) 'created_at': createdAt, + }); + } + + MessageHistoriesCompanion copyWith({ + Value? id, + Value? messageId, + Value? contactId, + Value? content, + Value? createdAt, + }) { + return MessageHistoriesCompanion( + id: id ?? this.id, + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + content: content ?? this.content, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessageHistoriesCompanion(') + ..write('id: $id, ') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('content: $content, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class Reactions extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Reactions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn emoji = GeneratedColumn( + 'emoji', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderId = GeneratedColumn( + 'sender_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [messageId, emoji, senderId, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'reactions'; + @override + Set get $primaryKey => {messageId, senderId, emoji}; + @override + ReactionsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReactionsData( + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + emoji: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}emoji'], + )!, + senderId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_id'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + Reactions createAlias(String alias) { + return Reactions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(message_id, sender_id, emoji)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class ReactionsData extends DataClass implements Insertable { + final String messageId; + final String emoji; + final int? senderId; + final int createdAt; + const ReactionsData({ + required this.messageId, + required this.emoji, + this.senderId, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['message_id'] = Variable(messageId); + map['emoji'] = Variable(emoji); + if (!nullToAbsent || senderId != null) { + map['sender_id'] = Variable(senderId); + } + map['created_at'] = Variable(createdAt); + return map; + } + + ReactionsCompanion toCompanion(bool nullToAbsent) { + return ReactionsCompanion( + messageId: Value(messageId), + emoji: Value(emoji), + senderId: senderId == null && nullToAbsent + ? const Value.absent() + : Value(senderId), + createdAt: Value(createdAt), + ); + } + + factory ReactionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReactionsData( + messageId: serializer.fromJson(json['messageId']), + emoji: serializer.fromJson(json['emoji']), + senderId: serializer.fromJson(json['senderId']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'messageId': serializer.toJson(messageId), + 'emoji': serializer.toJson(emoji), + 'senderId': serializer.toJson(senderId), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReactionsData copyWith({ + String? messageId, + String? emoji, + Value senderId = const Value.absent(), + int? createdAt, + }) => ReactionsData( + messageId: messageId ?? this.messageId, + emoji: emoji ?? this.emoji, + senderId: senderId.present ? senderId.value : this.senderId, + createdAt: createdAt ?? this.createdAt, + ); + ReactionsData copyWithCompanion(ReactionsCompanion data) { + return ReactionsData( + messageId: data.messageId.present ? data.messageId.value : this.messageId, + emoji: data.emoji.present ? data.emoji.value : this.emoji, + senderId: data.senderId.present ? data.senderId.value : this.senderId, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReactionsData(') + ..write('messageId: $messageId, ') + ..write('emoji: $emoji, ') + ..write('senderId: $senderId, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(messageId, emoji, senderId, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReactionsData && + other.messageId == this.messageId && + other.emoji == this.emoji && + other.senderId == this.senderId && + other.createdAt == this.createdAt); +} + +class ReactionsCompanion extends UpdateCompanion { + final Value messageId; + final Value emoji; + final Value senderId; + final Value createdAt; + final Value rowid; + const ReactionsCompanion({ + this.messageId = const Value.absent(), + this.emoji = const Value.absent(), + this.senderId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReactionsCompanion.insert({ + required String messageId, + required String emoji, + this.senderId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : messageId = Value(messageId), + emoji = Value(emoji); + static Insertable custom({ + Expression? messageId, + Expression? emoji, + Expression? senderId, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (messageId != null) 'message_id': messageId, + if (emoji != null) 'emoji': emoji, + if (senderId != null) 'sender_id': senderId, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReactionsCompanion copyWith({ + Value? messageId, + Value? emoji, + Value? senderId, + Value? createdAt, + Value? rowid, + }) { + return ReactionsCompanion( + messageId: messageId ?? this.messageId, + emoji: emoji ?? this.emoji, + senderId: senderId ?? this.senderId, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (emoji.present) { + map['emoji'] = Variable(emoji.value); + } + if (senderId.present) { + map['sender_id'] = Variable(senderId.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('ReactionsCompanion(') + ..write('messageId: $messageId, ') + ..write('emoji: $emoji, ') + ..write('senderId: $senderId, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class GroupMembers extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + GroupMembers(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn memberState = GeneratedColumn( + 'member_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn groupPublicKey = + GeneratedColumn( + 'group_public_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastChatOpened = GeneratedColumn( + 'last_chat_opened', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastTypeIndicator = GeneratedColumn( + 'last_type_indicator', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessage = GeneratedColumn( + 'last_message', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupId, + contactId, + memberState, + groupPublicKey, + lastChatOpened, + lastTypeIndicator, + lastMessage, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'group_members'; + @override + Set get $primaryKey => {groupId, contactId}; + @override + GroupMembersData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupMembersData( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + memberState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}member_state'], + ), + groupPublicKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}group_public_key'], + ), + lastChatOpened: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_chat_opened'], + ), + lastTypeIndicator: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_type_indicator'], + ), + lastMessage: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + GroupMembers createAlias(String alias) { + return GroupMembers(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(group_id, contact_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class GroupMembersData extends DataClass + implements Insertable { + final String groupId; + final int contactId; + final String? memberState; + final i2.Uint8List? groupPublicKey; + final int? lastChatOpened; + final int? lastTypeIndicator; + final int? lastMessage; + final int createdAt; + const GroupMembersData({ + required this.groupId, + required this.contactId, + this.memberState, + this.groupPublicKey, + this.lastChatOpened, + this.lastTypeIndicator, + this.lastMessage, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['contact_id'] = Variable(contactId); + if (!nullToAbsent || memberState != null) { + map['member_state'] = Variable(memberState); + } + if (!nullToAbsent || groupPublicKey != null) { + map['group_public_key'] = Variable(groupPublicKey); + } + if (!nullToAbsent || lastChatOpened != null) { + map['last_chat_opened'] = Variable(lastChatOpened); + } + if (!nullToAbsent || lastTypeIndicator != null) { + map['last_type_indicator'] = Variable(lastTypeIndicator); + } + if (!nullToAbsent || lastMessage != null) { + map['last_message'] = Variable(lastMessage); + } + map['created_at'] = Variable(createdAt); + return map; + } + + GroupMembersCompanion toCompanion(bool nullToAbsent) { + return GroupMembersCompanion( + groupId: Value(groupId), + contactId: Value(contactId), + memberState: memberState == null && nullToAbsent + ? const Value.absent() + : Value(memberState), + groupPublicKey: groupPublicKey == null && nullToAbsent + ? const Value.absent() + : Value(groupPublicKey), + lastChatOpened: lastChatOpened == null && nullToAbsent + ? const Value.absent() + : Value(lastChatOpened), + lastTypeIndicator: lastTypeIndicator == null && nullToAbsent + ? const Value.absent() + : Value(lastTypeIndicator), + lastMessage: lastMessage == null && nullToAbsent + ? const Value.absent() + : Value(lastMessage), + createdAt: Value(createdAt), + ); + } + + factory GroupMembersData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupMembersData( + groupId: serializer.fromJson(json['groupId']), + contactId: serializer.fromJson(json['contactId']), + memberState: serializer.fromJson(json['memberState']), + groupPublicKey: serializer.fromJson( + json['groupPublicKey'], + ), + lastChatOpened: serializer.fromJson(json['lastChatOpened']), + lastTypeIndicator: serializer.fromJson(json['lastTypeIndicator']), + lastMessage: serializer.fromJson(json['lastMessage']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'contactId': serializer.toJson(contactId), + 'memberState': serializer.toJson(memberState), + 'groupPublicKey': serializer.toJson(groupPublicKey), + 'lastChatOpened': serializer.toJson(lastChatOpened), + 'lastTypeIndicator': serializer.toJson(lastTypeIndicator), + 'lastMessage': serializer.toJson(lastMessage), + 'createdAt': serializer.toJson(createdAt), + }; + } + + GroupMembersData copyWith({ + String? groupId, + int? contactId, + Value memberState = const Value.absent(), + Value groupPublicKey = const Value.absent(), + Value lastChatOpened = const Value.absent(), + Value lastTypeIndicator = const Value.absent(), + Value lastMessage = const Value.absent(), + int? createdAt, + }) => GroupMembersData( + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + memberState: memberState.present ? memberState.value : this.memberState, + groupPublicKey: groupPublicKey.present + ? groupPublicKey.value + : this.groupPublicKey, + lastChatOpened: lastChatOpened.present + ? lastChatOpened.value + : this.lastChatOpened, + lastTypeIndicator: lastTypeIndicator.present + ? lastTypeIndicator.value + : this.lastTypeIndicator, + lastMessage: lastMessage.present ? lastMessage.value : this.lastMessage, + createdAt: createdAt ?? this.createdAt, + ); + GroupMembersData copyWithCompanion(GroupMembersCompanion data) { + return GroupMembersData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + memberState: data.memberState.present + ? data.memberState.value + : this.memberState, + groupPublicKey: data.groupPublicKey.present + ? data.groupPublicKey.value + : this.groupPublicKey, + lastChatOpened: data.lastChatOpened.present + ? data.lastChatOpened.value + : this.lastChatOpened, + lastTypeIndicator: data.lastTypeIndicator.present + ? data.lastTypeIndicator.value + : this.lastTypeIndicator, + lastMessage: data.lastMessage.present + ? data.lastMessage.value + : this.lastMessage, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('GroupMembersData(') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('memberState: $memberState, ') + ..write('groupPublicKey: $groupPublicKey, ') + ..write('lastChatOpened: $lastChatOpened, ') + ..write('lastTypeIndicator: $lastTypeIndicator, ') + ..write('lastMessage: $lastMessage, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupId, + contactId, + memberState, + $driftBlobEquality.hash(groupPublicKey), + lastChatOpened, + lastTypeIndicator, + lastMessage, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupMembersData && + other.groupId == this.groupId && + other.contactId == this.contactId && + other.memberState == this.memberState && + $driftBlobEquality.equals( + other.groupPublicKey, + this.groupPublicKey, + ) && + other.lastChatOpened == this.lastChatOpened && + other.lastTypeIndicator == this.lastTypeIndicator && + other.lastMessage == this.lastMessage && + other.createdAt == this.createdAt); +} + +class GroupMembersCompanion extends UpdateCompanion { + final Value groupId; + final Value contactId; + final Value memberState; + final Value groupPublicKey; + final Value lastChatOpened; + final Value lastTypeIndicator; + final Value lastMessage; + final Value createdAt; + final Value rowid; + const GroupMembersCompanion({ + this.groupId = const Value.absent(), + this.contactId = const Value.absent(), + this.memberState = const Value.absent(), + this.groupPublicKey = const Value.absent(), + this.lastChatOpened = const Value.absent(), + this.lastTypeIndicator = const Value.absent(), + this.lastMessage = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupMembersCompanion.insert({ + required String groupId, + required int contactId, + this.memberState = const Value.absent(), + this.groupPublicKey = const Value.absent(), + this.lastChatOpened = const Value.absent(), + this.lastTypeIndicator = const Value.absent(), + this.lastMessage = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + contactId = Value(contactId); + static Insertable custom({ + Expression? groupId, + Expression? contactId, + Expression? memberState, + Expression? groupPublicKey, + Expression? lastChatOpened, + Expression? lastTypeIndicator, + Expression? lastMessage, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (contactId != null) 'contact_id': contactId, + if (memberState != null) 'member_state': memberState, + if (groupPublicKey != null) 'group_public_key': groupPublicKey, + if (lastChatOpened != null) 'last_chat_opened': lastChatOpened, + if (lastTypeIndicator != null) 'last_type_indicator': lastTypeIndicator, + if (lastMessage != null) 'last_message': lastMessage, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupMembersCompanion copyWith({ + Value? groupId, + Value? contactId, + Value? memberState, + Value? groupPublicKey, + Value? lastChatOpened, + Value? lastTypeIndicator, + Value? lastMessage, + Value? createdAt, + Value? rowid, + }) { + return GroupMembersCompanion( + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + memberState: memberState ?? this.memberState, + groupPublicKey: groupPublicKey ?? this.groupPublicKey, + lastChatOpened: lastChatOpened ?? this.lastChatOpened, + lastTypeIndicator: lastTypeIndicator ?? this.lastTypeIndicator, + lastMessage: lastMessage ?? this.lastMessage, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (memberState.present) { + map['member_state'] = Variable(memberState.value); + } + if (groupPublicKey.present) { + map['group_public_key'] = Variable(groupPublicKey.value); + } + if (lastChatOpened.present) { + map['last_chat_opened'] = Variable(lastChatOpened.value); + } + if (lastTypeIndicator.present) { + map['last_type_indicator'] = Variable(lastTypeIndicator.value); + } + if (lastMessage.present) { + map['last_message'] = Variable(lastMessage.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('GroupMembersCompanion(') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('memberState: $memberState, ') + ..write('groupPublicKey: $groupPublicKey, ') + ..write('lastChatOpened: $lastChatOpened, ') + ..write('lastTypeIndicator: $lastTypeIndicator, ') + ..write('lastMessage: $lastMessage, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class Receipts extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Receipts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn receiptId = GeneratedColumn( + 'receipt_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn message = + GeneratedColumn( + 'message', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactWillSendsReceipt = + GeneratedColumn( + 'contact_will_sends_receipt', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 1 CHECK (contact_will_sends_receipt IN (0, 1))', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn + willBeRetriedByMediaUpload = GeneratedColumn( + 'will_be_retried_by_media_upload', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (will_be_retried_by_media_upload IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn markForRetry = GeneratedColumn( + 'mark_for_retry', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn markForRetryAfterAccepted = + GeneratedColumn( + 'mark_for_retry_after_accepted', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByServerAt = GeneratedColumn( + 'ack_by_server_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn retryCount = GeneratedColumn( + 'retry_count', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn lastRetry = GeneratedColumn( + 'last_retry', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + receiptId, + contactId, + messageId, + message, + contactWillSendsReceipt, + willBeRetriedByMediaUpload, + markForRetry, + markForRetryAfterAccepted, + ackByServerAt, + retryCount, + lastRetry, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'receipts'; + @override + Set get $primaryKey => {receiptId}; + @override + ReceiptsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReceiptsData( + receiptId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}receipt_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + ), + message: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}message'], + )!, + contactWillSendsReceipt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_will_sends_receipt'], + )!, + willBeRetriedByMediaUpload: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}will_be_retried_by_media_upload'], + )!, + markForRetry: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}mark_for_retry'], + ), + markForRetryAfterAccepted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}mark_for_retry_after_accepted'], + ), + ackByServerAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_server_at'], + ), + retryCount: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}retry_count'], + )!, + lastRetry: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_retry'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + Receipts createAlias(String alias) { + return Receipts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(receipt_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ReceiptsData extends DataClass implements Insertable { + final String receiptId; + final int contactId; + final String? messageId; + final i2.Uint8List message; + final int contactWillSendsReceipt; + final int willBeRetriedByMediaUpload; + final int? markForRetry; + final int? markForRetryAfterAccepted; + final int? ackByServerAt; + final int retryCount; + final int? lastRetry; + final int createdAt; + const ReceiptsData({ + required this.receiptId, + required this.contactId, + this.messageId, + required this.message, + required this.contactWillSendsReceipt, + required this.willBeRetriedByMediaUpload, + this.markForRetry, + this.markForRetryAfterAccepted, + this.ackByServerAt, + required this.retryCount, + this.lastRetry, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['receipt_id'] = Variable(receiptId); + map['contact_id'] = Variable(contactId); + if (!nullToAbsent || messageId != null) { + map['message_id'] = Variable(messageId); + } + map['message'] = Variable(message); + map['contact_will_sends_receipt'] = Variable(contactWillSendsReceipt); + map['will_be_retried_by_media_upload'] = Variable( + willBeRetriedByMediaUpload, + ); + if (!nullToAbsent || markForRetry != null) { + map['mark_for_retry'] = Variable(markForRetry); + } + if (!nullToAbsent || markForRetryAfterAccepted != null) { + map['mark_for_retry_after_accepted'] = Variable( + markForRetryAfterAccepted, + ); + } + if (!nullToAbsent || ackByServerAt != null) { + map['ack_by_server_at'] = Variable(ackByServerAt); + } + map['retry_count'] = Variable(retryCount); + if (!nullToAbsent || lastRetry != null) { + map['last_retry'] = Variable(lastRetry); + } + map['created_at'] = Variable(createdAt); + return map; + } + + ReceiptsCompanion toCompanion(bool nullToAbsent) { + return ReceiptsCompanion( + receiptId: Value(receiptId), + contactId: Value(contactId), + messageId: messageId == null && nullToAbsent + ? const Value.absent() + : Value(messageId), + message: Value(message), + contactWillSendsReceipt: Value(contactWillSendsReceipt), + willBeRetriedByMediaUpload: Value(willBeRetriedByMediaUpload), + markForRetry: markForRetry == null && nullToAbsent + ? const Value.absent() + : Value(markForRetry), + markForRetryAfterAccepted: + markForRetryAfterAccepted == null && nullToAbsent + ? const Value.absent() + : Value(markForRetryAfterAccepted), + ackByServerAt: ackByServerAt == null && nullToAbsent + ? const Value.absent() + : Value(ackByServerAt), + retryCount: Value(retryCount), + lastRetry: lastRetry == null && nullToAbsent + ? const Value.absent() + : Value(lastRetry), + createdAt: Value(createdAt), + ); + } + + factory ReceiptsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReceiptsData( + receiptId: serializer.fromJson(json['receiptId']), + contactId: serializer.fromJson(json['contactId']), + messageId: serializer.fromJson(json['messageId']), + message: serializer.fromJson(json['message']), + contactWillSendsReceipt: serializer.fromJson( + json['contactWillSendsReceipt'], + ), + willBeRetriedByMediaUpload: serializer.fromJson( + json['willBeRetriedByMediaUpload'], + ), + markForRetry: serializer.fromJson(json['markForRetry']), + markForRetryAfterAccepted: serializer.fromJson( + json['markForRetryAfterAccepted'], + ), + ackByServerAt: serializer.fromJson(json['ackByServerAt']), + retryCount: serializer.fromJson(json['retryCount']), + lastRetry: serializer.fromJson(json['lastRetry']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'receiptId': serializer.toJson(receiptId), + 'contactId': serializer.toJson(contactId), + 'messageId': serializer.toJson(messageId), + 'message': serializer.toJson(message), + 'contactWillSendsReceipt': serializer.toJson( + contactWillSendsReceipt, + ), + 'willBeRetriedByMediaUpload': serializer.toJson( + willBeRetriedByMediaUpload, + ), + 'markForRetry': serializer.toJson(markForRetry), + 'markForRetryAfterAccepted': serializer.toJson( + markForRetryAfterAccepted, + ), + 'ackByServerAt': serializer.toJson(ackByServerAt), + 'retryCount': serializer.toJson(retryCount), + 'lastRetry': serializer.toJson(lastRetry), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReceiptsData copyWith({ + String? receiptId, + int? contactId, + Value messageId = const Value.absent(), + i2.Uint8List? message, + int? contactWillSendsReceipt, + int? willBeRetriedByMediaUpload, + Value markForRetry = const Value.absent(), + Value markForRetryAfterAccepted = const Value.absent(), + Value ackByServerAt = const Value.absent(), + int? retryCount, + Value lastRetry = const Value.absent(), + int? createdAt, + }) => ReceiptsData( + receiptId: receiptId ?? this.receiptId, + contactId: contactId ?? this.contactId, + messageId: messageId.present ? messageId.value : this.messageId, + message: message ?? this.message, + contactWillSendsReceipt: + contactWillSendsReceipt ?? this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: + willBeRetriedByMediaUpload ?? this.willBeRetriedByMediaUpload, + markForRetry: markForRetry.present ? markForRetry.value : this.markForRetry, + markForRetryAfterAccepted: markForRetryAfterAccepted.present + ? markForRetryAfterAccepted.value + : this.markForRetryAfterAccepted, + ackByServerAt: ackByServerAt.present + ? ackByServerAt.value + : this.ackByServerAt, + retryCount: retryCount ?? this.retryCount, + lastRetry: lastRetry.present ? lastRetry.value : this.lastRetry, + createdAt: createdAt ?? this.createdAt, + ); + ReceiptsData copyWithCompanion(ReceiptsCompanion data) { + return ReceiptsData( + receiptId: data.receiptId.present ? data.receiptId.value : this.receiptId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + message: data.message.present ? data.message.value : this.message, + contactWillSendsReceipt: data.contactWillSendsReceipt.present + ? data.contactWillSendsReceipt.value + : this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: data.willBeRetriedByMediaUpload.present + ? data.willBeRetriedByMediaUpload.value + : this.willBeRetriedByMediaUpload, + markForRetry: data.markForRetry.present + ? data.markForRetry.value + : this.markForRetry, + markForRetryAfterAccepted: data.markForRetryAfterAccepted.present + ? data.markForRetryAfterAccepted.value + : this.markForRetryAfterAccepted, + ackByServerAt: data.ackByServerAt.present + ? data.ackByServerAt.value + : this.ackByServerAt, + retryCount: data.retryCount.present + ? data.retryCount.value + : this.retryCount, + lastRetry: data.lastRetry.present ? data.lastRetry.value : this.lastRetry, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReceiptsData(') + ..write('receiptId: $receiptId, ') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('message: $message, ') + ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') + ..write('willBeRetriedByMediaUpload: $willBeRetriedByMediaUpload, ') + ..write('markForRetry: $markForRetry, ') + ..write('markForRetryAfterAccepted: $markForRetryAfterAccepted, ') + ..write('ackByServerAt: $ackByServerAt, ') + ..write('retryCount: $retryCount, ') + ..write('lastRetry: $lastRetry, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + receiptId, + contactId, + messageId, + $driftBlobEquality.hash(message), + contactWillSendsReceipt, + willBeRetriedByMediaUpload, + markForRetry, + markForRetryAfterAccepted, + ackByServerAt, + retryCount, + lastRetry, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReceiptsData && + other.receiptId == this.receiptId && + other.contactId == this.contactId && + other.messageId == this.messageId && + $driftBlobEquality.equals(other.message, this.message) && + other.contactWillSendsReceipt == this.contactWillSendsReceipt && + other.willBeRetriedByMediaUpload == this.willBeRetriedByMediaUpload && + other.markForRetry == this.markForRetry && + other.markForRetryAfterAccepted == this.markForRetryAfterAccepted && + other.ackByServerAt == this.ackByServerAt && + other.retryCount == this.retryCount && + other.lastRetry == this.lastRetry && + other.createdAt == this.createdAt); +} + +class ReceiptsCompanion extends UpdateCompanion { + final Value receiptId; + final Value contactId; + final Value messageId; + final Value message; + final Value contactWillSendsReceipt; + final Value willBeRetriedByMediaUpload; + final Value markForRetry; + final Value markForRetryAfterAccepted; + final Value ackByServerAt; + final Value retryCount; + final Value lastRetry; + final Value createdAt; + final Value rowid; + const ReceiptsCompanion({ + this.receiptId = const Value.absent(), + this.contactId = const Value.absent(), + this.messageId = const Value.absent(), + this.message = const Value.absent(), + this.contactWillSendsReceipt = const Value.absent(), + this.willBeRetriedByMediaUpload = const Value.absent(), + this.markForRetry = const Value.absent(), + this.markForRetryAfterAccepted = const Value.absent(), + this.ackByServerAt = const Value.absent(), + this.retryCount = const Value.absent(), + this.lastRetry = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReceiptsCompanion.insert({ + required String receiptId, + required int contactId, + this.messageId = const Value.absent(), + required i2.Uint8List message, + this.contactWillSendsReceipt = const Value.absent(), + this.willBeRetriedByMediaUpload = const Value.absent(), + this.markForRetry = const Value.absent(), + this.markForRetryAfterAccepted = const Value.absent(), + this.ackByServerAt = const Value.absent(), + this.retryCount = const Value.absent(), + this.lastRetry = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : receiptId = Value(receiptId), + contactId = Value(contactId), + message = Value(message); + static Insertable custom({ + Expression? receiptId, + Expression? contactId, + Expression? messageId, + Expression? message, + Expression? contactWillSendsReceipt, + Expression? willBeRetriedByMediaUpload, + Expression? markForRetry, + Expression? markForRetryAfterAccepted, + Expression? ackByServerAt, + Expression? retryCount, + Expression? lastRetry, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (receiptId != null) 'receipt_id': receiptId, + if (contactId != null) 'contact_id': contactId, + if (messageId != null) 'message_id': messageId, + if (message != null) 'message': message, + if (contactWillSendsReceipt != null) + 'contact_will_sends_receipt': contactWillSendsReceipt, + if (willBeRetriedByMediaUpload != null) + 'will_be_retried_by_media_upload': willBeRetriedByMediaUpload, + if (markForRetry != null) 'mark_for_retry': markForRetry, + if (markForRetryAfterAccepted != null) + 'mark_for_retry_after_accepted': markForRetryAfterAccepted, + if (ackByServerAt != null) 'ack_by_server_at': ackByServerAt, + if (retryCount != null) 'retry_count': retryCount, + if (lastRetry != null) 'last_retry': lastRetry, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReceiptsCompanion copyWith({ + Value? receiptId, + Value? contactId, + Value? messageId, + Value? message, + Value? contactWillSendsReceipt, + Value? willBeRetriedByMediaUpload, + Value? markForRetry, + Value? markForRetryAfterAccepted, + Value? ackByServerAt, + Value? retryCount, + Value? lastRetry, + Value? createdAt, + Value? rowid, + }) { + return ReceiptsCompanion( + receiptId: receiptId ?? this.receiptId, + contactId: contactId ?? this.contactId, + messageId: messageId ?? this.messageId, + message: message ?? this.message, + contactWillSendsReceipt: + contactWillSendsReceipt ?? this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: + willBeRetriedByMediaUpload ?? this.willBeRetriedByMediaUpload, + markForRetry: markForRetry ?? this.markForRetry, + markForRetryAfterAccepted: + markForRetryAfterAccepted ?? this.markForRetryAfterAccepted, + ackByServerAt: ackByServerAt ?? this.ackByServerAt, + retryCount: retryCount ?? this.retryCount, + lastRetry: lastRetry ?? this.lastRetry, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (receiptId.present) { + map['receipt_id'] = Variable(receiptId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (message.present) { + map['message'] = Variable(message.value); + } + if (contactWillSendsReceipt.present) { + map['contact_will_sends_receipt'] = Variable( + contactWillSendsReceipt.value, + ); + } + if (willBeRetriedByMediaUpload.present) { + map['will_be_retried_by_media_upload'] = Variable( + willBeRetriedByMediaUpload.value, + ); + } + if (markForRetry.present) { + map['mark_for_retry'] = Variable(markForRetry.value); + } + if (markForRetryAfterAccepted.present) { + map['mark_for_retry_after_accepted'] = Variable( + markForRetryAfterAccepted.value, + ); + } + if (ackByServerAt.present) { + map['ack_by_server_at'] = Variable(ackByServerAt.value); + } + if (retryCount.present) { + map['retry_count'] = Variable(retryCount.value); + } + if (lastRetry.present) { + map['last_retry'] = Variable(lastRetry.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('ReceiptsCompanion(') + ..write('receiptId: $receiptId, ') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('message: $message, ') + ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') + ..write('willBeRetriedByMediaUpload: $willBeRetriedByMediaUpload, ') + ..write('markForRetry: $markForRetry, ') + ..write('markForRetryAfterAccepted: $markForRetryAfterAccepted, ') + ..write('ackByServerAt: $ackByServerAt, ') + ..write('retryCount: $retryCount, ') + ..write('lastRetry: $lastRetry, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class ReceivedReceipts extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + ReceivedReceipts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn receiptId = GeneratedColumn( + 'receipt_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [receiptId, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'received_receipts'; + @override + Set get $primaryKey => {receiptId}; + @override + ReceivedReceiptsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReceivedReceiptsData( + receiptId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}receipt_id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + ReceivedReceipts createAlias(String alias) { + return ReceivedReceipts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(receipt_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ReceivedReceiptsData extends DataClass + implements Insertable { + final String receiptId; + final int createdAt; + const ReceivedReceiptsData({ + required this.receiptId, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['receipt_id'] = Variable(receiptId); + map['created_at'] = Variable(createdAt); + return map; + } + + ReceivedReceiptsCompanion toCompanion(bool nullToAbsent) { + return ReceivedReceiptsCompanion( + receiptId: Value(receiptId), + createdAt: Value(createdAt), + ); + } + + factory ReceivedReceiptsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReceivedReceiptsData( + receiptId: serializer.fromJson(json['receiptId']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'receiptId': serializer.toJson(receiptId), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReceivedReceiptsData copyWith({String? receiptId, int? createdAt}) => + ReceivedReceiptsData( + receiptId: receiptId ?? this.receiptId, + createdAt: createdAt ?? this.createdAt, + ); + ReceivedReceiptsData copyWithCompanion(ReceivedReceiptsCompanion data) { + return ReceivedReceiptsData( + receiptId: data.receiptId.present ? data.receiptId.value : this.receiptId, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReceivedReceiptsData(') + ..write('receiptId: $receiptId, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(receiptId, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReceivedReceiptsData && + other.receiptId == this.receiptId && + other.createdAt == this.createdAt); +} + +class ReceivedReceiptsCompanion extends UpdateCompanion { + final Value receiptId; + final Value createdAt; + final Value rowid; + const ReceivedReceiptsCompanion({ + this.receiptId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReceivedReceiptsCompanion.insert({ + required String receiptId, + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : receiptId = Value(receiptId); + static Insertable custom({ + Expression? receiptId, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (receiptId != null) 'receipt_id': receiptId, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReceivedReceiptsCompanion copyWith({ + Value? receiptId, + Value? createdAt, + Value? rowid, + }) { + return ReceivedReceiptsCompanion( + receiptId: receiptId ?? this.receiptId, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (receiptId.present) { + map['receipt_id'] = Variable(receiptId.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('ReceivedReceiptsCompanion(') + ..write('receiptId: $receiptId, ') + ..write('createdAt: $createdAt, ') + ..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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn identityKey = + GeneratedColumn( + 'identity_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalIdentityKeyStores createAlias(String alias) { + return SignalIdentityKeyStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(device_id, name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalIdentityKeyStoresData extends DataClass + implements Insertable { + final int deviceId; + final String name; + final i2.Uint8List identityKey; + final int 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, + i2.Uint8List? identityKey, + int? 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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn preKey = + GeneratedColumn( + 'pre_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalPreKeyStores createAlias(String alias) { + return SignalPreKeyStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(pre_key_id)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalPreKeyStoresData extends DataClass + implements Insertable { + final int preKeyId; + final i2.Uint8List preKey; + final int 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, + i2.Uint8List? preKey, + int? 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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderKey = + GeneratedColumn( + 'sender_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + @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); + } + + @override + List get customConstraints => const ['PRIMARY KEY(sender_key_name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalSenderKeyStoresData extends DataClass + implements Insertable { + final String senderKeyName; + final i2.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, + i2.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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn sessionRecord = + GeneratedColumn( + 'session_record', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalSessionStores createAlias(String alias) { + return SignalSessionStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(device_id, name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalSessionStoresData extends DataClass + implements Insertable { + final int deviceId; + final String name; + final i2.Uint8List sessionRecord; + final int 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, + i2.Uint8List? sessionRecord, + int? 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 i2.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 MessageActions extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MessageActions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn actionAt = GeneratedColumn( + 'action_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [messageId, contactId, type, actionAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'message_actions'; + @override + Set get $primaryKey => {messageId, contactId, type}; + @override + MessageActionsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MessageActionsData( + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + actionAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}action_at'], + )!, + ); + } + + @override + MessageActions createAlias(String alias) { + return MessageActions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(message_id, contact_id, type)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class MessageActionsData extends DataClass + implements Insertable { + final String messageId; + final int contactId; + final String type; + final int actionAt; + const MessageActionsData({ + required this.messageId, + required this.contactId, + required this.type, + required this.actionAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['message_id'] = Variable(messageId); + map['contact_id'] = Variable(contactId); + map['type'] = Variable(type); + map['action_at'] = Variable(actionAt); + return map; + } + + MessageActionsCompanion toCompanion(bool nullToAbsent) { + return MessageActionsCompanion( + messageId: Value(messageId), + contactId: Value(contactId), + type: Value(type), + actionAt: Value(actionAt), + ); + } + + factory MessageActionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessageActionsData( + messageId: serializer.fromJson(json['messageId']), + contactId: serializer.fromJson(json['contactId']), + type: serializer.fromJson(json['type']), + actionAt: serializer.fromJson(json['actionAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'messageId': serializer.toJson(messageId), + 'contactId': serializer.toJson(contactId), + 'type': serializer.toJson(type), + 'actionAt': serializer.toJson(actionAt), + }; + } + + MessageActionsData copyWith({ + String? messageId, + int? contactId, + String? type, + int? actionAt, + }) => MessageActionsData( + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + ); + MessageActionsData copyWithCompanion(MessageActionsCompanion data) { + return MessageActionsData( + messageId: data.messageId.present ? data.messageId.value : this.messageId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + type: data.type.present ? data.type.value : this.type, + actionAt: data.actionAt.present ? data.actionAt.value : this.actionAt, + ); + } + + @override + String toString() { + return (StringBuffer('MessageActionsData(') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('actionAt: $actionAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(messageId, contactId, type, actionAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessageActionsData && + other.messageId == this.messageId && + other.contactId == this.contactId && + other.type == this.type && + other.actionAt == this.actionAt); +} + +class MessageActionsCompanion extends UpdateCompanion { + final Value messageId; + final Value contactId; + final Value type; + final Value actionAt; + final Value rowid; + const MessageActionsCompanion({ + this.messageId = const Value.absent(), + this.contactId = const Value.absent(), + this.type = const Value.absent(), + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + MessageActionsCompanion.insert({ + required String messageId, + required int contactId, + required String type, + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : messageId = Value(messageId), + contactId = Value(contactId), + type = Value(type); + static Insertable custom({ + Expression? messageId, + Expression? contactId, + Expression? type, + Expression? actionAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (messageId != null) 'message_id': messageId, + if (contactId != null) 'contact_id': contactId, + if (type != null) 'type': type, + if (actionAt != null) 'action_at': actionAt, + if (rowid != null) 'rowid': rowid, + }); + } + + MessageActionsCompanion copyWith({ + Value? messageId, + Value? contactId, + Value? type, + Value? actionAt, + Value? rowid, + }) { + return MessageActionsCompanion( + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (actionAt.present) { + map['action_at'] = Variable(actionAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessageActionsCompanion(') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('actionAt: $actionAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class GroupHistories extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + GroupHistories(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupHistoryId = GeneratedColumn( + 'group_history_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn affectedContactId = GeneratedColumn( + 'affected_contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn oldGroupName = GeneratedColumn( + 'old_group_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn newGroupName = GeneratedColumn( + 'new_group_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn newDeleteMessagesAfterMilliseconds = + GeneratedColumn( + 'new_delete_messages_after_milliseconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn actionAt = GeneratedColumn( + 'action_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupHistoryId, + groupId, + contactId, + affectedContactId, + oldGroupName, + newGroupName, + newDeleteMessagesAfterMilliseconds, + type, + actionAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'group_histories'; + @override + Set get $primaryKey => {groupHistoryId}; + @override + GroupHistoriesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupHistoriesData( + groupHistoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_history_id'], + )!, + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + affectedContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}affected_contact_id'], + ), + oldGroupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}old_group_name'], + ), + newGroupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}new_group_name'], + ), + newDeleteMessagesAfterMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}new_delete_messages_after_milliseconds'], + ), + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + actionAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}action_at'], + )!, + ); + } + + @override + GroupHistories createAlias(String alias) { + return GroupHistories(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(group_history_id)']; + @override + bool get dontWriteConstraints => true; +} + +class GroupHistoriesData extends DataClass + implements Insertable { + final String groupHistoryId; + final String groupId; + final int? contactId; + final int? affectedContactId; + final String? oldGroupName; + final String? newGroupName; + final int? newDeleteMessagesAfterMilliseconds; + final String type; + final int actionAt; + const GroupHistoriesData({ + required this.groupHistoryId, + required this.groupId, + this.contactId, + this.affectedContactId, + this.oldGroupName, + this.newGroupName, + this.newDeleteMessagesAfterMilliseconds, + required this.type, + required this.actionAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_history_id'] = Variable(groupHistoryId); + map['group_id'] = Variable(groupId); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + if (!nullToAbsent || affectedContactId != null) { + map['affected_contact_id'] = Variable(affectedContactId); + } + if (!nullToAbsent || oldGroupName != null) { + map['old_group_name'] = Variable(oldGroupName); + } + if (!nullToAbsent || newGroupName != null) { + map['new_group_name'] = Variable(newGroupName); + } + if (!nullToAbsent || newDeleteMessagesAfterMilliseconds != null) { + map['new_delete_messages_after_milliseconds'] = Variable( + newDeleteMessagesAfterMilliseconds, + ); + } + map['type'] = Variable(type); + map['action_at'] = Variable(actionAt); + return map; + } + + GroupHistoriesCompanion toCompanion(bool nullToAbsent) { + return GroupHistoriesCompanion( + groupHistoryId: Value(groupHistoryId), + groupId: Value(groupId), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + affectedContactId: affectedContactId == null && nullToAbsent + ? const Value.absent() + : Value(affectedContactId), + oldGroupName: oldGroupName == null && nullToAbsent + ? const Value.absent() + : Value(oldGroupName), + newGroupName: newGroupName == null && nullToAbsent + ? const Value.absent() + : Value(newGroupName), + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds == null && nullToAbsent + ? const Value.absent() + : Value(newDeleteMessagesAfterMilliseconds), + type: Value(type), + actionAt: Value(actionAt), + ); + } + + factory GroupHistoriesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupHistoriesData( + groupHistoryId: serializer.fromJson(json['groupHistoryId']), + groupId: serializer.fromJson(json['groupId']), + contactId: serializer.fromJson(json['contactId']), + affectedContactId: serializer.fromJson(json['affectedContactId']), + oldGroupName: serializer.fromJson(json['oldGroupName']), + newGroupName: serializer.fromJson(json['newGroupName']), + newDeleteMessagesAfterMilliseconds: serializer.fromJson( + json['newDeleteMessagesAfterMilliseconds'], + ), + type: serializer.fromJson(json['type']), + actionAt: serializer.fromJson(json['actionAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupHistoryId': serializer.toJson(groupHistoryId), + 'groupId': serializer.toJson(groupId), + 'contactId': serializer.toJson(contactId), + 'affectedContactId': serializer.toJson(affectedContactId), + 'oldGroupName': serializer.toJson(oldGroupName), + 'newGroupName': serializer.toJson(newGroupName), + 'newDeleteMessagesAfterMilliseconds': serializer.toJson( + newDeleteMessagesAfterMilliseconds, + ), + 'type': serializer.toJson(type), + 'actionAt': serializer.toJson(actionAt), + }; + } + + GroupHistoriesData copyWith({ + String? groupHistoryId, + String? groupId, + Value contactId = const Value.absent(), + Value affectedContactId = const Value.absent(), + Value oldGroupName = const Value.absent(), + Value newGroupName = const Value.absent(), + Value newDeleteMessagesAfterMilliseconds = const Value.absent(), + String? type, + int? actionAt, + }) => GroupHistoriesData( + groupHistoryId: groupHistoryId ?? this.groupHistoryId, + groupId: groupId ?? this.groupId, + contactId: contactId.present ? contactId.value : this.contactId, + affectedContactId: affectedContactId.present + ? affectedContactId.value + : this.affectedContactId, + oldGroupName: oldGroupName.present ? oldGroupName.value : this.oldGroupName, + newGroupName: newGroupName.present ? newGroupName.value : this.newGroupName, + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds.present + ? newDeleteMessagesAfterMilliseconds.value + : this.newDeleteMessagesAfterMilliseconds, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + ); + GroupHistoriesData copyWithCompanion(GroupHistoriesCompanion data) { + return GroupHistoriesData( + groupHistoryId: data.groupHistoryId.present + ? data.groupHistoryId.value + : this.groupHistoryId, + groupId: data.groupId.present ? data.groupId.value : this.groupId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + affectedContactId: data.affectedContactId.present + ? data.affectedContactId.value + : this.affectedContactId, + oldGroupName: data.oldGroupName.present + ? data.oldGroupName.value + : this.oldGroupName, + newGroupName: data.newGroupName.present + ? data.newGroupName.value + : this.newGroupName, + newDeleteMessagesAfterMilliseconds: + data.newDeleteMessagesAfterMilliseconds.present + ? data.newDeleteMessagesAfterMilliseconds.value + : this.newDeleteMessagesAfterMilliseconds, + type: data.type.present ? data.type.value : this.type, + actionAt: data.actionAt.present ? data.actionAt.value : this.actionAt, + ); + } + + @override + String toString() { + return (StringBuffer('GroupHistoriesData(') + ..write('groupHistoryId: $groupHistoryId, ') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('affectedContactId: $affectedContactId, ') + ..write('oldGroupName: $oldGroupName, ') + ..write('newGroupName: $newGroupName, ') + ..write( + 'newDeleteMessagesAfterMilliseconds: $newDeleteMessagesAfterMilliseconds, ', + ) + ..write('type: $type, ') + ..write('actionAt: $actionAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupHistoryId, + groupId, + contactId, + affectedContactId, + oldGroupName, + newGroupName, + newDeleteMessagesAfterMilliseconds, + type, + actionAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupHistoriesData && + other.groupHistoryId == this.groupHistoryId && + other.groupId == this.groupId && + other.contactId == this.contactId && + other.affectedContactId == this.affectedContactId && + other.oldGroupName == this.oldGroupName && + other.newGroupName == this.newGroupName && + other.newDeleteMessagesAfterMilliseconds == + this.newDeleteMessagesAfterMilliseconds && + other.type == this.type && + other.actionAt == this.actionAt); +} + +class GroupHistoriesCompanion extends UpdateCompanion { + final Value groupHistoryId; + final Value groupId; + final Value contactId; + final Value affectedContactId; + final Value oldGroupName; + final Value newGroupName; + final Value newDeleteMessagesAfterMilliseconds; + final Value type; + final Value actionAt; + final Value rowid; + const GroupHistoriesCompanion({ + this.groupHistoryId = const Value.absent(), + this.groupId = const Value.absent(), + this.contactId = const Value.absent(), + this.affectedContactId = const Value.absent(), + this.oldGroupName = const Value.absent(), + this.newGroupName = const Value.absent(), + this.newDeleteMessagesAfterMilliseconds = const Value.absent(), + this.type = const Value.absent(), + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupHistoriesCompanion.insert({ + required String groupHistoryId, + required String groupId, + this.contactId = const Value.absent(), + this.affectedContactId = const Value.absent(), + this.oldGroupName = const Value.absent(), + this.newGroupName = const Value.absent(), + this.newDeleteMessagesAfterMilliseconds = const Value.absent(), + required String type, + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupHistoryId = Value(groupHistoryId), + groupId = Value(groupId), + type = Value(type); + static Insertable custom({ + Expression? groupHistoryId, + Expression? groupId, + Expression? contactId, + Expression? affectedContactId, + Expression? oldGroupName, + Expression? newGroupName, + Expression? newDeleteMessagesAfterMilliseconds, + Expression? type, + Expression? actionAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupHistoryId != null) 'group_history_id': groupHistoryId, + if (groupId != null) 'group_id': groupId, + if (contactId != null) 'contact_id': contactId, + if (affectedContactId != null) 'affected_contact_id': affectedContactId, + if (oldGroupName != null) 'old_group_name': oldGroupName, + if (newGroupName != null) 'new_group_name': newGroupName, + if (newDeleteMessagesAfterMilliseconds != null) + 'new_delete_messages_after_milliseconds': + newDeleteMessagesAfterMilliseconds, + if (type != null) 'type': type, + if (actionAt != null) 'action_at': actionAt, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupHistoriesCompanion copyWith({ + Value? groupHistoryId, + Value? groupId, + Value? contactId, + Value? affectedContactId, + Value? oldGroupName, + Value? newGroupName, + Value? newDeleteMessagesAfterMilliseconds, + Value? type, + Value? actionAt, + Value? rowid, + }) { + return GroupHistoriesCompanion( + groupHistoryId: groupHistoryId ?? this.groupHistoryId, + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + affectedContactId: affectedContactId ?? this.affectedContactId, + oldGroupName: oldGroupName ?? this.oldGroupName, + newGroupName: newGroupName ?? this.newGroupName, + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds ?? + this.newDeleteMessagesAfterMilliseconds, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupHistoryId.present) { + map['group_history_id'] = Variable(groupHistoryId.value); + } + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (affectedContactId.present) { + map['affected_contact_id'] = Variable(affectedContactId.value); + } + if (oldGroupName.present) { + map['old_group_name'] = Variable(oldGroupName.value); + } + if (newGroupName.present) { + map['new_group_name'] = Variable(newGroupName.value); + } + if (newDeleteMessagesAfterMilliseconds.present) { + map['new_delete_messages_after_milliseconds'] = Variable( + newDeleteMessagesAfterMilliseconds.value, + ); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (actionAt.present) { + map['action_at'] = Variable(actionAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GroupHistoriesCompanion(') + ..write('groupHistoryId: $groupHistoryId, ') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('affectedContactId: $affectedContactId, ') + ..write('oldGroupName: $oldGroupName, ') + ..write('newGroupName: $newGroupName, ') + ..write( + 'newDeleteMessagesAfterMilliseconds: $newDeleteMessagesAfterMilliseconds, ', + ) + ..write('type: $type, ') + ..write('actionAt: $actionAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class KeyVerifications extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + KeyVerifications(this.attachedDatabase, [this._alias]); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [contactId, type, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'key_verifications'; + @override + Set get $primaryKey => {contactId}; + @override + KeyVerificationsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return KeyVerificationsData( + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + KeyVerifications createAlias(String alias) { + return KeyVerifications(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(contact_id)']; + @override + bool get dontWriteConstraints => true; +} + +class KeyVerificationsData extends DataClass + implements Insertable { + final int contactId; + final String type; + final int createdAt; + const KeyVerificationsData({ + required this.contactId, + required this.type, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['contact_id'] = Variable(contactId); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + return map; + } + + KeyVerificationsCompanion toCompanion(bool nullToAbsent) { + return KeyVerificationsCompanion( + contactId: Value(contactId), + type: Value(type), + createdAt: Value(createdAt), + ); + } + + factory KeyVerificationsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return KeyVerificationsData( + contactId: serializer.fromJson(json['contactId']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'contactId': serializer.toJson(contactId), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + }; + } + + KeyVerificationsData copyWith({ + int? contactId, + String? type, + int? createdAt, + }) => KeyVerificationsData( + contactId: contactId ?? this.contactId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + KeyVerificationsData copyWithCompanion(KeyVerificationsCompanion data) { + return KeyVerificationsData( + contactId: data.contactId.present ? data.contactId.value : this.contactId, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('KeyVerificationsData(') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(contactId, type, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is KeyVerificationsData && + other.contactId == this.contactId && + other.type == this.type && + other.createdAt == this.createdAt); +} + +class KeyVerificationsCompanion extends UpdateCompanion { + final Value contactId; + final Value type; + final Value createdAt; + const KeyVerificationsCompanion({ + this.contactId = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + }); + KeyVerificationsCompanion.insert({ + this.contactId = const Value.absent(), + required String type, + this.createdAt = const Value.absent(), + }) : type = Value(type); + static Insertable custom({ + Expression? contactId, + Expression? type, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (contactId != null) 'contact_id': contactId, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + }); + } + + KeyVerificationsCompanion copyWith({ + Value? contactId, + Value? type, + Value? createdAt, + }) { + return KeyVerificationsCompanion( + contactId: contactId ?? this.contactId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('KeyVerificationsCompanion(') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class VerificationTokens extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + VerificationTokens(this.attachedDatabase, [this._alias]); + late final GeneratedColumn tokenId = GeneratedColumn( + 'token_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn token = + GeneratedColumn( + 'token', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [tokenId, token, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'verification_tokens'; + @override + Set get $primaryKey => {tokenId}; + @override + VerificationTokensData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return VerificationTokensData( + tokenId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}token_id'], + )!, + token: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}token'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + VerificationTokens createAlias(String alias) { + return VerificationTokens(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class VerificationTokensData extends DataClass + implements Insertable { + final int tokenId; + final i2.Uint8List token; + final int createdAt; + const VerificationTokensData({ + required this.tokenId, + required this.token, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['token_id'] = Variable(tokenId); + map['token'] = Variable(token); + map['created_at'] = Variable(createdAt); + return map; + } + + VerificationTokensCompanion toCompanion(bool nullToAbsent) { + return VerificationTokensCompanion( + tokenId: Value(tokenId), + token: Value(token), + createdAt: Value(createdAt), + ); + } + + factory VerificationTokensData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return VerificationTokensData( + tokenId: serializer.fromJson(json['tokenId']), + token: serializer.fromJson(json['token']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'tokenId': serializer.toJson(tokenId), + 'token': serializer.toJson(token), + 'createdAt': serializer.toJson(createdAt), + }; + } + + VerificationTokensData copyWith({ + int? tokenId, + i2.Uint8List? token, + int? createdAt, + }) => VerificationTokensData( + tokenId: tokenId ?? this.tokenId, + token: token ?? this.token, + createdAt: createdAt ?? this.createdAt, + ); + VerificationTokensData copyWithCompanion(VerificationTokensCompanion data) { + return VerificationTokensData( + tokenId: data.tokenId.present ? data.tokenId.value : this.tokenId, + token: data.token.present ? data.token.value : this.token, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('VerificationTokensData(') + ..write('tokenId: $tokenId, ') + ..write('token: $token, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(tokenId, $driftBlobEquality.hash(token), createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is VerificationTokensData && + other.tokenId == this.tokenId && + $driftBlobEquality.equals(other.token, this.token) && + other.createdAt == this.createdAt); +} + +class VerificationTokensCompanion + extends UpdateCompanion { + final Value tokenId; + final Value token; + final Value createdAt; + const VerificationTokensCompanion({ + this.tokenId = const Value.absent(), + this.token = const Value.absent(), + this.createdAt = const Value.absent(), + }); + VerificationTokensCompanion.insert({ + this.tokenId = const Value.absent(), + required i2.Uint8List token, + this.createdAt = const Value.absent(), + }) : token = Value(token); + static Insertable custom({ + Expression? tokenId, + Expression? token, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (tokenId != null) 'token_id': tokenId, + if (token != null) 'token': token, + if (createdAt != null) 'created_at': createdAt, + }); + } + + VerificationTokensCompanion copyWith({ + Value? tokenId, + Value? token, + Value? createdAt, + }) { + return VerificationTokensCompanion( + tokenId: tokenId ?? this.tokenId, + token: token ?? this.token, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (tokenId.present) { + map['token_id'] = Variable(tokenId.value); + } + if (token.present) { + map['token'] = Variable(token.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('VerificationTokensCompanion(') + ..write('tokenId: $tokenId, ') + ..write('token: $token, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryAnnouncedUsers extends Table + with + TableInfo< + UserDiscoveryAnnouncedUsers, + UserDiscoveryAnnouncedUsersData + > { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryAnnouncedUsers(this.attachedDatabase, [this._alias]); + late final GeneratedColumn announcedUserId = GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn announcedPublicKey = + GeneratedColumn( + 'announced_public_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicId = GeneratedColumn( + 'public_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL UNIQUE', + ); + @override + List get $columns => [ + announcedUserId, + announcedPublicKey, + publicId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_announced_users'; + @override + Set get $primaryKey => {announcedUserId}; + @override + UserDiscoveryAnnouncedUsersData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryAnnouncedUsersData( + announcedUserId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}announced_user_id'], + )!, + announcedPublicKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}announced_public_key'], + )!, + publicId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_id'], + )!, + ); + } + + @override + UserDiscoveryAnnouncedUsers createAlias(String alias) { + return UserDiscoveryAnnouncedUsers(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(announced_user_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryAnnouncedUsersData extends DataClass + implements Insertable { + final int announcedUserId; + final i2.Uint8List announcedPublicKey; + final int publicId; + const UserDiscoveryAnnouncedUsersData({ + required this.announcedUserId, + required this.announcedPublicKey, + required this.publicId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['announced_user_id'] = Variable(announcedUserId); + map['announced_public_key'] = Variable(announcedPublicKey); + map['public_id'] = Variable(publicId); + return map; + } + + UserDiscoveryAnnouncedUsersCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: Value(announcedUserId), + announcedPublicKey: Value(announcedPublicKey), + publicId: Value(publicId), + ); + } + + factory UserDiscoveryAnnouncedUsersData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryAnnouncedUsersData( + announcedUserId: serializer.fromJson(json['announcedUserId']), + announcedPublicKey: serializer.fromJson( + json['announcedPublicKey'], + ), + publicId: serializer.fromJson(json['publicId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'announcedUserId': serializer.toJson(announcedUserId), + 'announcedPublicKey': serializer.toJson(announcedPublicKey), + 'publicId': serializer.toJson(publicId), + }; + } + + UserDiscoveryAnnouncedUsersData copyWith({ + int? announcedUserId, + i2.Uint8List? announcedPublicKey, + int? publicId, + }) => UserDiscoveryAnnouncedUsersData( + announcedUserId: announcedUserId ?? this.announcedUserId, + announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, + publicId: publicId ?? this.publicId, + ); + UserDiscoveryAnnouncedUsersData copyWithCompanion( + UserDiscoveryAnnouncedUsersCompanion data, + ) { + return UserDiscoveryAnnouncedUsersData( + announcedUserId: data.announcedUserId.present + ? data.announcedUserId.value + : this.announcedUserId, + announcedPublicKey: data.announcedPublicKey.present + ? data.announcedPublicKey.value + : this.announcedPublicKey, + publicId: data.publicId.present ? data.publicId.value : this.publicId, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryAnnouncedUsersData(') + ..write('announcedUserId: $announcedUserId, ') + ..write('announcedPublicKey: $announcedPublicKey, ') + ..write('publicId: $publicId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + announcedUserId, + $driftBlobEquality.hash(announcedPublicKey), + publicId, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryAnnouncedUsersData && + other.announcedUserId == this.announcedUserId && + $driftBlobEquality.equals( + other.announcedPublicKey, + this.announcedPublicKey, + ) && + other.publicId == this.publicId); +} + +class UserDiscoveryAnnouncedUsersCompanion + extends UpdateCompanion { + final Value announcedUserId; + final Value announcedPublicKey; + final Value publicId; + const UserDiscoveryAnnouncedUsersCompanion({ + this.announcedUserId = const Value.absent(), + this.announcedPublicKey = const Value.absent(), + this.publicId = const Value.absent(), + }); + UserDiscoveryAnnouncedUsersCompanion.insert({ + this.announcedUserId = const Value.absent(), + required i2.Uint8List announcedPublicKey, + required int publicId, + }) : announcedPublicKey = Value(announcedPublicKey), + publicId = Value(publicId); + static Insertable custom({ + Expression? announcedUserId, + Expression? announcedPublicKey, + Expression? publicId, + }) { + return RawValuesInsertable({ + if (announcedUserId != null) 'announced_user_id': announcedUserId, + if (announcedPublicKey != null) + 'announced_public_key': announcedPublicKey, + if (publicId != null) 'public_id': publicId, + }); + } + + UserDiscoveryAnnouncedUsersCompanion copyWith({ + Value? announcedUserId, + Value? announcedPublicKey, + Value? publicId, + }) { + return UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: announcedUserId ?? this.announcedUserId, + announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, + publicId: publicId ?? this.publicId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (announcedUserId.present) { + map['announced_user_id'] = Variable(announcedUserId.value); + } + if (announcedPublicKey.present) { + map['announced_public_key'] = Variable( + announcedPublicKey.value, + ); + } + if (publicId.present) { + map['public_id'] = Variable(publicId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryAnnouncedUsersCompanion(') + ..write('announcedUserId: $announcedUserId, ') + ..write('announcedPublicKey: $announcedPublicKey, ') + ..write('publicId: $publicId') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryUserRelations extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryUserRelations(this.attachedDatabase, [this._alias]); + late final GeneratedColumn announcedUserId = GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES user_discovery_announced_users(announced_user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn fromContactId = GeneratedColumn( + 'from_contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn publicKeyVerifiedTimestamp = + GeneratedColumn( + 'public_key_verified_timestamp', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + announcedUserId, + fromContactId, + publicKeyVerifiedTimestamp, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_user_relations'; + @override + Set get $primaryKey => {announcedUserId, fromContactId}; + @override + UserDiscoveryUserRelationsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryUserRelationsData( + announcedUserId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}announced_user_id'], + )!, + fromContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}from_contact_id'], + )!, + publicKeyVerifiedTimestamp: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_key_verified_timestamp'], + ), + ); + } + + @override + UserDiscoveryUserRelations createAlias(String alias) { + return UserDiscoveryUserRelations(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(announced_user_id, from_contact_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryUserRelationsData extends DataClass + implements Insertable { + final int announcedUserId; + final int fromContactId; + final int? publicKeyVerifiedTimestamp; + const UserDiscoveryUserRelationsData({ + required this.announcedUserId, + required this.fromContactId, + this.publicKeyVerifiedTimestamp, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['announced_user_id'] = Variable(announcedUserId); + map['from_contact_id'] = Variable(fromContactId); + if (!nullToAbsent || publicKeyVerifiedTimestamp != null) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp, + ); + } + return map; + } + + UserDiscoveryUserRelationsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryUserRelationsCompanion( + announcedUserId: Value(announcedUserId), + fromContactId: Value(fromContactId), + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp == null && nullToAbsent + ? const Value.absent() + : Value(publicKeyVerifiedTimestamp), + ); + } + + factory UserDiscoveryUserRelationsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryUserRelationsData( + announcedUserId: serializer.fromJson(json['announcedUserId']), + fromContactId: serializer.fromJson(json['fromContactId']), + publicKeyVerifiedTimestamp: serializer.fromJson( + json['publicKeyVerifiedTimestamp'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'announcedUserId': serializer.toJson(announcedUserId), + 'fromContactId': serializer.toJson(fromContactId), + 'publicKeyVerifiedTimestamp': serializer.toJson( + publicKeyVerifiedTimestamp, + ), + }; + } + + UserDiscoveryUserRelationsData copyWith({ + int? announcedUserId, + int? fromContactId, + Value publicKeyVerifiedTimestamp = const Value.absent(), + }) => UserDiscoveryUserRelationsData( + announcedUserId: announcedUserId ?? this.announcedUserId, + fromContactId: fromContactId ?? this.fromContactId, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp.present + ? publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + UserDiscoveryUserRelationsData copyWithCompanion( + UserDiscoveryUserRelationsCompanion data, + ) { + return UserDiscoveryUserRelationsData( + announcedUserId: data.announcedUserId.present + ? data.announcedUserId.value + : this.announcedUserId, + fromContactId: data.fromContactId.present + ? data.fromContactId.value + : this.fromContactId, + publicKeyVerifiedTimestamp: data.publicKeyVerifiedTimestamp.present + ? data.publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryUserRelationsData(') + ..write('announcedUserId: $announcedUserId, ') + ..write('fromContactId: $fromContactId, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(announcedUserId, fromContactId, publicKeyVerifiedTimestamp); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryUserRelationsData && + other.announcedUserId == this.announcedUserId && + other.fromContactId == this.fromContactId && + other.publicKeyVerifiedTimestamp == this.publicKeyVerifiedTimestamp); +} + +class UserDiscoveryUserRelationsCompanion + extends UpdateCompanion { + final Value announcedUserId; + final Value fromContactId; + final Value publicKeyVerifiedTimestamp; + final Value rowid; + const UserDiscoveryUserRelationsCompanion({ + this.announcedUserId = const Value.absent(), + this.fromContactId = const Value.absent(), + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }); + UserDiscoveryUserRelationsCompanion.insert({ + required int announcedUserId, + required int fromContactId, + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }) : announcedUserId = Value(announcedUserId), + fromContactId = Value(fromContactId); + static Insertable custom({ + Expression? announcedUserId, + Expression? fromContactId, + Expression? publicKeyVerifiedTimestamp, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (announcedUserId != null) 'announced_user_id': announcedUserId, + if (fromContactId != null) 'from_contact_id': fromContactId, + if (publicKeyVerifiedTimestamp != null) + 'public_key_verified_timestamp': publicKeyVerifiedTimestamp, + if (rowid != null) 'rowid': rowid, + }); + } + + UserDiscoveryUserRelationsCompanion copyWith({ + Value? announcedUserId, + Value? fromContactId, + Value? publicKeyVerifiedTimestamp, + Value? rowid, + }) { + return UserDiscoveryUserRelationsCompanion( + announcedUserId: announcedUserId ?? this.announcedUserId, + fromContactId: fromContactId ?? this.fromContactId, + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp ?? this.publicKeyVerifiedTimestamp, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (announcedUserId.present) { + map['announced_user_id'] = Variable(announcedUserId.value); + } + if (fromContactId.present) { + map['from_contact_id'] = Variable(fromContactId.value); + } + if (publicKeyVerifiedTimestamp.present) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp.value, + ); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryUserRelationsCompanion(') + ..write('announcedUserId: $announcedUserId, ') + ..write('fromContactId: $fromContactId, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryOtherPromotions extends Table + with + TableInfo< + UserDiscoveryOtherPromotions, + UserDiscoveryOtherPromotionsData + > { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryOtherPromotions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn fromContactId = GeneratedColumn( + 'from_contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn promotionId = GeneratedColumn( + 'promotion_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicId = GeneratedColumn( + 'public_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn threshold = GeneratedColumn( + 'threshold', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn announcementShare = + GeneratedColumn( + 'announcement_share', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicKeyVerifiedTimestamp = + GeneratedColumn( + 'public_key_verified_timestamp', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + fromContactId, + promotionId, + publicId, + threshold, + announcementShare, + publicKeyVerifiedTimestamp, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_other_promotions'; + @override + Set get $primaryKey => {fromContactId, promotionId}; + @override + UserDiscoveryOtherPromotionsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryOtherPromotionsData( + fromContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}from_contact_id'], + )!, + promotionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}promotion_id'], + )!, + publicId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_id'], + )!, + threshold: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}threshold'], + )!, + announcementShare: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}announcement_share'], + )!, + publicKeyVerifiedTimestamp: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_key_verified_timestamp'], + ), + ); + } + + @override + UserDiscoveryOtherPromotions createAlias(String alias) { + return UserDiscoveryOtherPromotions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(from_contact_id, promotion_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryOtherPromotionsData extends DataClass + implements Insertable { + final int fromContactId; + final int promotionId; + final int publicId; + final int threshold; + final i2.Uint8List announcementShare; + final int? publicKeyVerifiedTimestamp; + const UserDiscoveryOtherPromotionsData({ + required this.fromContactId, + required this.promotionId, + required this.publicId, + required this.threshold, + required this.announcementShare, + this.publicKeyVerifiedTimestamp, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['from_contact_id'] = Variable(fromContactId); + map['promotion_id'] = Variable(promotionId); + map['public_id'] = Variable(publicId); + map['threshold'] = Variable(threshold); + map['announcement_share'] = Variable(announcementShare); + if (!nullToAbsent || publicKeyVerifiedTimestamp != null) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp, + ); + } + return map; + } + + UserDiscoveryOtherPromotionsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryOtherPromotionsCompanion( + fromContactId: Value(fromContactId), + promotionId: Value(promotionId), + publicId: Value(publicId), + threshold: Value(threshold), + announcementShare: Value(announcementShare), + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp == null && nullToAbsent + ? const Value.absent() + : Value(publicKeyVerifiedTimestamp), + ); + } + + factory UserDiscoveryOtherPromotionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryOtherPromotionsData( + fromContactId: serializer.fromJson(json['fromContactId']), + promotionId: serializer.fromJson(json['promotionId']), + publicId: serializer.fromJson(json['publicId']), + threshold: serializer.fromJson(json['threshold']), + announcementShare: serializer.fromJson( + json['announcementShare'], + ), + publicKeyVerifiedTimestamp: serializer.fromJson( + json['publicKeyVerifiedTimestamp'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'fromContactId': serializer.toJson(fromContactId), + 'promotionId': serializer.toJson(promotionId), + 'publicId': serializer.toJson(publicId), + 'threshold': serializer.toJson(threshold), + 'announcementShare': serializer.toJson(announcementShare), + 'publicKeyVerifiedTimestamp': serializer.toJson( + publicKeyVerifiedTimestamp, + ), + }; + } + + UserDiscoveryOtherPromotionsData copyWith({ + int? fromContactId, + int? promotionId, + int? publicId, + int? threshold, + i2.Uint8List? announcementShare, + Value publicKeyVerifiedTimestamp = const Value.absent(), + }) => UserDiscoveryOtherPromotionsData( + fromContactId: fromContactId ?? this.fromContactId, + promotionId: promotionId ?? this.promotionId, + publicId: publicId ?? this.publicId, + threshold: threshold ?? this.threshold, + announcementShare: announcementShare ?? this.announcementShare, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp.present + ? publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + UserDiscoveryOtherPromotionsData copyWithCompanion( + UserDiscoveryOtherPromotionsCompanion data, + ) { + return UserDiscoveryOtherPromotionsData( + fromContactId: data.fromContactId.present + ? data.fromContactId.value + : this.fromContactId, + promotionId: data.promotionId.present + ? data.promotionId.value + : this.promotionId, + publicId: data.publicId.present ? data.publicId.value : this.publicId, + threshold: data.threshold.present ? data.threshold.value : this.threshold, + announcementShare: data.announcementShare.present + ? data.announcementShare.value + : this.announcementShare, + publicKeyVerifiedTimestamp: data.publicKeyVerifiedTimestamp.present + ? data.publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOtherPromotionsData(') + ..write('fromContactId: $fromContactId, ') + ..write('promotionId: $promotionId, ') + ..write('publicId: $publicId, ') + ..write('threshold: $threshold, ') + ..write('announcementShare: $announcementShare, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + fromContactId, + promotionId, + publicId, + threshold, + $driftBlobEquality.hash(announcementShare), + publicKeyVerifiedTimestamp, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryOtherPromotionsData && + other.fromContactId == this.fromContactId && + other.promotionId == this.promotionId && + other.publicId == this.publicId && + other.threshold == this.threshold && + $driftBlobEquality.equals( + other.announcementShare, + this.announcementShare, + ) && + other.publicKeyVerifiedTimestamp == this.publicKeyVerifiedTimestamp); +} + +class UserDiscoveryOtherPromotionsCompanion + extends UpdateCompanion { + final Value fromContactId; + final Value promotionId; + final Value publicId; + final Value threshold; + final Value announcementShare; + final Value publicKeyVerifiedTimestamp; + final Value rowid; + const UserDiscoveryOtherPromotionsCompanion({ + this.fromContactId = const Value.absent(), + this.promotionId = const Value.absent(), + this.publicId = const Value.absent(), + this.threshold = const Value.absent(), + this.announcementShare = const Value.absent(), + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }); + UserDiscoveryOtherPromotionsCompanion.insert({ + required int fromContactId, + required int promotionId, + required int publicId, + required int threshold, + required i2.Uint8List announcementShare, + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }) : fromContactId = Value(fromContactId), + promotionId = Value(promotionId), + publicId = Value(publicId), + threshold = Value(threshold), + announcementShare = Value(announcementShare); + static Insertable custom({ + Expression? fromContactId, + Expression? promotionId, + Expression? publicId, + Expression? threshold, + Expression? announcementShare, + Expression? publicKeyVerifiedTimestamp, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (fromContactId != null) 'from_contact_id': fromContactId, + if (promotionId != null) 'promotion_id': promotionId, + if (publicId != null) 'public_id': publicId, + if (threshold != null) 'threshold': threshold, + if (announcementShare != null) 'announcement_share': announcementShare, + if (publicKeyVerifiedTimestamp != null) + 'public_key_verified_timestamp': publicKeyVerifiedTimestamp, + if (rowid != null) 'rowid': rowid, + }); + } + + UserDiscoveryOtherPromotionsCompanion copyWith({ + Value? fromContactId, + Value? promotionId, + Value? publicId, + Value? threshold, + Value? announcementShare, + Value? publicKeyVerifiedTimestamp, + Value? rowid, + }) { + return UserDiscoveryOtherPromotionsCompanion( + fromContactId: fromContactId ?? this.fromContactId, + promotionId: promotionId ?? this.promotionId, + publicId: publicId ?? this.publicId, + threshold: threshold ?? this.threshold, + announcementShare: announcementShare ?? this.announcementShare, + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp ?? this.publicKeyVerifiedTimestamp, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (fromContactId.present) { + map['from_contact_id'] = Variable(fromContactId.value); + } + if (promotionId.present) { + map['promotion_id'] = Variable(promotionId.value); + } + if (publicId.present) { + map['public_id'] = Variable(publicId.value); + } + if (threshold.present) { + map['threshold'] = Variable(threshold.value); + } + if (announcementShare.present) { + map['announcement_share'] = Variable( + announcementShare.value, + ); + } + if (publicKeyVerifiedTimestamp.present) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp.value, + ); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOtherPromotionsCompanion(') + ..write('fromContactId: $fromContactId, ') + ..write('promotionId: $promotionId, ') + ..write('publicId: $publicId, ') + ..write('threshold: $threshold, ') + ..write('announcementShare: $announcementShare, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryOwnPromotions extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryOwnPromotions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn versionId = GeneratedColumn( + 'version_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn promotion = + GeneratedColumn( + 'promotion', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + @override + List get $columns => [versionId, contactId, promotion]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_own_promotions'; + @override + Set get $primaryKey => {versionId}; + @override + UserDiscoveryOwnPromotionsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryOwnPromotionsData( + versionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}version_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + promotion: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}promotion'], + )!, + ); + } + + @override + UserDiscoveryOwnPromotions createAlias(String alias) { + return UserDiscoveryOwnPromotions(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryOwnPromotionsData extends DataClass + implements Insertable { + final int versionId; + final int contactId; + final i2.Uint8List promotion; + const UserDiscoveryOwnPromotionsData({ + required this.versionId, + required this.contactId, + required this.promotion, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['version_id'] = Variable(versionId); + map['contact_id'] = Variable(contactId); + map['promotion'] = Variable(promotion); + return map; + } + + UserDiscoveryOwnPromotionsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryOwnPromotionsCompanion( + versionId: Value(versionId), + contactId: Value(contactId), + promotion: Value(promotion), + ); + } + + factory UserDiscoveryOwnPromotionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryOwnPromotionsData( + versionId: serializer.fromJson(json['versionId']), + contactId: serializer.fromJson(json['contactId']), + promotion: serializer.fromJson(json['promotion']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'versionId': serializer.toJson(versionId), + 'contactId': serializer.toJson(contactId), + 'promotion': serializer.toJson(promotion), + }; + } + + UserDiscoveryOwnPromotionsData copyWith({ + int? versionId, + int? contactId, + i2.Uint8List? promotion, + }) => UserDiscoveryOwnPromotionsData( + versionId: versionId ?? this.versionId, + contactId: contactId ?? this.contactId, + promotion: promotion ?? this.promotion, + ); + UserDiscoveryOwnPromotionsData copyWithCompanion( + UserDiscoveryOwnPromotionsCompanion data, + ) { + return UserDiscoveryOwnPromotionsData( + versionId: data.versionId.present ? data.versionId.value : this.versionId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + promotion: data.promotion.present ? data.promotion.value : this.promotion, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOwnPromotionsData(') + ..write('versionId: $versionId, ') + ..write('contactId: $contactId, ') + ..write('promotion: $promotion') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(versionId, contactId, $driftBlobEquality.hash(promotion)); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryOwnPromotionsData && + other.versionId == this.versionId && + other.contactId == this.contactId && + $driftBlobEquality.equals(other.promotion, this.promotion)); +} + +class UserDiscoveryOwnPromotionsCompanion + extends UpdateCompanion { + final Value versionId; + final Value contactId; + final Value promotion; + const UserDiscoveryOwnPromotionsCompanion({ + this.versionId = const Value.absent(), + this.contactId = const Value.absent(), + this.promotion = const Value.absent(), + }); + UserDiscoveryOwnPromotionsCompanion.insert({ + this.versionId = const Value.absent(), + required int contactId, + required i2.Uint8List promotion, + }) : contactId = Value(contactId), + promotion = Value(promotion); + static Insertable custom({ + Expression? versionId, + Expression? contactId, + Expression? promotion, + }) { + return RawValuesInsertable({ + if (versionId != null) 'version_id': versionId, + if (contactId != null) 'contact_id': contactId, + if (promotion != null) 'promotion': promotion, + }); + } + + UserDiscoveryOwnPromotionsCompanion copyWith({ + Value? versionId, + Value? contactId, + Value? promotion, + }) { + return UserDiscoveryOwnPromotionsCompanion( + versionId: versionId ?? this.versionId, + contactId: contactId ?? this.contactId, + promotion: promotion ?? this.promotion, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (versionId.present) { + map['version_id'] = Variable(versionId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (promotion.present) { + map['promotion'] = Variable(promotion.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOwnPromotionsCompanion(') + ..write('versionId: $versionId, ') + ..write('contactId: $contactId, ') + ..write('promotion: $promotion') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryShares extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryShares(this.attachedDatabase, [this._alias]); + late final GeneratedColumn shareId = GeneratedColumn( + 'share_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn share = + GeneratedColumn( + 'share', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + @override + List get $columns => [shareId, share, contactId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_shares'; + @override + Set get $primaryKey => {shareId}; + @override + UserDiscoverySharesData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoverySharesData( + shareId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}share_id'], + )!, + share: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}share'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + ); + } + + @override + UserDiscoveryShares createAlias(String alias) { + return UserDiscoveryShares(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoverySharesData extends DataClass + implements Insertable { + final int shareId; + final i2.Uint8List share; + final int? contactId; + const UserDiscoverySharesData({ + required this.shareId, + required this.share, + this.contactId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['share_id'] = Variable(shareId); + map['share'] = Variable(share); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + return map; + } + + UserDiscoverySharesCompanion toCompanion(bool nullToAbsent) { + return UserDiscoverySharesCompanion( + shareId: Value(shareId), + share: Value(share), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + ); + } + + factory UserDiscoverySharesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoverySharesData( + shareId: serializer.fromJson(json['shareId']), + share: serializer.fromJson(json['share']), + contactId: serializer.fromJson(json['contactId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'shareId': serializer.toJson(shareId), + 'share': serializer.toJson(share), + 'contactId': serializer.toJson(contactId), + }; + } + + UserDiscoverySharesData copyWith({ + int? shareId, + i2.Uint8List? share, + Value contactId = const Value.absent(), + }) => UserDiscoverySharesData( + shareId: shareId ?? this.shareId, + share: share ?? this.share, + contactId: contactId.present ? contactId.value : this.contactId, + ); + UserDiscoverySharesData copyWithCompanion(UserDiscoverySharesCompanion data) { + return UserDiscoverySharesData( + shareId: data.shareId.present ? data.shareId.value : this.shareId, + share: data.share.present ? data.share.value : this.share, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoverySharesData(') + ..write('shareId: $shareId, ') + ..write('share: $share, ') + ..write('contactId: $contactId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(shareId, $driftBlobEquality.hash(share), contactId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoverySharesData && + other.shareId == this.shareId && + $driftBlobEquality.equals(other.share, this.share) && + other.contactId == this.contactId); +} + +class UserDiscoverySharesCompanion + extends UpdateCompanion { + final Value shareId; + final Value share; + final Value contactId; + const UserDiscoverySharesCompanion({ + this.shareId = const Value.absent(), + this.share = const Value.absent(), + this.contactId = const Value.absent(), + }); + UserDiscoverySharesCompanion.insert({ + this.shareId = const Value.absent(), + required i2.Uint8List share, + this.contactId = const Value.absent(), + }) : share = Value(share); + static Insertable custom({ + Expression? shareId, + Expression? share, + Expression? contactId, + }) { + return RawValuesInsertable({ + if (shareId != null) 'share_id': shareId, + if (share != null) 'share': share, + if (contactId != null) 'contact_id': contactId, + }); + } + + UserDiscoverySharesCompanion copyWith({ + Value? shareId, + Value? share, + Value? contactId, + }) { + return UserDiscoverySharesCompanion( + shareId: shareId ?? this.shareId, + share: share ?? this.share, + contactId: contactId ?? this.contactId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (shareId.present) { + map['share_id'] = Variable(shareId.value); + } + if (share.present) { + map['share'] = Variable(share.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoverySharesCompanion(') + ..write('shareId: $shareId, ') + ..write('share: $share, ') + ..write('contactId: $contactId') + ..write(')')) + .toString(); + } +} + +class DatabaseAtV12 extends GeneratedDatabase { + DatabaseAtV12(QueryExecutor e) : super(e); + late final Contacts contacts = Contacts(this); + late final Groups groups = Groups(this); + late final MediaFiles mediaFiles = MediaFiles(this); + late final Messages messages = Messages(this); + late final MessageHistories messageHistories = MessageHistories(this); + late final Reactions reactions = Reactions(this); + late final GroupMembers groupMembers = GroupMembers(this); + late final Receipts receipts = Receipts(this); + late final ReceivedReceipts receivedReceipts = ReceivedReceipts(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 MessageActions messageActions = MessageActions(this); + late final GroupHistories groupHistories = GroupHistories(this); + late final KeyVerifications keyVerifications = KeyVerifications(this); + late final VerificationTokens verificationTokens = VerificationTokens(this); + late final UserDiscoveryAnnouncedUsers userDiscoveryAnnouncedUsers = + UserDiscoveryAnnouncedUsers(this); + late final UserDiscoveryUserRelations userDiscoveryUserRelations = + UserDiscoveryUserRelations(this); + late final UserDiscoveryOtherPromotions userDiscoveryOtherPromotions = + UserDiscoveryOtherPromotions(this); + late final UserDiscoveryOwnPromotions userDiscoveryOwnPromotions = + UserDiscoveryOwnPromotions(this); + late final UserDiscoveryShares userDiscoveryShares = UserDiscoveryShares( + this, + ); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + contacts, + groups, + mediaFiles, + messages, + messageHistories, + reactions, + groupMembers, + receipts, + receivedReceipts, + signalIdentityKeyStores, + signalPreKeyStores, + signalSenderKeyStores, + signalSessionStores, + messageActions, + groupHistories, + keyVerifications, + verificationTokens, + userDiscoveryAnnouncedUsers, + userDiscoveryUserRelations, + userDiscoveryOtherPromotions, + userDiscoveryOwnPromotions, + userDiscoveryShares, + ]; + @override + StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules([ + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('messages', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'media_files', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('messages', kind: UpdateKind.update)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('reactions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('reactions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_members', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('receipts', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('receipts', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_actions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_actions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('key_verifications', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'user_discovery_announced_users', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_user_relations', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_user_relations', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_other_promotions', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_own_promotions', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('user_discovery_shares', kind: UpdateKind.delete)], + ), + ]); + @override + int get schemaVersion => 12; +} diff --git a/test/rust/create_db_for_rust_testing.dart b/test/rust/create_db_for_rust_testing.dart index a9c308f6..948d04b8 100644 --- a/test/rust/create_db_for_rust_testing.dart +++ b/test/rust/create_db_for_rust_testing.dart @@ -11,7 +11,7 @@ void main() { late File dbFile; setUp(() { - dbFile = File('rust/tests/testing.db'); + dbFile = File('rust/core/tests/testing.db'); if (dbFile.existsSync()) { dbFile.deleteSync(); } From fce85c58f9e4c0bb999d3ab8672ea770d91fa338 Mon Sep 17 00:00:00 2001 From: otsmr Date: Sat, 18 Apr 2026 01:59:46 +0200 Subject: [PATCH 07/86] concept for password less recovery --- .../src/passwordless_recovery/types.proto | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 rust/protocols/src/passwordless_recovery/types.proto diff --git a/rust/protocols/src/passwordless_recovery/types.proto b/rust/protocols/src/passwordless_recovery/types.proto new file mode 100644 index 00000000..7490553e --- /dev/null +++ b/rust/protocols/src/passwordless_recovery/types.proto @@ -0,0 +1,86 @@ +syntax = "proto3"; +package passwordless_recovery; + +// Recovery Process +// - Generating: TempID and a new assymetric key pair +// - Uploading to the server TempID + Push Tokens so the server can notify the user that someone helped him + + +// Send from the person who tries to recover their account. +// This can be done via a link, which will then be opend in the app of the contact. +// The contact than has to manualy select from which user he got the request. +// -> Using this phishing is harder, as the user has to manualy select the user to recovery +// -> The user who wants to recover his account does not need to remember her old username +message RecoveryRequest { + int64 temp_id = 1; + bytes public_key = 2; +} + +// Used as envelope for TrustedFriendShare and RecoveryData +message EncryptedEnvelope { + bytes encrypted_data = 1; + bytes iv = 2; + bytes mac = 3; +} + +// Send from the trusted friend to +// This is encrypted with the received public key. +message TrustedFriendShare { + + // This allows to display the user which user has send him his recovery data. + User trusted_friend = 1; + + // This allows to display the userdata, showing that he is recovering the correct person. + User share_user = 2; + + // The minimum threshold required to decrypte the shares. + int32 threshold = 3; + + // The actual share which will become: SecretSharedDate + bytes share = 4; + + message User { + int64 user_id = 1; + string display_name = 2; + bytes avatar = 3; + } +} + +// After received all shares this is decrypted by the user restoring its own +message SecretSharedDate { + + // No second factor was selected + optional RecoveryData recovery_data = 1; + + + // Server has + optional SecondFactorMail second_factor_mail = 2; + optional SecondFactorPin second_factor_pin = 3; + + // The recovery data in case a second factor was used + // The decryption key is loaded from the server either using the PIN or the MAIL + optional bytes recovery_data_encrypted = 4; + + + message SecondFactorPin { + // Required to try the PIN to get the share from the server. + // This prevents that someone else can lock the pin, as the server only + // allows 3 tries then after 1 day again 3 tries until the key is deleted. + bytes unlock_token = 1; + // This never is send to the server but used to hash the pin before sending it to the server. + // This prevents that the server every knows the shot 4-diget PIN. + bytes pin_seed = 2; + } + + message SecondFactorMail {} + +} + +// The data which is recovered at the end. +// The backup_master_key allows to recover the actual backup uploaded in the background to the server. +// In case the backup is not available any more the user can use its user_id and his private_key to requister as a new user. +message RecoveryData { + int64 user_id = 1; + bytes private_key = 2; + bytes backup_master_key = 3; +} From 4ffd367b236b50fa4ea11f9a8e5eadaea3246340 Mon Sep 17 00:00:00 2001 From: otsmr Date: Sat, 18 Apr 2026 13:34:11 +0200 Subject: [PATCH 08/86] add some options --- lib/core/bridge/user_discovery.dart | 25 ------------------------- lib/src/model/json/userdata.dart | 13 ++++++++----- lib/src/model/json/userdata.g.dart | 15 +++++++-------- lib/src/views/chats/chat_list.view.dart | 10 ---------- 4 files changed, 15 insertions(+), 48 deletions(-) delete mode 100644 lib/core/bridge/user_discovery.dart diff --git a/lib/core/bridge/user_discovery.dart b/lib/core/bridge/user_discovery.dart deleted file mode 100644 index 46bbebe6..00000000 --- a/lib/core/bridge/user_discovery.dart +++ /dev/null @@ -1,25 +0,0 @@ -// This file is automatically generated, so please do not edit it. -// @generated by `flutter_rust_bridge`@ 2.12.0. - -// ignore_for_file: invalid_use_of_internal_member, unused_import - -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; - -import '../frb_generated.dart'; - -// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `get_all_announced_users`, `get_announced_user_by_public_id`, `get_config`, `get_contact_version`, `get_other_promotions_by_public_id`, `get_own_promotions_after_version`, `get_share_for_contact`, `push_new_user_relation`, `push_own_promotion`, `set_contact_version`, `set_shares`, `store_other_promotion`, `update_config` - -class UserDiscoveryDatabaseStore { - const UserDiscoveryDatabaseStore(); - - static Future default_() => RustLib.instance.api - .crateBridgeUserDiscoveryUserDiscoveryDatabaseStoreDefault(); - - @override - int get hashCode => 0; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is UserDiscoveryDatabaseStore && runtimeType == other.runtimeType; -} diff --git a/lib/src/model/json/userdata.dart b/lib/src/model/json/userdata.dart index 21789624..04f52587 100644 --- a/lib/src/model/json/userdata.dart +++ b/lib/src/model/json/userdata.dart @@ -43,6 +43,9 @@ class UserData { DateTime? lastImageSend; int? todaysImageCounter; + String? lastPlanBallance; + String? additionalUserInvites; + // --- SETTINGS --- @JsonKey(defaultValue: ThemeMode.system) @@ -78,11 +81,6 @@ class UserData { @JsonKey(defaultValue: true) bool typingIndicators = true; - String? lastPlanBallance; - String? additionalUserInvites; - - List? tutorialDisplayed; - String? myBestFriendGroupId; DateTime? signalLastSignedPreKeyUpdated; @@ -93,6 +91,11 @@ class UserData { @JsonKey(defaultValue: false) bool screenLockEnabled = false; + // > User Discovery Configurations + + @JsonKey(defaultValue: false) + bool isUserDiscoveryEnabled = false; + // -- Custom DATA -- @JsonKey(defaultValue: 100_000) diff --git a/lib/src/model/json/userdata.g.dart b/lib/src/model/json/userdata.g.dart index 911b53f3..16e851ff 100644 --- a/lib/src/model/json/userdata.g.dart +++ b/lib/src/model/json/userdata.g.dart @@ -24,6 +24,8 @@ UserData _$UserDataFromJson(Map json) => ? null : DateTime.parse(json['lastImageSend'] as String) ..todaysImageCounter = (json['todaysImageCounter'] as num?)?.toInt() + ..lastPlanBallance = json['lastPlanBallance'] as String? + ..additionalUserInvites = json['additionalUserInvites'] as String? ..themeMode = $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode']) ?? ThemeMode.system @@ -51,11 +53,6 @@ UserData _$UserDataFromJson(Map json) => ..autoStoreAllSendUnlimitedMediaFiles = json['autoStoreAllSendUnlimitedMediaFiles'] as bool? ?? false ..typingIndicators = json['typingIndicators'] as bool? ?? true - ..lastPlanBallance = json['lastPlanBallance'] as String? - ..additionalUserInvites = json['additionalUserInvites'] as String? - ..tutorialDisplayed = (json['tutorialDisplayed'] as List?) - ?.map((e) => e as String) - .toList() ..myBestFriendGroupId = json['myBestFriendGroupId'] as String? ..signalLastSignedPreKeyUpdated = json['signalLastSignedPreKeyUpdated'] == null @@ -64,6 +61,8 @@ UserData _$UserDataFromJson(Map json) => ..allowErrorTrackingViaSentry = json['allowErrorTrackingViaSentry'] as bool? ?? false ..screenLockEnabled = json['screenLockEnabled'] as bool? ?? false + ..isUserDiscoveryEnabled = + json['isUserDiscoveryEnabled'] as bool? ?? false ..currentPreKeyIndexStart = (json['currentPreKeyIndexStart'] as num?)?.toInt() ?? 100000 ..currentSignedPreKeyIndexStart = @@ -106,6 +105,8 @@ Map _$UserDataToJson(UserData instance) => { 'subscriptionPlanIdStore': instance.subscriptionPlanIdStore, 'lastImageSend': instance.lastImageSend?.toIso8601String(), 'todaysImageCounter': instance.todaysImageCounter, + 'lastPlanBallance': instance.lastPlanBallance, + 'additionalUserInvites': instance.additionalUserInvites, 'themeMode': _$ThemeModeEnumMap[instance.themeMode]!, 'defaultShowTime': instance.defaultShowTime, 'requestedAudioPermission': instance.requestedAudioPermission, @@ -119,14 +120,12 @@ Map _$UserDataToJson(UserData instance) => { 'autoStoreAllSendUnlimitedMediaFiles': instance.autoStoreAllSendUnlimitedMediaFiles, 'typingIndicators': instance.typingIndicators, - 'lastPlanBallance': instance.lastPlanBallance, - 'additionalUserInvites': instance.additionalUserInvites, - 'tutorialDisplayed': instance.tutorialDisplayed, 'myBestFriendGroupId': instance.myBestFriendGroupId, 'signalLastSignedPreKeyUpdated': instance.signalLastSignedPreKeyUpdated ?.toIso8601String(), 'allowErrorTrackingViaSentry': instance.allowErrorTrackingViaSentry, 'screenLockEnabled': instance.screenLockEnabled, + 'isUserDiscoveryEnabled': instance.isUserDiscoveryEnabled, 'currentPreKeyIndexStart': instance.currentPreKeyIndexStart, 'currentSignedPreKeyIndexStart': instance.currentSignedPreKeyIndexStart, 'lastChangeLogHash': instance.lastChangeLogHash, diff --git a/lib/src/views/chats/chat_list.view.dart b/lib/src/views/chats/chat_list.view.dart index 1f2a89a8..9776910a 100644 --- a/lib/src/views/chats/chat_list.view.dart +++ b/lib/src/views/chats/chat_list.view.dart @@ -52,17 +52,7 @@ class _ChatListViewState extends State { }); }); - // In case the user is already a Tester, ask him for permission. - WidgetsBinding.instance.addPostFrameCallback((_) async { - if (gUser.subscriptionPlan == SubscriptionPlan.Tester.name && - !gUser.askedForUserStudyPermission) { - await context.push( - Routes.settingsHelpUserStudy, - extra: true, - ); - } - final changeLog = await rootBundle.loadString('CHANGELOG.md'); final changeLogHash = (await compute( Sha256().hash, From 6516c4564c82fd2b08dcc05f380b6b5c84510173 Mon Sep 17 00:00:00 2001 From: otsmr Date: Sat, 18 Apr 2026 13:54:45 +0200 Subject: [PATCH 09/86] move files --- .gitignore | 1 + flutter_rust_bridge.yaml | 2 +- lib/core/frb_generated.dart | 2 +- pubspec.lock | 2 +- pubspec.yaml | 6 ++-- rust/.gitignore | 4 ++- rust/Cargo.lock | 31 +++++++++------- rust/core/.gitignore | 3 -- rust/core/Cargo.toml | 33 ------------------ rust/{core => }/src/bridge/error.rs | 0 rust/{core => }/src/bridge/log/mod.rs | 0 rust/{core => }/src/bridge/mod.rs | 0 .../src/bridge/user_discovery_utils.rs | 0 rust/{core => }/src/database/contact.rs | 0 rust/{core => }/src/database/mod.rs | 0 rust/{core => }/src/frb_generated.rs | 0 rust/{core => }/src/lib.rs | 0 rust/{core => }/src/user_discovery_store.rs | 0 rust/{core => }/src/utils.rs | 0 rust/{core => }/tests/testing.db | Bin .../traits.rs => rust_dependencies/.gitignore | 0 rust_dependencies/Cargo.toml | 3 ++ .../protocols/Cargo.toml | 0 .../protocols/build.rs | 0 .../protocols/src/key_verification/error.rs | 0 .../protocols/src/key_verification/mod.rs | 0 .../stores/in_memory_store.rs | 0 .../src/key_verification/stores/mod.rs | 0 .../protocols/src/key_verification/traits.rs | 0 .../src/key_verification/types.proto | 0 .../protocols/src/lib.rs | 0 .../src/passwordless_recovery/mod.rs | 0 .../src/passwordless_recovery/traits.rs | 0 .../src/passwordless_recovery/types.proto | 0 .../protocols/src/user_discovery.rs | 0 .../protocols/src/user_discovery/README.md | 0 .../protocols/src/user_discovery/error.rs | 0 .../user_discovery/stores/in_memory_store.rs | 0 .../src/user_discovery/stores/mod.rs | 0 .../protocols/src/user_discovery/tests.rs | 0 .../protocols/src/user_discovery/traits.rs | 0 .../protocols/src/user_discovery/types.proto | 0 test/rust/create_db_for_rust_testing.dart | 2 +- 43 files changed, 33 insertions(+), 56 deletions(-) delete mode 100644 rust/core/.gitignore delete mode 100644 rust/core/Cargo.toml rename rust/{core => }/src/bridge/error.rs (100%) rename rust/{core => }/src/bridge/log/mod.rs (100%) rename rust/{core => }/src/bridge/mod.rs (100%) rename rust/{core => }/src/bridge/user_discovery_utils.rs (100%) rename rust/{core => }/src/database/contact.rs (100%) rename rust/{core => }/src/database/mod.rs (100%) rename rust/{core => }/src/frb_generated.rs (100%) rename rust/{core => }/src/lib.rs (100%) rename rust/{core => }/src/user_discovery_store.rs (100%) rename rust/{core => }/src/utils.rs (100%) rename rust/{core => }/tests/testing.db (100%) rename rust/protocols/src/passwordless_recovery/traits.rs => rust_dependencies/.gitignore (100%) create mode 100644 rust_dependencies/Cargo.toml rename {rust => rust_dependencies}/protocols/Cargo.toml (100%) rename {rust => rust_dependencies}/protocols/build.rs (100%) rename {rust => rust_dependencies}/protocols/src/key_verification/error.rs (100%) rename {rust => rust_dependencies}/protocols/src/key_verification/mod.rs (100%) rename {rust => rust_dependencies}/protocols/src/key_verification/stores/in_memory_store.rs (100%) rename {rust => rust_dependencies}/protocols/src/key_verification/stores/mod.rs (100%) rename {rust => rust_dependencies}/protocols/src/key_verification/traits.rs (100%) rename {rust => rust_dependencies}/protocols/src/key_verification/types.proto (100%) rename {rust => rust_dependencies}/protocols/src/lib.rs (100%) rename {rust => rust_dependencies}/protocols/src/passwordless_recovery/mod.rs (100%) create mode 100644 rust_dependencies/protocols/src/passwordless_recovery/traits.rs rename {rust => rust_dependencies}/protocols/src/passwordless_recovery/types.proto (100%) rename {rust => rust_dependencies}/protocols/src/user_discovery.rs (100%) rename {rust => rust_dependencies}/protocols/src/user_discovery/README.md (100%) rename {rust => rust_dependencies}/protocols/src/user_discovery/error.rs (100%) rename {rust => rust_dependencies}/protocols/src/user_discovery/stores/in_memory_store.rs (100%) rename {rust => rust_dependencies}/protocols/src/user_discovery/stores/mod.rs (100%) rename {rust => rust_dependencies}/protocols/src/user_discovery/tests.rs (100%) rename {rust => rust_dependencies}/protocols/src/user_discovery/traits.rs (100%) rename {rust => rust_dependencies}/protocols/src/user_discovery/types.proto (100%) diff --git a/.gitignore b/.gitignore index 0ed545b6..22e61b6f 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ app.*.map.json /android/app/.cxx/ android/.kotlin/ devtools_options.yaml +rust/target \ No newline at end of file diff --git a/flutter_rust_bridge.yaml b/flutter_rust_bridge.yaml index 17b5a8f7..30bd38a7 100644 --- a/flutter_rust_bridge.yaml +++ b/flutter_rust_bridge.yaml @@ -1,3 +1,3 @@ rust_input: crate::bridge -rust_root: rust/core +rust_root: rust dart_output: lib/core \ No newline at end of file diff --git a/lib/core/frb_generated.dart b/lib/core/frb_generated.dart index 8e9bdf11..c49fc9c7 100644 --- a/lib/core/frb_generated.dart +++ b/lib/core/frb_generated.dart @@ -75,7 +75,7 @@ class RustLib extends BaseEntrypoint { static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig( stem: 'rust_lib_twonly', - ioDirectory: 'rust/core/target/release/', + ioDirectory: 'rust/target/release/', webPrefix: 'pkg/', ); } diff --git a/pubspec.lock b/pubspec.lock index 4af8361e..e4208c58 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1810,7 +1810,7 @@ packages: source: hosted version: "2.4.0" sqlite3: - dependency: transitive + dependency: "direct main" description: name: sqlite3 sha256: "3145bd74dcdb4fd6f5c6dda4d4e4490a8087d7f286a14dee5d37087290f0f8a2" diff --git a/pubspec.yaml b/pubspec.yaml index 045e440a..2d2d621a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,12 +58,13 @@ dependencies: json_annotation: ^4.9.0 # google.dev protobuf: ^4.0.0 # google.dev scrollable_positioned_list: ^0.3.8 # google.dev + drift: ^2.25.1 + drift_flutter: ^0.2.4 + sqlite3: ^2.9.4 # Flutter Favorite provider: ^6.1.2 - drift: ^2.25.1 - drift_flutter: ^0.2.4 flutter_local_notifications: ^19.1.0 sentry_flutter: ^9.14.0 @@ -112,6 +113,7 @@ dependencies: path: rust_builder flutter_rust_bridge: 2.12.0 + dependency_overrides: dots_indicator: path: ./dependencies/dots_indicator diff --git a/rust/.gitignore b/rust/.gitignore index c41cc9e3..dfb400ce 100644 --- a/rust/.gitignore +++ b/rust/.gitignore @@ -1 +1,3 @@ -/target \ No newline at end of file +/target + +tests/tmp_testing.db* \ No newline at end of file diff --git a/rust/Cargo.lock b/rust/Cargo.lock index c792ed14..5823bc53 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -139,7 +139,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5106bf2680d585dc5f29711b8aa5dde353180b8e14af89b7f0424f760c84e7ce" dependencies = [ "hashbrown 0.15.5", - "rand 0.8.5", + "rand 0.8.6", "zeroize", ] @@ -1160,7 +1160,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "smallvec", "zeroize", ] @@ -1436,7 +1436,6 @@ dependencies = [ "base64", "blahaj", "hmac 0.13.0", - "pretty_env_logger", "prost", "prost-build", "rand 0.10.1", @@ -1466,9 +1465,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha", @@ -1912,7 +1911,7 @@ dependencies = [ "md-5", "memchr", "percent-encoding", - "rand 0.8.5", + "rand 0.8.6", "rsa", "serde", "sha1", @@ -1950,7 +1949,7 @@ dependencies = [ "log", "md-5", "memchr", - "rand 0.8.5", + "rand 0.8.6", "serde", "serde_json", "sha2 0.10.9", @@ -2110,9 +2109,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.52.0" +version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91135f59b1cbf38c91e73cf3386fca9bb77915c45ce2771460c9d92f0f3d776" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ "bytes", "libc", @@ -2256,11 +2255,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.57.1", ] [[package]] @@ -2269,7 +2268,7 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.51.0", ] [[package]] @@ -2546,6 +2545,12 @@ dependencies = [ "wit-bindgen-rust-macro", ] +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "wit-bindgen-core" version = "0.51.0" diff --git a/rust/core/.gitignore b/rust/core/.gitignore deleted file mode 100644 index dfb400ce..00000000 --- a/rust/core/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target - -tests/tmp_testing.db* \ No newline at end of file diff --git a/rust/core/Cargo.toml b/rust/core/Cargo.toml deleted file mode 100644 index 25875329..00000000 --- a/rust/core/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "rust_lib_twonly" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib", "staticlib"] - -[dependencies] -flutter_rust_bridge = "=2.12.0" -thiserror = "2.0.18" -sqlx = { version = "0.9.0-alpha.1", default-features = false, features = [ - "runtime-tokio", - "sqlite", - "migrate", - "macros", - "chrono", - "derive", - "json", -] } -tokio = { version = "1.44", features = ["full"] } -tracing = "0.1.44" -rand = "0.10.1" -protocols = { path = "../protocols" } -parking_lot = "0.12.5" - -[dev-dependencies] -pretty_env_logger = "0.5.0" -tempfile = "3.27.0" - - -[build-dependencies] -prost-build = "0.14.1" diff --git a/rust/core/src/bridge/error.rs b/rust/src/bridge/error.rs similarity index 100% rename from rust/core/src/bridge/error.rs rename to rust/src/bridge/error.rs diff --git a/rust/core/src/bridge/log/mod.rs b/rust/src/bridge/log/mod.rs similarity index 100% rename from rust/core/src/bridge/log/mod.rs rename to rust/src/bridge/log/mod.rs diff --git a/rust/core/src/bridge/mod.rs b/rust/src/bridge/mod.rs similarity index 100% rename from rust/core/src/bridge/mod.rs rename to rust/src/bridge/mod.rs diff --git a/rust/core/src/bridge/user_discovery_utils.rs b/rust/src/bridge/user_discovery_utils.rs similarity index 100% rename from rust/core/src/bridge/user_discovery_utils.rs rename to rust/src/bridge/user_discovery_utils.rs diff --git a/rust/core/src/database/contact.rs b/rust/src/database/contact.rs similarity index 100% rename from rust/core/src/database/contact.rs rename to rust/src/database/contact.rs diff --git a/rust/core/src/database/mod.rs b/rust/src/database/mod.rs similarity index 100% rename from rust/core/src/database/mod.rs rename to rust/src/database/mod.rs diff --git a/rust/core/src/frb_generated.rs b/rust/src/frb_generated.rs similarity index 100% rename from rust/core/src/frb_generated.rs rename to rust/src/frb_generated.rs diff --git a/rust/core/src/lib.rs b/rust/src/lib.rs similarity index 100% rename from rust/core/src/lib.rs rename to rust/src/lib.rs diff --git a/rust/core/src/user_discovery_store.rs b/rust/src/user_discovery_store.rs similarity index 100% rename from rust/core/src/user_discovery_store.rs rename to rust/src/user_discovery_store.rs diff --git a/rust/core/src/utils.rs b/rust/src/utils.rs similarity index 100% rename from rust/core/src/utils.rs rename to rust/src/utils.rs diff --git a/rust/core/tests/testing.db b/rust/tests/testing.db similarity index 100% rename from rust/core/tests/testing.db rename to rust/tests/testing.db diff --git a/rust/protocols/src/passwordless_recovery/traits.rs b/rust_dependencies/.gitignore similarity index 100% rename from rust/protocols/src/passwordless_recovery/traits.rs rename to rust_dependencies/.gitignore diff --git a/rust_dependencies/Cargo.toml b/rust_dependencies/Cargo.toml new file mode 100644 index 00000000..1f2f14b9 --- /dev/null +++ b/rust_dependencies/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +members = ["protocols"] +resolver = "3" diff --git a/rust/protocols/Cargo.toml b/rust_dependencies/protocols/Cargo.toml similarity index 100% rename from rust/protocols/Cargo.toml rename to rust_dependencies/protocols/Cargo.toml diff --git a/rust/protocols/build.rs b/rust_dependencies/protocols/build.rs similarity index 100% rename from rust/protocols/build.rs rename to rust_dependencies/protocols/build.rs diff --git a/rust/protocols/src/key_verification/error.rs b/rust_dependencies/protocols/src/key_verification/error.rs similarity index 100% rename from rust/protocols/src/key_verification/error.rs rename to rust_dependencies/protocols/src/key_verification/error.rs diff --git a/rust/protocols/src/key_verification/mod.rs b/rust_dependencies/protocols/src/key_verification/mod.rs similarity index 100% rename from rust/protocols/src/key_verification/mod.rs rename to rust_dependencies/protocols/src/key_verification/mod.rs diff --git a/rust/protocols/src/key_verification/stores/in_memory_store.rs b/rust_dependencies/protocols/src/key_verification/stores/in_memory_store.rs similarity index 100% rename from rust/protocols/src/key_verification/stores/in_memory_store.rs rename to rust_dependencies/protocols/src/key_verification/stores/in_memory_store.rs diff --git a/rust/protocols/src/key_verification/stores/mod.rs b/rust_dependencies/protocols/src/key_verification/stores/mod.rs similarity index 100% rename from rust/protocols/src/key_verification/stores/mod.rs rename to rust_dependencies/protocols/src/key_verification/stores/mod.rs diff --git a/rust/protocols/src/key_verification/traits.rs b/rust_dependencies/protocols/src/key_verification/traits.rs similarity index 100% rename from rust/protocols/src/key_verification/traits.rs rename to rust_dependencies/protocols/src/key_verification/traits.rs diff --git a/rust/protocols/src/key_verification/types.proto b/rust_dependencies/protocols/src/key_verification/types.proto similarity index 100% rename from rust/protocols/src/key_verification/types.proto rename to rust_dependencies/protocols/src/key_verification/types.proto diff --git a/rust/protocols/src/lib.rs b/rust_dependencies/protocols/src/lib.rs similarity index 100% rename from rust/protocols/src/lib.rs rename to rust_dependencies/protocols/src/lib.rs diff --git a/rust/protocols/src/passwordless_recovery/mod.rs b/rust_dependencies/protocols/src/passwordless_recovery/mod.rs similarity index 100% rename from rust/protocols/src/passwordless_recovery/mod.rs rename to rust_dependencies/protocols/src/passwordless_recovery/mod.rs diff --git a/rust_dependencies/protocols/src/passwordless_recovery/traits.rs b/rust_dependencies/protocols/src/passwordless_recovery/traits.rs new file mode 100644 index 00000000..e69de29b diff --git a/rust/protocols/src/passwordless_recovery/types.proto b/rust_dependencies/protocols/src/passwordless_recovery/types.proto similarity index 100% rename from rust/protocols/src/passwordless_recovery/types.proto rename to rust_dependencies/protocols/src/passwordless_recovery/types.proto diff --git a/rust/protocols/src/user_discovery.rs b/rust_dependencies/protocols/src/user_discovery.rs similarity index 100% rename from rust/protocols/src/user_discovery.rs rename to rust_dependencies/protocols/src/user_discovery.rs diff --git a/rust/protocols/src/user_discovery/README.md b/rust_dependencies/protocols/src/user_discovery/README.md similarity index 100% rename from rust/protocols/src/user_discovery/README.md rename to rust_dependencies/protocols/src/user_discovery/README.md diff --git a/rust/protocols/src/user_discovery/error.rs b/rust_dependencies/protocols/src/user_discovery/error.rs similarity index 100% rename from rust/protocols/src/user_discovery/error.rs rename to rust_dependencies/protocols/src/user_discovery/error.rs diff --git a/rust/protocols/src/user_discovery/stores/in_memory_store.rs b/rust_dependencies/protocols/src/user_discovery/stores/in_memory_store.rs similarity index 100% rename from rust/protocols/src/user_discovery/stores/in_memory_store.rs rename to rust_dependencies/protocols/src/user_discovery/stores/in_memory_store.rs diff --git a/rust/protocols/src/user_discovery/stores/mod.rs b/rust_dependencies/protocols/src/user_discovery/stores/mod.rs similarity index 100% rename from rust/protocols/src/user_discovery/stores/mod.rs rename to rust_dependencies/protocols/src/user_discovery/stores/mod.rs diff --git a/rust/protocols/src/user_discovery/tests.rs b/rust_dependencies/protocols/src/user_discovery/tests.rs similarity index 100% rename from rust/protocols/src/user_discovery/tests.rs rename to rust_dependencies/protocols/src/user_discovery/tests.rs diff --git a/rust/protocols/src/user_discovery/traits.rs b/rust_dependencies/protocols/src/user_discovery/traits.rs similarity index 100% rename from rust/protocols/src/user_discovery/traits.rs rename to rust_dependencies/protocols/src/user_discovery/traits.rs diff --git a/rust/protocols/src/user_discovery/types.proto b/rust_dependencies/protocols/src/user_discovery/types.proto similarity index 100% rename from rust/protocols/src/user_discovery/types.proto rename to rust_dependencies/protocols/src/user_discovery/types.proto diff --git a/test/rust/create_db_for_rust_testing.dart b/test/rust/create_db_for_rust_testing.dart index 948d04b8..a9c308f6 100644 --- a/test/rust/create_db_for_rust_testing.dart +++ b/test/rust/create_db_for_rust_testing.dart @@ -11,7 +11,7 @@ void main() { late File dbFile; setUp(() { - dbFile = File('rust/core/tests/testing.db'); + dbFile = File('rust/tests/testing.db'); if (dbFile.existsSync()) { dbFile.deleteSync(); } From e1956c980749e9a6025e206066a28f639572fe6d Mon Sep 17 00:00:00 2001 From: otsmr Date: Sun, 19 Apr 2026 17:13:05 +0200 Subject: [PATCH 10/86] initialization of user discovery works --- lib/core/bridge.dart | 34 +- lib/core/bridge/callbacks.dart | 58 + lib/core/bridge/wrapper/user_discovery.dart | 61 + lib/core/database/contact.dart | 28 - lib/core/frb_generated.dart | 1511 ++++++++++++++++- lib/core/frb_generated.io.dart | 333 +++- lib/core/frb_generated.web.dart | 333 +++- lib/main.dart | 9 +- lib/src/callbacks/callbacks.dart | 28 + lib/src/callbacks/logging.callbacks.dart | 32 + .../callbacks/user_discovery.callbacks.dart | 294 ++++ lib/src/constants/routes.keys.dart | 2 + lib/src/model/json/userdata.dart | 3 + lib/src/providers/routing.provider.dart | 9 +- lib/src/services/user_discovery.service.dart | 26 + lib/src/themes/light.dart | 24 +- lib/src/utils/misc.dart | 47 + lib/src/views/settings/privacy.view.dart | 7 + .../block_users.view.dart} | 8 +- .../settings/privacy/user_discovery.view.dart | 26 + .../user_discovery_disabled.component.dart | 93 + .../user_discovery_enabled.component.dart | 45 + pubspec.lock | 38 +- pubspec.yaml | 5 +- rust/Cargo.lock | 166 +- rust/Cargo.toml | 38 +- rust/src/bridge/callbacks.rs | 47 + rust/src/bridge/callbacks/log.rs | 28 + rust/src/bridge/callbacks/macros.rs | 57 + rust/src/bridge/callbacks/user_discovery.rs | 169 ++ rust/src/bridge/error.rs | 6 + rust/src/bridge/log.rs | 73 + rust/src/bridge/log/mod.rs | 44 - rust/src/bridge/mod.rs | 161 +- rust/src/bridge/user_discovery_utils.rs | 27 - rust/src/bridge/wrapper/mod.rs | 1 + rust/src/bridge/wrapper/user_discovery.rs | 61 + rust/src/database/contact.rs | 58 - rust/src/database/mod.rs | 11 +- rust/src/frb_generated.rs | 921 ++++++++-- rust/src/lib.rs | 2 +- rust/src/standalone/mod.rs | 9 + rust/src/user_discovery_store.rs | 349 ---- rust/src/utils.rs | 20 +- .../user_discovery/stores/in_memory_store.rs | 3 - .../protocols/src/user_discovery/tests.rs | 10 +- .../protocols/src/user_discovery/traits.rs | 4 +- 47 files changed, 4435 insertions(+), 884 deletions(-) create mode 100644 lib/core/bridge/callbacks.dart create mode 100644 lib/core/bridge/wrapper/user_discovery.dart delete mode 100644 lib/core/database/contact.dart create mode 100644 lib/src/callbacks/callbacks.dart create mode 100644 lib/src/callbacks/logging.callbacks.dart create mode 100644 lib/src/callbacks/user_discovery.callbacks.dart create mode 100644 lib/src/services/user_discovery.service.dart rename lib/src/views/settings/{privacy_view_block.view.dart => privacy/block_users.view.dart} (93%) create mode 100644 lib/src/views/settings/privacy/user_discovery.view.dart create mode 100644 lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart create mode 100644 lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart create mode 100644 rust/src/bridge/callbacks.rs create mode 100644 rust/src/bridge/callbacks/log.rs create mode 100644 rust/src/bridge/callbacks/macros.rs create mode 100644 rust/src/bridge/callbacks/user_discovery.rs create mode 100644 rust/src/bridge/log.rs delete mode 100644 rust/src/bridge/log/mod.rs delete mode 100644 rust/src/bridge/user_discovery_utils.rs create mode 100644 rust/src/bridge/wrapper/mod.rs create mode 100644 rust/src/bridge/wrapper/user_discovery.rs delete mode 100644 rust/src/database/contact.rs create mode 100644 rust/src/standalone/mod.rs delete mode 100644 rust/src/user_discovery_store.rs diff --git a/lib/core/bridge.dart b/lib/core/bridge.dart index 91657918..d7b6740a 100644 --- a/lib/core/bridge.dart +++ b/lib/core/bridge.dart @@ -5,20 +5,36 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; -import 'database/contact.dart'; import 'frb_generated.dart'; -// These functions are ignored because they are not marked as `pub`: `get_workspace` -// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `Twonly` +// These functions are ignored because they are not marked as `pub`: `get_twonly_flutter` +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `TwonlyFlutter` -Future initializeTwonly({required TwonlyConfig config}) => - RustLib.instance.api.crateBridgeInitializeTwonly(config: config); +Future initializeTwonlyFlutter({required TwonlyConfig config}) => + RustLib.instance.api.crateBridgeInitializeTwonlyFlutter(config: config); -Future> getAllContacts() => - RustLib.instance.api.crateBridgeGetAllContacts(); +class AnnouncedUser { + const AnnouncedUser({ + required this.userId, + required this.publicKey, + required this.publicId, + }); + final PlatformInt64 userId; + final Uint8List publicKey; + final PlatformInt64 publicId; -Future loadPromotions() => - RustLib.instance.api.crateBridgeLoadPromotions(); + @override + int get hashCode => userId.hashCode ^ publicKey.hashCode ^ publicId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is AnnouncedUser && + runtimeType == other.runtimeType && + userId == other.userId && + publicKey == other.publicKey && + publicId == other.publicId; +} class OtherPromotion { const OtherPromotion({ diff --git a/lib/core/bridge/callbacks.dart b/lib/core/bridge/callbacks.dart new file mode 100644 index 00000000..28859ca4 --- /dev/null +++ b/lib/core/bridge/callbacks.dart @@ -0,0 +1,58 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.12.0. + +// ignore_for_file: invalid_use_of_internal_member + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +import '../bridge.dart'; +import '../frb_generated.dart'; + +// These functions are ignored because they are not marked as `pub`: `get_callbacks` +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `FlutterCallbacks`, `Logging`, `UserDiscoveryCallbacks` + +Future initFlutterCallbacks({ + required FutureOr> Function() loggingGetStreamSink, + required FutureOr Function(Uint8List) userDiscoverySignData, + required FutureOr Function(Uint8List, Uint8List, Uint8List) + userDiscoveryVerifySignature, + required FutureOr Function(PlatformInt64, Uint8List) + userDiscoveryVerifyStoredPubkey, + required FutureOr Function(List) userDiscoverySetShares, + required FutureOr Function(PlatformInt64) + userDiscoveryGetShareForContact, + required FutureOr Function(PlatformInt64, PlatformInt64, Uint8List) + userDiscoveryPushOwnPromotion, + required FutureOr?> Function(PlatformInt64) + userDiscoveryGetOwnPromotionsAfterVersion, + required FutureOr Function(OtherPromotion) + userDiscoveryStoreOtherPromotion, + required FutureOr?> Function(PlatformInt64) + userDiscoveryGetOtherPromotionsByPublicId, + required FutureOr Function(PlatformInt64) + userDiscoveryGetAnnouncedUserByPublicId, + required FutureOr Function(PlatformInt64) + userDiscoveryGetContactVersion, + required FutureOr Function(PlatformInt64, Uint8List) + userDiscoverySetContactVersion, + required FutureOr Function(PlatformInt64, AnnouncedUser, PlatformInt64?) + userDiscoveryPushNewUserRelation, +}) => RustLib.instance.api.crateBridgeCallbacksInitFlutterCallbacks( + loggingGetStreamSink: loggingGetStreamSink, + userDiscoverySignData: userDiscoverySignData, + userDiscoveryVerifySignature: userDiscoveryVerifySignature, + userDiscoveryVerifyStoredPubkey: userDiscoveryVerifyStoredPubkey, + userDiscoverySetShares: userDiscoverySetShares, + userDiscoveryGetShareForContact: userDiscoveryGetShareForContact, + userDiscoveryPushOwnPromotion: userDiscoveryPushOwnPromotion, + userDiscoveryGetOwnPromotionsAfterVersion: + userDiscoveryGetOwnPromotionsAfterVersion, + userDiscoveryStoreOtherPromotion: userDiscoveryStoreOtherPromotion, + userDiscoveryGetOtherPromotionsByPublicId: + userDiscoveryGetOtherPromotionsByPublicId, + userDiscoveryGetAnnouncedUserByPublicId: + userDiscoveryGetAnnouncedUserByPublicId, + userDiscoveryGetContactVersion: userDiscoveryGetContactVersion, + userDiscoverySetContactVersion: userDiscoverySetContactVersion, + userDiscoveryPushNewUserRelation: userDiscoveryPushNewUserRelation, +); diff --git a/lib/core/bridge/wrapper/user_discovery.dart b/lib/core/bridge/wrapper/user_discovery.dart new file mode 100644 index 00000000..b4d4edf3 --- /dev/null +++ b/lib/core/bridge/wrapper/user_discovery.dart @@ -0,0 +1,61 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.12.0. + +// ignore_for_file: invalid_use_of_internal_member + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +import '../../frb_generated.dart'; + +class FlutterUserDiscovery { + const FlutterUserDiscovery(); + + static Future getCurrentVersion() => RustLib.instance.api + .crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryGetCurrentVersion(); + + static Future> getNewMessages({ + required PlatformInt64 contactId, + required List receivedVersion, + }) => RustLib.instance.api + .crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryGetNewMessages( + contactId: contactId, + receivedVersion: receivedVersion, + ); + + static Future handleUserDiscoveryMessages({ + required PlatformInt64 contactId, + required List messages, + }) => RustLib.instance.api + .crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleUserDiscoveryMessages( + contactId: contactId, + messages: messages, + ); + + static Future initializeOrUpdate({ + required int threshold, + required PlatformInt64 userId, + required List publicKey, + }) => RustLib.instance.api + .crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryInitializeOrUpdate( + threshold: threshold, + userId: userId, + publicKey: publicKey, + ); + + static Future shouldRequestNewMessages({ + required PlatformInt64 contactId, + required List version, + }) => RustLib.instance.api + .crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryShouldRequestNewMessages( + contactId: contactId, + version: version, + ); + + @override + int get hashCode => 0; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FlutterUserDiscovery && runtimeType == other.runtimeType; +} diff --git a/lib/core/database/contact.dart b/lib/core/database/contact.dart deleted file mode 100644 index 42799c8d..00000000 --- a/lib/core/database/contact.dart +++ /dev/null @@ -1,28 +0,0 @@ -// This file is automatically generated, so please do not edit it. -// @generated by `flutter_rust_bridge`@ 2.12.0. - -// ignore_for_file: unused_import - -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; - -import '../frb_generated.dart'; - -class Contact { - const Contact({ - required this.userId, - required this.username, - }); - final PlatformInt64 userId; - final String username; - - @override - int get hashCode => userId.hashCode ^ username.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is Contact && - runtimeType == other.runtimeType && - userId == other.userId && - username == other.username; -} diff --git a/lib/core/frb_generated.dart b/lib/core/frb_generated.dart index c49fc9c7..a1248a9a 100644 --- a/lib/core/frb_generated.dart +++ b/lib/core/frb_generated.dart @@ -9,7 +9,8 @@ import 'dart:convert'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; import 'bridge.dart'; -import 'database/contact.dart'; +import 'bridge/callbacks.dart'; +import 'bridge/wrapper/user_discovery.dart'; import 'frb_generated.dart'; import 'frb_generated.io.dart' if (dart.library.js_interop) 'frb_generated.web.dart'; @@ -70,7 +71,7 @@ class RustLib extends BaseEntrypoint { String get codegenVersion => '2.12.0'; @override - int get rustContentHash => 776002844; + int get rustContentHash => 523281685; static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig( @@ -81,11 +82,69 @@ class RustLib extends BaseEntrypoint { } abstract class RustLibApi extends BaseApi { - Future> crateBridgeGetAllContacts(); + Future + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryGetCurrentVersion(); - Future crateBridgeInitializeTwonly({required TwonlyConfig config}); + Future> + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryGetNewMessages({ + required PlatformInt64 contactId, + required List receivedVersion, + }); - Future crateBridgeLoadPromotions(); + Future + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleUserDiscoveryMessages({ + required PlatformInt64 contactId, + required List messages, + }); + + Future + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryInitializeOrUpdate({ + required int threshold, + required PlatformInt64 userId, + required List publicKey, + }); + + Future + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryShouldRequestNewMessages({ + required PlatformInt64 contactId, + required List version, + }); + + Future crateBridgeCallbacksInitFlutterCallbacks({ + required FutureOr> Function() loggingGetStreamSink, + required FutureOr Function(Uint8List) userDiscoverySignData, + required FutureOr Function(Uint8List, Uint8List, Uint8List) + userDiscoveryVerifySignature, + required FutureOr Function(PlatformInt64, Uint8List) + userDiscoveryVerifyStoredPubkey, + required FutureOr Function(List) userDiscoverySetShares, + required FutureOr Function(PlatformInt64) + userDiscoveryGetShareForContact, + required FutureOr Function(PlatformInt64, PlatformInt64, Uint8List) + userDiscoveryPushOwnPromotion, + required FutureOr?> Function(PlatformInt64) + userDiscoveryGetOwnPromotionsAfterVersion, + required FutureOr Function(OtherPromotion) + userDiscoveryStoreOtherPromotion, + required FutureOr?> Function(PlatformInt64) + userDiscoveryGetOtherPromotionsByPublicId, + required FutureOr Function(PlatformInt64) + userDiscoveryGetAnnouncedUserByPublicId, + required FutureOr Function(PlatformInt64) + userDiscoveryGetContactVersion, + required FutureOr Function(PlatformInt64, Uint8List) + userDiscoverySetContactVersion, + required FutureOr Function( + PlatformInt64, + AnnouncedUser, + PlatformInt64?, + ) + userDiscoveryPushNewUserRelation, + }); + + Future crateBridgeInitializeTwonlyFlutter({ + required TwonlyConfig config, + }); } class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { @@ -97,7 +156,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { }); @override - Future> crateBridgeGetAllContacts() { + Future + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryGetCurrentVersion() { return handler.executeNormal( NormalTask( callFfi: (port_) { @@ -110,28 +170,36 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); }, codec: SseCodec( - decodeSuccessData: sse_decode_list_contact, + decodeSuccessData: sse_decode_list_prim_u_8_strict, decodeErrorData: sse_decode_AnyhowException, ), - constMeta: kCrateBridgeGetAllContactsConstMeta, + constMeta: + kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryGetCurrentVersionConstMeta, argValues: [], apiImpl: this, ), ); } - TaskConstMeta get kCrateBridgeGetAllContactsConstMeta => const TaskConstMeta( - debugName: 'get_all_contacts', - argNames: [], - ); + TaskConstMeta + get kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryGetCurrentVersionConstMeta => + const TaskConstMeta( + debugName: 'flutter_user_discovery_get_current_version', + argNames: [], + ); @override - Future crateBridgeInitializeTwonly({required TwonlyConfig config}) { + Future> + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryGetNewMessages({ + required PlatformInt64 contactId, + required List receivedVersion, + }) { return handler.executeNormal( NormalTask( callFfi: (port_) { final serializer = SseSerializer(generalizedFrbRustBinding); - sse_encode_box_autoadd_twonly_config(config, serializer); + sse_encode_i_64(contactId, serializer); + sse_encode_list_prim_u_8_loose(receivedVersion, serializer); pdeCallFfi( generalizedFrbRustBinding, serializer, @@ -140,28 +208,36 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); }, codec: SseCodec( - decodeSuccessData: sse_decode_unit, + decodeSuccessData: sse_decode_list_list_prim_u_8_strict, decodeErrorData: sse_decode_AnyhowException, ), - constMeta: kCrateBridgeInitializeTwonlyConstMeta, - argValues: [config], + constMeta: + kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryGetNewMessagesConstMeta, + argValues: [contactId, receivedVersion], apiImpl: this, ), ); } - TaskConstMeta get kCrateBridgeInitializeTwonlyConstMeta => + TaskConstMeta + get kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryGetNewMessagesConstMeta => const TaskConstMeta( - debugName: 'initialize_twonly', - argNames: ['config'], + debugName: 'flutter_user_discovery_get_new_messages', + argNames: ['contactId', 'receivedVersion'], ); @override - Future crateBridgeLoadPromotions() { + Future + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleUserDiscoveryMessages({ + required PlatformInt64 contactId, + required List messages, + }) { return handler.executeNormal( NormalTask( callFfi: (port_) { final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_i_64(contactId, serializer); + sse_encode_list_list_prim_u_8_strict(messages, serializer); pdeCallFfi( generalizedFrbRustBinding, serializer, @@ -170,20 +246,709 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); }, codec: SseCodec( - decodeSuccessData: sse_decode_other_promotion, - decodeErrorData: null, + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_AnyhowException, ), - constMeta: kCrateBridgeLoadPromotionsConstMeta, - argValues: [], + constMeta: + kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleUserDiscoveryMessagesConstMeta, + argValues: [contactId, messages], apiImpl: this, ), ); } - TaskConstMeta get kCrateBridgeLoadPromotionsConstMeta => const TaskConstMeta( - debugName: 'load_promotions', - argNames: [], - ); + TaskConstMeta + get kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleUserDiscoveryMessagesConstMeta => + const TaskConstMeta( + debugName: 'flutter_user_discovery_handle_user_discovery_messages', + argNames: ['contactId', 'messages'], + ); + + @override + Future + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryInitializeOrUpdate({ + required int threshold, + required PlatformInt64 userId, + required List publicKey, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_u_8(threshold, serializer); + sse_encode_i_64(userId, serializer); + sse_encode_list_prim_u_8_loose(publicKey, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 4, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_AnyhowException, + ), + constMeta: + kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryInitializeOrUpdateConstMeta, + argValues: [threshold, userId, publicKey], + apiImpl: this, + ), + ); + } + + TaskConstMeta + get kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryInitializeOrUpdateConstMeta => + const TaskConstMeta( + debugName: 'flutter_user_discovery_initialize_or_update', + argNames: ['threshold', 'userId', 'publicKey'], + ); + + @override + Future + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryShouldRequestNewMessages({ + required PlatformInt64 contactId, + required List version, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_i_64(contactId, serializer); + sse_encode_list_prim_u_8_loose(version, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 5, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_bool, + decodeErrorData: sse_decode_AnyhowException, + ), + constMeta: + kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryShouldRequestNewMessagesConstMeta, + argValues: [contactId, version], + apiImpl: this, + ), + ); + } + + TaskConstMeta + get kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryShouldRequestNewMessagesConstMeta => + const TaskConstMeta( + debugName: 'flutter_user_discovery_should_request_new_messages', + argNames: ['contactId', 'version'], + ); + + @override + Future crateBridgeCallbacksInitFlutterCallbacks({ + required FutureOr> Function() loggingGetStreamSink, + required FutureOr Function(Uint8List) userDiscoverySignData, + required FutureOr Function(Uint8List, Uint8List, Uint8List) + userDiscoveryVerifySignature, + required FutureOr Function(PlatformInt64, Uint8List) + userDiscoveryVerifyStoredPubkey, + required FutureOr Function(List) userDiscoverySetShares, + required FutureOr Function(PlatformInt64) + userDiscoveryGetShareForContact, + required FutureOr Function(PlatformInt64, PlatformInt64, Uint8List) + userDiscoveryPushOwnPromotion, + required FutureOr?> Function(PlatformInt64) + userDiscoveryGetOwnPromotionsAfterVersion, + required FutureOr Function(OtherPromotion) + userDiscoveryStoreOtherPromotion, + required FutureOr?> Function(PlatformInt64) + userDiscoveryGetOtherPromotionsByPublicId, + required FutureOr Function(PlatformInt64) + userDiscoveryGetAnnouncedUserByPublicId, + required FutureOr Function(PlatformInt64) + userDiscoveryGetContactVersion, + required FutureOr Function(PlatformInt64, Uint8List) + userDiscoverySetContactVersion, + required FutureOr Function( + PlatformInt64, + AnnouncedUser, + PlatformInt64?, + ) + userDiscoveryPushNewUserRelation, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException( + loggingGetStreamSink, + serializer, + ); + sse_encode_DartFn_Inputs_list_prim_u_8_strict_Output_opt_list_prim_u_8_strict_AnyhowException( + userDiscoverySignData, + serializer, + ); + sse_encode_DartFn_Inputs_list_prim_u_8_strict_list_prim_u_8_strict_list_prim_u_8_strict_Output_bool_AnyhowException( + userDiscoveryVerifySignature, + serializer, + ); + sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + userDiscoveryVerifyStoredPubkey, + serializer, + ); + sse_encode_DartFn_Inputs_list_list_prim_u_8_strict_Output_bool_AnyhowException( + userDiscoverySetShares, + serializer, + ); + sse_encode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException( + userDiscoveryGetShareForContact, + serializer, + ); + sse_encode_DartFn_Inputs_i_64_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + userDiscoveryPushOwnPromotion, + serializer, + ); + sse_encode_DartFn_Inputs_i_64_Output_opt_list_list_prim_u_8_strict_AnyhowException( + userDiscoveryGetOwnPromotionsAfterVersion, + serializer, + ); + sse_encode_DartFn_Inputs_other_promotion_Output_bool_AnyhowException( + userDiscoveryStoreOtherPromotion, + serializer, + ); + sse_encode_DartFn_Inputs_i_64_Output_opt_list_other_promotion_AnyhowException( + userDiscoveryGetOtherPromotionsByPublicId, + serializer, + ); + sse_encode_DartFn_Inputs_i_64_Output_opt_box_autoadd_announced_user_AnyhowException( + userDiscoveryGetAnnouncedUserByPublicId, + serializer, + ); + sse_encode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException( + userDiscoveryGetContactVersion, + serializer, + ); + sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + userDiscoverySetContactVersion, + serializer, + ); + sse_encode_DartFn_Inputs_i_64_announced_user_opt_box_autoadd_i_64_Output_bool_AnyhowException( + userDiscoveryPushNewUserRelation, + serializer, + ); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 6, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: null, + ), + constMeta: kCrateBridgeCallbacksInitFlutterCallbacksConstMeta, + argValues: [ + loggingGetStreamSink, + userDiscoverySignData, + userDiscoveryVerifySignature, + userDiscoveryVerifyStoredPubkey, + userDiscoverySetShares, + userDiscoveryGetShareForContact, + userDiscoveryPushOwnPromotion, + userDiscoveryGetOwnPromotionsAfterVersion, + userDiscoveryStoreOtherPromotion, + userDiscoveryGetOtherPromotionsByPublicId, + userDiscoveryGetAnnouncedUserByPublicId, + userDiscoveryGetContactVersion, + userDiscoverySetContactVersion, + userDiscoveryPushNewUserRelation, + ], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateBridgeCallbacksInitFlutterCallbacksConstMeta => + const TaskConstMeta( + debugName: 'init_flutter_callbacks', + argNames: [ + 'loggingGetStreamSink', + 'userDiscoverySignData', + 'userDiscoveryVerifySignature', + 'userDiscoveryVerifyStoredPubkey', + 'userDiscoverySetShares', + 'userDiscoveryGetShareForContact', + 'userDiscoveryPushOwnPromotion', + 'userDiscoveryGetOwnPromotionsAfterVersion', + 'userDiscoveryStoreOtherPromotion', + 'userDiscoveryGetOtherPromotionsByPublicId', + 'userDiscoveryGetAnnouncedUserByPublicId', + 'userDiscoveryGetContactVersion', + 'userDiscoverySetContactVersion', + 'userDiscoveryPushNewUserRelation', + ], + ); + + @override + Future crateBridgeInitializeTwonlyFlutter({ + required TwonlyConfig config, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_box_autoadd_twonly_config(config, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 7, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_AnyhowException, + ), + constMeta: kCrateBridgeInitializeTwonlyFlutterConstMeta, + argValues: [config], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateBridgeInitializeTwonlyFlutterConstMeta => + const TaskConstMeta( + debugName: 'initialize_twonly_flutter', + argNames: ['config'], + ); + + Future Function( + int, + ) + encode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException( + FutureOr> Function() raw, + ) { + return ( + callId, + ) async { + Box>? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw()); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_StreamSink_String_Sse(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } + + Future Function(int, dynamic) + encode_DartFn_Inputs_i_64_Output_opt_box_autoadd_announced_user_AnyhowException( + FutureOr Function(PlatformInt64) raw, + ) { + return (callId, rawArg0) async { + final arg0 = dco_decode_i_64(rawArg0); + + Box? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw(arg0)); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_opt_box_autoadd_announced_user(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } + + Future Function(int, dynamic) + encode_DartFn_Inputs_i_64_Output_opt_list_list_prim_u_8_strict_AnyhowException( + FutureOr?> Function(PlatformInt64) raw, + ) { + return (callId, rawArg0) async { + final arg0 = dco_decode_i_64(rawArg0); + + Box?>? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw(arg0)); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_opt_list_list_prim_u_8_strict(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } + + Future Function(int, dynamic) + encode_DartFn_Inputs_i_64_Output_opt_list_other_promotion_AnyhowException( + FutureOr?> Function(PlatformInt64) raw, + ) { + return (callId, rawArg0) async { + final arg0 = dco_decode_i_64(rawArg0); + + Box?>? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw(arg0)); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_opt_list_other_promotion(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } + + Future Function(int, dynamic) + encode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException( + FutureOr Function(PlatformInt64) raw, + ) { + return (callId, rawArg0) async { + final arg0 = dco_decode_i_64(rawArg0); + + Box? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw(arg0)); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_opt_list_prim_u_8_strict(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } + + Future Function(int, dynamic, dynamic, dynamic) + encode_DartFn_Inputs_i_64_announced_user_opt_box_autoadd_i_64_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, AnnouncedUser, PlatformInt64?) raw, + ) { + return (callId, rawArg0, rawArg1, rawArg2) async { + final arg0 = dco_decode_i_64(rawArg0); + final arg1 = dco_decode_announced_user(rawArg1); + final arg2 = dco_decode_opt_box_autoadd_i_64(rawArg2); + + Box? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw(arg0, arg1, arg2)); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_bool(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } + + Future Function(int, dynamic, dynamic, dynamic) + encode_DartFn_Inputs_i_64_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, PlatformInt64, Uint8List) raw, + ) { + return (callId, rawArg0, rawArg1, rawArg2) async { + final arg0 = dco_decode_i_64(rawArg0); + final arg1 = dco_decode_i_64(rawArg1); + final arg2 = dco_decode_list_prim_u_8_strict(rawArg2); + + Box? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw(arg0, arg1, arg2)); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_bool(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } + + Future Function(int, dynamic, dynamic) + encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, Uint8List) raw, + ) { + return (callId, rawArg0, rawArg1) async { + final arg0 = dco_decode_i_64(rawArg0); + final arg1 = dco_decode_list_prim_u_8_strict(rawArg1); + + Box? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw(arg0, arg1)); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_bool(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } + + Future Function(int, dynamic) + encode_DartFn_Inputs_list_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(List) raw, + ) { + return (callId, rawArg0) async { + final arg0 = dco_decode_list_list_prim_u_8_strict(rawArg0); + + Box? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw(arg0)); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_bool(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } + + Future Function(int, dynamic) + encode_DartFn_Inputs_list_prim_u_8_strict_Output_opt_list_prim_u_8_strict_AnyhowException( + FutureOr Function(Uint8List) raw, + ) { + return (callId, rawArg0) async { + final arg0 = dco_decode_list_prim_u_8_strict(rawArg0); + + Box? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw(arg0)); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_opt_list_prim_u_8_strict(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } + + Future Function(int, dynamic, dynamic, dynamic) + encode_DartFn_Inputs_list_prim_u_8_strict_list_prim_u_8_strict_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(Uint8List, Uint8List, Uint8List) raw, + ) { + return (callId, rawArg0, rawArg1, rawArg2) async { + final arg0 = dco_decode_list_prim_u_8_strict(rawArg0); + final arg1 = dco_decode_list_prim_u_8_strict(rawArg1); + final arg2 = dco_decode_list_prim_u_8_strict(rawArg2); + + Box? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw(arg0, arg1, arg2)); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_bool(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } + + Future Function(int, dynamic) + encode_DartFn_Inputs_other_promotion_Output_bool_AnyhowException( + FutureOr Function(OtherPromotion) raw, + ) { + return (callId, rawArg0) async { + final arg0 = dco_decode_other_promotion(rawArg0); + + Box? rawOutput; + Box? rawError; + try { + rawOutput = Box(await raw(arg0)); + } catch (e, s) { + rawError = Box(AnyhowException('$e\n\n$s')); + } + + final serializer = SseSerializer(generalizedFrbRustBinding); + assert((rawOutput != null) ^ (rawError != null)); + if (rawOutput != null) { + serializer.buffer.putUint8(0); + sse_encode_bool(rawOutput.value, serializer); + } else { + serializer.buffer.putUint8(1); + sse_encode_AnyhowException(rawError!.value, serializer); + } + final output = serializer.intoRaw(); + + generalizedFrbRustBinding.dartFnDeliverOutput( + callId: callId, + ptr: output.ptr, + rustVecLen: output.rustVecLen, + dataLen: output.dataLen, + ); + }; + } @protected AnyhowException dco_decode_AnyhowException(dynamic raw) { @@ -191,12 +956,157 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return AnyhowException(raw as String); } + @protected + FutureOr> Function() + dco_decode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + FutureOr Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_box_autoadd_announced_user_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + FutureOr?> Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_list_list_prim_u_8_strict_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + FutureOr?> Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_list_other_promotion_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + FutureOr Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + FutureOr Function(PlatformInt64, AnnouncedUser, PlatformInt64?) + dco_decode_DartFn_Inputs_i_64_announced_user_opt_box_autoadd_i_64_Output_bool_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + FutureOr Function(PlatformInt64, PlatformInt64, Uint8List) + dco_decode_DartFn_Inputs_i_64_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + FutureOr Function(PlatformInt64, Uint8List) + dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + FutureOr Function(List) + dco_decode_DartFn_Inputs_list_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + FutureOr Function(Uint8List) + dco_decode_DartFn_Inputs_list_prim_u_8_strict_Output_opt_list_prim_u_8_strict_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + FutureOr Function(Uint8List, Uint8List, Uint8List) + dco_decode_DartFn_Inputs_list_prim_u_8_strict_list_prim_u_8_strict_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + FutureOr Function(OtherPromotion) + dco_decode_DartFn_Inputs_other_promotion_Output_bool_AnyhowException( + dynamic raw, + ) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(''); + } + + @protected + Object dco_decode_DartOpaque(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return decodeDartOpaque(raw, generalizedFrbRustBinding); + } + + @protected + RustStreamSink dco_decode_StreamSink_String_Sse(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + throw UnimplementedError(); + } + @protected String dco_decode_String(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs return raw as String; } + @protected + AnnouncedUser dco_decode_announced_user(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 3) + throw Exception('unexpected arr length: expect 3 but see ${arr.length}'); + return AnnouncedUser( + userId: dco_decode_i_64(arr[0]), + publicKey: dco_decode_list_prim_u_8_strict(arr[1]), + publicId: dco_decode_i_64(arr[2]), + ); + } + + @protected + bool dco_decode_bool(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as bool; + } + + @protected + AnnouncedUser dco_decode_box_autoadd_announced_user(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dco_decode_announced_user(raw); + } + @protected PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -210,15 +1120,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - Contact dco_decode_contact(dynamic raw) { + FlutterUserDiscovery dco_decode_flutter_user_discovery(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs final arr = raw as List; - if (arr.length != 2) - throw Exception('unexpected arr length: expect 2 but see ${arr.length}'); - return Contact( - userId: dco_decode_i_64(arr[0]), - username: dco_decode_String(arr[1]), - ); + if (arr.isNotEmpty) + throw Exception('unexpected arr length: expect 0 but see ${arr.length}'); + return const FlutterUserDiscovery(); } @protected @@ -228,9 +1135,27 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - List dco_decode_list_contact(dynamic raw) { + PlatformInt64 dco_decode_isize(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs - return (raw as List).map(dco_decode_contact).toList(); + return dcoDecodeI64(raw); + } + + @protected + List dco_decode_list_list_prim_u_8_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return (raw as List).map(dco_decode_list_prim_u_8_strict).toList(); + } + + @protected + List dco_decode_list_other_promotion(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return (raw as List).map(dco_decode_other_promotion).toList(); + } + + @protected + List dco_decode_list_prim_u_8_loose(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as List; } @protected @@ -239,12 +1164,36 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw as Uint8List; } + @protected + AnnouncedUser? dco_decode_opt_box_autoadd_announced_user(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw == null ? null : dco_decode_box_autoadd_announced_user(raw); + } + @protected PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs return raw == null ? null : dco_decode_box_autoadd_i_64(raw); } + @protected + List? dco_decode_opt_list_list_prim_u_8_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw == null ? null : dco_decode_list_list_prim_u_8_strict(raw); + } + + @protected + List? dco_decode_opt_list_other_promotion(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw == null ? null : dco_decode_list_other_promotion(raw); + } + + @protected + Uint8List? dco_decode_opt_list_prim_u_8_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw == null ? null : dco_decode_list_prim_u_8_strict(raw); + } + @protected OtherPromotion dco_decode_other_promotion(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -291,6 +1240,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return; } + @protected + BigInt dco_decode_usize(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dcoDecodeU64(raw); + } + @protected AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -298,6 +1253,21 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return AnyhowException(inner); } + @protected + Object sse_decode_DartOpaque(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final inner = sse_decode_isize(deserializer); + return decodeDartOpaque(inner, generalizedFrbRustBinding); + } + + @protected + RustStreamSink sse_decode_StreamSink_String_Sse( + SseDeserializer deserializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + throw UnimplementedError('Unreachable ()'); + } + @protected String sse_decode_String(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -305,6 +1275,33 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return utf8.decoder.convert(inner); } + @protected + AnnouncedUser sse_decode_announced_user(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final var_userId = sse_decode_i_64(deserializer); + final var_publicKey = sse_decode_list_prim_u_8_strict(deserializer); + final var_publicId = sse_decode_i_64(deserializer); + return AnnouncedUser( + userId: var_userId, + publicKey: var_publicKey, + publicId: var_publicId, + ); + } + + @protected + bool sse_decode_bool(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint8() != 0; + } + + @protected + AnnouncedUser sse_decode_box_autoadd_announced_user( + SseDeserializer deserializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + return sse_decode_announced_user(deserializer); + } + @protected PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -320,11 +1317,11 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - Contact sse_decode_contact(SseDeserializer deserializer) { + FlutterUserDiscovery sse_decode_flutter_user_discovery( + SseDeserializer deserializer, + ) { // Codec=Sse (Serialization based), see doc to use other codecs - final var_userId = sse_decode_i_64(deserializer); - final var_username = sse_decode_String(deserializer); - return Contact(userId: var_userId, username: var_username); + return const FlutterUserDiscovery(); } @protected @@ -334,17 +1331,46 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - List sse_decode_list_contact(SseDeserializer deserializer) { + PlatformInt64 sse_decode_isize(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getPlatformInt64(); + } + + @protected + List sse_decode_list_list_prim_u_8_strict( + SseDeserializer deserializer, + ) { // Codec=Sse (Serialization based), see doc to use other codecs final len_ = sse_decode_i_32(deserializer); - final ans_ = []; + final ans_ = []; for (var idx_ = 0; idx_ < len_; ++idx_) { - ans_.add(sse_decode_contact(deserializer)); + ans_.add(sse_decode_list_prim_u_8_strict(deserializer)); } return ans_; } + @protected + List sse_decode_list_other_promotion( + SseDeserializer deserializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + final len_ = sse_decode_i_32(deserializer); + final ans_ = []; + for (var idx_ = 0; idx_ < len_; ++idx_) { + ans_.add(sse_decode_other_promotion(deserializer)); + } + return ans_; + } + + @protected + List sse_decode_list_prim_u_8_loose(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final len_ = sse_decode_i_32(deserializer); + return deserializer.buffer.getUint8List(len_); + } + @protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -352,6 +1378,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return deserializer.buffer.getUint8List(len_); } + @protected + AnnouncedUser? sse_decode_opt_box_autoadd_announced_user( + SseDeserializer deserializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + if (sse_decode_bool(deserializer)) { + return sse_decode_box_autoadd_announced_user(deserializer); + } else { + return null; + } + } + @protected PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -363,6 +1402,43 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } + @protected + List? sse_decode_opt_list_list_prim_u_8_strict( + SseDeserializer deserializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + if (sse_decode_bool(deserializer)) { + return sse_decode_list_list_prim_u_8_strict(deserializer); + } else { + return null; + } + } + + @protected + List? sse_decode_opt_list_other_promotion( + SseDeserializer deserializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + if (sse_decode_bool(deserializer)) { + return sse_decode_list_other_promotion(deserializer); + } else { + return null; + } + } + + @protected + Uint8List? sse_decode_opt_list_prim_u_8_strict(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + if (sse_decode_bool(deserializer)) { + return sse_decode_list_prim_u_8_strict(deserializer); + } else { + return null; + } + } + @protected OtherPromotion sse_decode_other_promotion(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -413,15 +1489,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - int sse_decode_i_32(SseDeserializer deserializer) { + BigInt sse_decode_usize(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs - return deserializer.buffer.getInt32(); + return deserializer.buffer.getBigUint64(); } @protected - bool sse_decode_bool(SseDeserializer deserializer) { + int sse_decode_i_32(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs - return deserializer.buffer.getUint8() != 0; + return deserializer.buffer.getInt32(); } @protected @@ -433,12 +1509,241 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_String(self.message, serializer); } + @protected + void sse_encode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException( + FutureOr> Function() self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException(self), + serializer, + ); + } + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_box_autoadd_announced_user_AnyhowException( + FutureOr Function(PlatformInt64) self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs_i_64_Output_opt_box_autoadd_announced_user_AnyhowException( + self, + ), + serializer, + ); + } + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_list_list_prim_u_8_strict_AnyhowException( + FutureOr?> Function(PlatformInt64) self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs_i_64_Output_opt_list_list_prim_u_8_strict_AnyhowException( + self, + ), + serializer, + ); + } + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_list_other_promotion_AnyhowException( + FutureOr?> Function(PlatformInt64) self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs_i_64_Output_opt_list_other_promotion_AnyhowException( + self, + ), + serializer, + ); + } + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException( + FutureOr Function(PlatformInt64) self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException( + self, + ), + serializer, + ); + } + + @protected + void + sse_encode_DartFn_Inputs_i_64_announced_user_opt_box_autoadd_i_64_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, AnnouncedUser, PlatformInt64?) self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs_i_64_announced_user_opt_box_autoadd_i_64_Output_bool_AnyhowException( + self, + ), + serializer, + ); + } + + @protected + void + sse_encode_DartFn_Inputs_i_64_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, PlatformInt64, Uint8List) self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs_i_64_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + self, + ), + serializer, + ); + } + + @protected + void + sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, Uint8List) self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + self, + ), + serializer, + ); + } + + @protected + void + sse_encode_DartFn_Inputs_list_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(List) self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs_list_list_prim_u_8_strict_Output_bool_AnyhowException( + self, + ), + serializer, + ); + } + + @protected + void + sse_encode_DartFn_Inputs_list_prim_u_8_strict_Output_opt_list_prim_u_8_strict_AnyhowException( + FutureOr Function(Uint8List) self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs_list_prim_u_8_strict_Output_opt_list_prim_u_8_strict_AnyhowException( + self, + ), + serializer, + ); + } + + @protected + void + sse_encode_DartFn_Inputs_list_prim_u_8_strict_list_prim_u_8_strict_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(Uint8List, Uint8List, Uint8List) self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs_list_prim_u_8_strict_list_prim_u_8_strict_list_prim_u_8_strict_Output_bool_AnyhowException( + self, + ), + serializer, + ); + } + + @protected + void sse_encode_DartFn_Inputs_other_promotion_Output_bool_AnyhowException( + FutureOr Function(OtherPromotion) self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_DartOpaque( + encode_DartFn_Inputs_other_promotion_Output_bool_AnyhowException(self), + serializer, + ); + } + + @protected + void sse_encode_DartOpaque(Object self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_isize( + PlatformPointerUtil.ptrToPlatformInt64( + encodeDartOpaque( + self, + portManager.dartHandlerPort, + generalizedFrbRustBinding, + ), + ), + serializer, + ); + } + + @protected + void sse_encode_StreamSink_String_Sse( + RustStreamSink self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_String( + self.setupAndSerialize( + codec: SseCodec( + decodeSuccessData: sse_decode_String, + decodeErrorData: sse_decode_AnyhowException, + ), + ), + serializer, + ); + } + @protected void sse_encode_String(String self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer); } + @protected + void sse_encode_announced_user(AnnouncedUser self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_64(self.userId, serializer); + sse_encode_list_prim_u_8_strict(self.publicKey, serializer); + sse_encode_i_64(self.publicId, serializer); + } + + @protected + void sse_encode_bool(bool self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint8(self ? 1 : 0); + } + + @protected + void sse_encode_box_autoadd_announced_user( + AnnouncedUser self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_announced_user(self, serializer); + } + @protected void sse_encode_box_autoadd_i_64( PlatformInt64 self, @@ -458,10 +1763,11 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - void sse_encode_contact(Contact self, SseSerializer serializer) { + void sse_encode_flutter_user_discovery( + FlutterUserDiscovery self, + SseSerializer serializer, + ) { // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_i_64(self.userId, serializer); - sse_encode_String(self.username, serializer); } @protected @@ -471,14 +1777,47 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - void sse_encode_list_contact(List self, SseSerializer serializer) { + void sse_encode_isize(PlatformInt64 self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putPlatformInt64(self); + } + + @protected + void sse_encode_list_list_prim_u_8_strict( + List self, + SseSerializer serializer, + ) { // Codec=Sse (Serialization based), see doc to use other codecs sse_encode_i_32(self.length, serializer); for (final item in self) { - sse_encode_contact(item, serializer); + sse_encode_list_prim_u_8_strict(item, serializer); } } + @protected + void sse_encode_list_other_promotion( + List self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + for (final item in self) { + sse_encode_other_promotion(item, serializer); + } + } + + @protected + void sse_encode_list_prim_u_8_loose( + List self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + serializer.buffer.putUint8List( + self is Uint8List ? self : Uint8List.fromList(self), + ); + } + @protected void sse_encode_list_prim_u_8_strict( Uint8List self, @@ -489,6 +1828,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { serializer.buffer.putUint8List(self); } + @protected + void sse_encode_opt_box_autoadd_announced_user( + AnnouncedUser? self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + sse_encode_bool(self != null, serializer); + if (self != null) { + sse_encode_box_autoadd_announced_user(self, serializer); + } + } + @protected void sse_encode_opt_box_autoadd_i_64( PlatformInt64? self, @@ -502,6 +1854,45 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } + @protected + void sse_encode_opt_list_list_prim_u_8_strict( + List? self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + sse_encode_bool(self != null, serializer); + if (self != null) { + sse_encode_list_list_prim_u_8_strict(self, serializer); + } + } + + @protected + void sse_encode_opt_list_other_promotion( + List? self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + sse_encode_bool(self != null, serializer); + if (self != null) { + sse_encode_list_other_promotion(self, serializer); + } + } + + @protected + void sse_encode_opt_list_prim_u_8_strict( + Uint8List? self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + sse_encode_bool(self != null, serializer); + if (self != null) { + sse_encode_list_prim_u_8_strict(self, serializer); + } + } + @protected void sse_encode_other_promotion( OtherPromotion self, @@ -543,15 +1934,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { // Codec=Sse (Serialization based), see doc to use other codecs } + @protected + void sse_encode_usize(BigInt self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putBigUint64(self); + } + @protected void sse_encode_i_32(int self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs serializer.buffer.putInt32(self); } - - @protected - void sse_encode_bool(bool self, SseSerializer serializer) { - // Codec=Sse (Serialization based), see doc to use other codecs - serializer.buffer.putUint8(self ? 1 : 0); - } } diff --git a/lib/core/frb_generated.io.dart b/lib/core/frb_generated.io.dart index 2216764d..77c9a8a1 100644 --- a/lib/core/frb_generated.io.dart +++ b/lib/core/frb_generated.io.dart @@ -1,7 +1,7 @@ // This file is automatically generated, so please do not edit it. // @generated by `flutter_rust_bridge`@ 2.12.0. -// ignore_for_file: unused_import, non_constant_identifier_names, unused_field +// ignore_for_file: unused_import, unnecessary_import, non_constant_identifier_names, unused_field import 'dart:async'; import 'dart:convert'; @@ -10,7 +10,8 @@ import 'dart:ffi' as ffi; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart'; import 'bridge.dart'; -import 'database/contact.dart'; +import 'bridge/callbacks.dart'; +import 'bridge/wrapper/user_discovery.dart'; import 'frb_generated.dart'; abstract class RustLibApiImplPlatform extends BaseApiImpl { @@ -24,9 +25,96 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected AnyhowException dco_decode_AnyhowException(dynamic raw); + @protected + FutureOr> Function() + dco_decode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_box_autoadd_announced_user_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr?> Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_list_list_prim_u_8_strict_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr?> Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_list_other_promotion_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(PlatformInt64, AnnouncedUser, PlatformInt64?) + dco_decode_DartFn_Inputs_i_64_announced_user_opt_box_autoadd_i_64_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(PlatformInt64, PlatformInt64, Uint8List) + dco_decode_DartFn_Inputs_i_64_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(PlatformInt64, Uint8List) + dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(List) + dco_decode_DartFn_Inputs_list_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(Uint8List) + dco_decode_DartFn_Inputs_list_prim_u_8_strict_Output_opt_list_prim_u_8_strict_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(Uint8List, Uint8List, Uint8List) + dco_decode_DartFn_Inputs_list_prim_u_8_strict_list_prim_u_8_strict_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(OtherPromotion) + dco_decode_DartFn_Inputs_other_promotion_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + Object dco_decode_DartOpaque(dynamic raw); + + @protected + RustStreamSink dco_decode_StreamSink_String_Sse(dynamic raw); + @protected String dco_decode_String(dynamic raw); + @protected + AnnouncedUser dco_decode_announced_user(dynamic raw); + + @protected + bool dco_decode_bool(dynamic raw); + + @protected + AnnouncedUser dco_decode_box_autoadd_announced_user(dynamic raw); + @protected PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw); @@ -34,20 +122,41 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { TwonlyConfig dco_decode_box_autoadd_twonly_config(dynamic raw); @protected - Contact dco_decode_contact(dynamic raw); + FlutterUserDiscovery dco_decode_flutter_user_discovery(dynamic raw); @protected PlatformInt64 dco_decode_i_64(dynamic raw); @protected - List dco_decode_list_contact(dynamic raw); + PlatformInt64 dco_decode_isize(dynamic raw); + + @protected + List dco_decode_list_list_prim_u_8_strict(dynamic raw); + + @protected + List dco_decode_list_other_promotion(dynamic raw); + + @protected + List dco_decode_list_prim_u_8_loose(dynamic raw); @protected Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); + @protected + AnnouncedUser? dco_decode_opt_box_autoadd_announced_user(dynamic raw); + @protected PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw); + @protected + List? dco_decode_opt_list_list_prim_u_8_strict(dynamic raw); + + @protected + List? dco_decode_opt_list_other_promotion(dynamic raw); + + @protected + Uint8List? dco_decode_opt_list_prim_u_8_strict(dynamic raw); + @protected OtherPromotion dco_decode_other_promotion(dynamic raw); @@ -63,12 +172,34 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void dco_decode_unit(dynamic raw); + @protected + BigInt dco_decode_usize(dynamic raw); + @protected AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer); + @protected + Object sse_decode_DartOpaque(SseDeserializer deserializer); + + @protected + RustStreamSink sse_decode_StreamSink_String_Sse( + SseDeserializer deserializer, + ); + @protected String sse_decode_String(SseDeserializer deserializer); + @protected + AnnouncedUser sse_decode_announced_user(SseDeserializer deserializer); + + @protected + bool sse_decode_bool(SseDeserializer deserializer); + + @protected + AnnouncedUser sse_decode_box_autoadd_announced_user( + SseDeserializer deserializer, + ); + @protected PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer); @@ -78,20 +209,53 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { ); @protected - Contact sse_decode_contact(SseDeserializer deserializer); + FlutterUserDiscovery sse_decode_flutter_user_discovery( + SseDeserializer deserializer, + ); @protected PlatformInt64 sse_decode_i_64(SseDeserializer deserializer); @protected - List sse_decode_list_contact(SseDeserializer deserializer); + PlatformInt64 sse_decode_isize(SseDeserializer deserializer); + + @protected + List sse_decode_list_list_prim_u_8_strict( + SseDeserializer deserializer, + ); + + @protected + List sse_decode_list_other_promotion( + SseDeserializer deserializer, + ); + + @protected + List sse_decode_list_prim_u_8_loose(SseDeserializer deserializer); @protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); + @protected + AnnouncedUser? sse_decode_opt_box_autoadd_announced_user( + SseDeserializer deserializer, + ); + @protected PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer); + @protected + List? sse_decode_opt_list_list_prim_u_8_strict( + SseDeserializer deserializer, + ); + + @protected + List? sse_decode_opt_list_other_promotion( + SseDeserializer deserializer, + ); + + @protected + Uint8List? sse_decode_opt_list_prim_u_8_strict(SseDeserializer deserializer); + @protected OtherPromotion sse_decode_other_promotion(SseDeserializer deserializer); @@ -108,10 +272,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_decode_unit(SseDeserializer deserializer); @protected - int sse_decode_i_32(SseDeserializer deserializer); + BigInt sse_decode_usize(SseDeserializer deserializer); @protected - bool sse_decode_bool(SseDeserializer deserializer); + int sse_decode_i_32(SseDeserializer deserializer); @protected void sse_encode_AnyhowException( @@ -119,9 +283,112 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); + @protected + void sse_encode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException( + FutureOr> Function() self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_box_autoadd_announced_user_AnyhowException( + FutureOr Function(PlatformInt64) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_list_list_prim_u_8_strict_AnyhowException( + FutureOr?> Function(PlatformInt64) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_list_other_promotion_AnyhowException( + FutureOr?> Function(PlatformInt64) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException( + FutureOr Function(PlatformInt64) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_announced_user_opt_box_autoadd_i_64_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, AnnouncedUser, PlatformInt64?) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, PlatformInt64, Uint8List) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, Uint8List) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_list_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(List) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_list_prim_u_8_strict_Output_opt_list_prim_u_8_strict_AnyhowException( + FutureOr Function(Uint8List) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_list_prim_u_8_strict_list_prim_u_8_strict_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(Uint8List, Uint8List, Uint8List) self, + SseSerializer serializer, + ); + + @protected + void sse_encode_DartFn_Inputs_other_promotion_Output_bool_AnyhowException( + FutureOr Function(OtherPromotion) self, + SseSerializer serializer, + ); + + @protected + void sse_encode_DartOpaque(Object self, SseSerializer serializer); + + @protected + void sse_encode_StreamSink_String_Sse( + RustStreamSink self, + SseSerializer serializer, + ); + @protected void sse_encode_String(String self, SseSerializer serializer); + @protected + void sse_encode_announced_user(AnnouncedUser self, SseSerializer serializer); + + @protected + void sse_encode_bool(bool self, SseSerializer serializer); + + @protected + void sse_encode_box_autoadd_announced_user( + AnnouncedUser self, + SseSerializer serializer, + ); + @protected void sse_encode_box_autoadd_i_64( PlatformInt64 self, @@ -135,13 +402,31 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { ); @protected - void sse_encode_contact(Contact self, SseSerializer serializer); + void sse_encode_flutter_user_discovery( + FlutterUserDiscovery self, + SseSerializer serializer, + ); @protected void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer); @protected - void sse_encode_list_contact(List self, SseSerializer serializer); + void sse_encode_isize(PlatformInt64 self, SseSerializer serializer); + + @protected + void sse_encode_list_list_prim_u_8_strict( + List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_list_other_promotion( + List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_list_prim_u_8_loose(List self, SseSerializer serializer); @protected void sse_encode_list_prim_u_8_strict( @@ -149,12 +434,36 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); + @protected + void sse_encode_opt_box_autoadd_announced_user( + AnnouncedUser? self, + SseSerializer serializer, + ); + @protected void sse_encode_opt_box_autoadd_i_64( PlatformInt64? self, SseSerializer serializer, ); + @protected + void sse_encode_opt_list_list_prim_u_8_strict( + List? self, + SseSerializer serializer, + ); + + @protected + void sse_encode_opt_list_other_promotion( + List? self, + SseSerializer serializer, + ); + + @protected + void sse_encode_opt_list_prim_u_8_strict( + Uint8List? self, + SseSerializer serializer, + ); + @protected void sse_encode_other_promotion( OtherPromotion self, @@ -174,10 +483,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_unit(void self, SseSerializer serializer); @protected - void sse_encode_i_32(int self, SseSerializer serializer); + void sse_encode_usize(BigInt self, SseSerializer serializer); @protected - void sse_encode_bool(bool self, SseSerializer serializer); + void sse_encode_i_32(int self, SseSerializer serializer); } // Section: wire_class diff --git a/lib/core/frb_generated.web.dart b/lib/core/frb_generated.web.dart index b658ac73..d56eac0e 100644 --- a/lib/core/frb_generated.web.dart +++ b/lib/core/frb_generated.web.dart @@ -1,7 +1,7 @@ // This file is automatically generated, so please do not edit it. // @generated by `flutter_rust_bridge`@ 2.12.0. -// ignore_for_file: unused_import, non_constant_identifier_names +// ignore_for_file: unused_import, unnecessary_import, non_constant_identifier_names // Static analysis wrongly picks the IO variant, thus ignore this @@ -11,7 +11,8 @@ import 'dart:convert'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart'; import 'bridge.dart'; -import 'database/contact.dart'; +import 'bridge/callbacks.dart'; +import 'bridge/wrapper/user_discovery.dart'; import 'frb_generated.dart'; abstract class RustLibApiImplPlatform extends BaseApiImpl { @@ -25,9 +26,96 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected AnyhowException dco_decode_AnyhowException(dynamic raw); + @protected + FutureOr> Function() + dco_decode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_box_autoadd_announced_user_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr?> Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_list_list_prim_u_8_strict_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr?> Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_list_other_promotion_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(PlatformInt64) + dco_decode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(PlatformInt64, AnnouncedUser, PlatformInt64?) + dco_decode_DartFn_Inputs_i_64_announced_user_opt_box_autoadd_i_64_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(PlatformInt64, PlatformInt64, Uint8List) + dco_decode_DartFn_Inputs_i_64_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(PlatformInt64, Uint8List) + dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(List) + dco_decode_DartFn_Inputs_list_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(Uint8List) + dco_decode_DartFn_Inputs_list_prim_u_8_strict_Output_opt_list_prim_u_8_strict_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(Uint8List, Uint8List, Uint8List) + dco_decode_DartFn_Inputs_list_prim_u_8_strict_list_prim_u_8_strict_list_prim_u_8_strict_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + FutureOr Function(OtherPromotion) + dco_decode_DartFn_Inputs_other_promotion_Output_bool_AnyhowException( + dynamic raw, + ); + + @protected + Object dco_decode_DartOpaque(dynamic raw); + + @protected + RustStreamSink dco_decode_StreamSink_String_Sse(dynamic raw); + @protected String dco_decode_String(dynamic raw); + @protected + AnnouncedUser dco_decode_announced_user(dynamic raw); + + @protected + bool dco_decode_bool(dynamic raw); + + @protected + AnnouncedUser dco_decode_box_autoadd_announced_user(dynamic raw); + @protected PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw); @@ -35,20 +123,41 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { TwonlyConfig dco_decode_box_autoadd_twonly_config(dynamic raw); @protected - Contact dco_decode_contact(dynamic raw); + FlutterUserDiscovery dco_decode_flutter_user_discovery(dynamic raw); @protected PlatformInt64 dco_decode_i_64(dynamic raw); @protected - List dco_decode_list_contact(dynamic raw); + PlatformInt64 dco_decode_isize(dynamic raw); + + @protected + List dco_decode_list_list_prim_u_8_strict(dynamic raw); + + @protected + List dco_decode_list_other_promotion(dynamic raw); + + @protected + List dco_decode_list_prim_u_8_loose(dynamic raw); @protected Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); + @protected + AnnouncedUser? dco_decode_opt_box_autoadd_announced_user(dynamic raw); + @protected PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw); + @protected + List? dco_decode_opt_list_list_prim_u_8_strict(dynamic raw); + + @protected + List? dco_decode_opt_list_other_promotion(dynamic raw); + + @protected + Uint8List? dco_decode_opt_list_prim_u_8_strict(dynamic raw); + @protected OtherPromotion dco_decode_other_promotion(dynamic raw); @@ -64,12 +173,34 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void dco_decode_unit(dynamic raw); + @protected + BigInt dco_decode_usize(dynamic raw); + @protected AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer); + @protected + Object sse_decode_DartOpaque(SseDeserializer deserializer); + + @protected + RustStreamSink sse_decode_StreamSink_String_Sse( + SseDeserializer deserializer, + ); + @protected String sse_decode_String(SseDeserializer deserializer); + @protected + AnnouncedUser sse_decode_announced_user(SseDeserializer deserializer); + + @protected + bool sse_decode_bool(SseDeserializer deserializer); + + @protected + AnnouncedUser sse_decode_box_autoadd_announced_user( + SseDeserializer deserializer, + ); + @protected PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer); @@ -79,20 +210,53 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { ); @protected - Contact sse_decode_contact(SseDeserializer deserializer); + FlutterUserDiscovery sse_decode_flutter_user_discovery( + SseDeserializer deserializer, + ); @protected PlatformInt64 sse_decode_i_64(SseDeserializer deserializer); @protected - List sse_decode_list_contact(SseDeserializer deserializer); + PlatformInt64 sse_decode_isize(SseDeserializer deserializer); + + @protected + List sse_decode_list_list_prim_u_8_strict( + SseDeserializer deserializer, + ); + + @protected + List sse_decode_list_other_promotion( + SseDeserializer deserializer, + ); + + @protected + List sse_decode_list_prim_u_8_loose(SseDeserializer deserializer); @protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); + @protected + AnnouncedUser? sse_decode_opt_box_autoadd_announced_user( + SseDeserializer deserializer, + ); + @protected PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer); + @protected + List? sse_decode_opt_list_list_prim_u_8_strict( + SseDeserializer deserializer, + ); + + @protected + List? sse_decode_opt_list_other_promotion( + SseDeserializer deserializer, + ); + + @protected + Uint8List? sse_decode_opt_list_prim_u_8_strict(SseDeserializer deserializer); + @protected OtherPromotion sse_decode_other_promotion(SseDeserializer deserializer); @@ -109,10 +273,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_decode_unit(SseDeserializer deserializer); @protected - int sse_decode_i_32(SseDeserializer deserializer); + BigInt sse_decode_usize(SseDeserializer deserializer); @protected - bool sse_decode_bool(SseDeserializer deserializer); + int sse_decode_i_32(SseDeserializer deserializer); @protected void sse_encode_AnyhowException( @@ -120,9 +284,112 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); + @protected + void sse_encode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException( + FutureOr> Function() self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_box_autoadd_announced_user_AnyhowException( + FutureOr Function(PlatformInt64) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_list_list_prim_u_8_strict_AnyhowException( + FutureOr?> Function(PlatformInt64) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_list_other_promotion_AnyhowException( + FutureOr?> Function(PlatformInt64) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException( + FutureOr Function(PlatformInt64) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_announced_user_opt_box_autoadd_i_64_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, AnnouncedUser, PlatformInt64?) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, PlatformInt64, Uint8List) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(PlatformInt64, Uint8List) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_list_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(List) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_list_prim_u_8_strict_Output_opt_list_prim_u_8_strict_AnyhowException( + FutureOr Function(Uint8List) self, + SseSerializer serializer, + ); + + @protected + void + sse_encode_DartFn_Inputs_list_prim_u_8_strict_list_prim_u_8_strict_list_prim_u_8_strict_Output_bool_AnyhowException( + FutureOr Function(Uint8List, Uint8List, Uint8List) self, + SseSerializer serializer, + ); + + @protected + void sse_encode_DartFn_Inputs_other_promotion_Output_bool_AnyhowException( + FutureOr Function(OtherPromotion) self, + SseSerializer serializer, + ); + + @protected + void sse_encode_DartOpaque(Object self, SseSerializer serializer); + + @protected + void sse_encode_StreamSink_String_Sse( + RustStreamSink self, + SseSerializer serializer, + ); + @protected void sse_encode_String(String self, SseSerializer serializer); + @protected + void sse_encode_announced_user(AnnouncedUser self, SseSerializer serializer); + + @protected + void sse_encode_bool(bool self, SseSerializer serializer); + + @protected + void sse_encode_box_autoadd_announced_user( + AnnouncedUser self, + SseSerializer serializer, + ); + @protected void sse_encode_box_autoadd_i_64( PlatformInt64 self, @@ -136,13 +403,31 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { ); @protected - void sse_encode_contact(Contact self, SseSerializer serializer); + void sse_encode_flutter_user_discovery( + FlutterUserDiscovery self, + SseSerializer serializer, + ); @protected void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer); @protected - void sse_encode_list_contact(List self, SseSerializer serializer); + void sse_encode_isize(PlatformInt64 self, SseSerializer serializer); + + @protected + void sse_encode_list_list_prim_u_8_strict( + List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_list_other_promotion( + List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_list_prim_u_8_loose(List self, SseSerializer serializer); @protected void sse_encode_list_prim_u_8_strict( @@ -150,12 +435,36 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); + @protected + void sse_encode_opt_box_autoadd_announced_user( + AnnouncedUser? self, + SseSerializer serializer, + ); + @protected void sse_encode_opt_box_autoadd_i_64( PlatformInt64? self, SseSerializer serializer, ); + @protected + void sse_encode_opt_list_list_prim_u_8_strict( + List? self, + SseSerializer serializer, + ); + + @protected + void sse_encode_opt_list_other_promotion( + List? self, + SseSerializer serializer, + ); + + @protected + void sse_encode_opt_list_prim_u_8_strict( + Uint8List? self, + SseSerializer serializer, + ); + @protected void sse_encode_other_promotion( OtherPromotion self, @@ -175,10 +484,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_unit(void self, SseSerializer serializer); @protected - void sse_encode_i_32(int self, SseSerializer serializer); + void sse_encode_usize(BigInt self, SseSerializer serializer); @protected - void sse_encode_bool(bool self, SseSerializer serializer); + void sse_encode_i_32(int self, SseSerializer serializer); } // Section: wire_class diff --git a/lib/main.dart b/lib/main.dart index 51d3e381..60db82de 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,6 +10,7 @@ import 'package:twonly/app.dart'; import 'package:twonly/core/bridge.dart' as bridge; import 'package:twonly/core/frb_generated.dart'; import 'package:twonly/globals.dart'; +import 'package:twonly/src/callbacks/callbacks.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/providers/connection.provider.dart'; import 'package:twonly/src/providers/image_editor.provider.dart'; @@ -37,7 +38,11 @@ void main() async { globalApplicationSupportDirectory = (await getApplicationSupportDirectory()).path; - await bridge.initializeTwonly( + initLogger(); + + await initFlutterCallbacksForRust(); + + await bridge.initializeTwonlyFlutter( config: bridge.TwonlyConfig( databasePath: '$globalApplicationSupportDirectory/twonly.sqlite', dataDirectory: globalApplicationSupportDirectory, @@ -68,8 +73,6 @@ void main() async { await deleteLocalUserData(); } - initLogger(); - final settingsController = SettingsChangeProvider(); await settingsController.loadSettings(); diff --git a/lib/src/callbacks/callbacks.dart b/lib/src/callbacks/callbacks.dart new file mode 100644 index 00000000..ae062921 --- /dev/null +++ b/lib/src/callbacks/callbacks.dart @@ -0,0 +1,28 @@ +import 'package:twonly/core/bridge/callbacks.dart'; +import 'package:twonly/src/callbacks/logging.callbacks.dart'; +import 'package:twonly/src/callbacks/user_discovery.callbacks.dart'; + +Future initFlutterCallbacksForRust() async { + await initFlutterCallbacks( + loggingGetStreamSink: LoggingCallbacks.getStreamSink, + userDiscoverySetShares: UserDiscoveryCallbacks.setShares, + userDiscoveryGetShareForContact: + UserDiscoveryCallbacks.userDiscoveryGetShareForContact, + userDiscoveryPushOwnPromotion: UserDiscoveryCallbacks.pushOwnPromotion, + userDiscoveryPushNewUserRelation: + UserDiscoveryCallbacks.pushNewUserRelation, + userDiscoveryGetOwnPromotionsAfterVersion: + UserDiscoveryCallbacks.getOwnPromotionsAfterVersion, + userDiscoveryStoreOtherPromotion: + UserDiscoveryCallbacks.storeOtherPromotion, + userDiscoveryGetOtherPromotionsByPublicId: + UserDiscoveryCallbacks.getOtherPromotionsByPublicId, + userDiscoveryGetAnnouncedUserByPublicId: + UserDiscoveryCallbacks.getAnnouncedUserByPublicId, + userDiscoveryGetContactVersion: UserDiscoveryCallbacks.getContactVersion, + userDiscoverySetContactVersion: UserDiscoveryCallbacks.setContactVersion, + userDiscoverySignData: UserDiscoveryCallbacks.signData, + userDiscoveryVerifySignature: UserDiscoveryCallbacks.verifySignature, + userDiscoveryVerifyStoredPubkey: UserDiscoveryCallbacks.verifyStoredPubKey, + ); +} diff --git a/lib/src/callbacks/logging.callbacks.dart b/lib/src/callbacks/logging.callbacks.dart new file mode 100644 index 00000000..bd8e7117 --- /dev/null +++ b/lib/src/callbacks/logging.callbacks.dart @@ -0,0 +1,32 @@ +import 'dart:async'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; +import 'package:twonly/src/utils/log.dart'; + +class LoggingCallbacks { + static Future> getStreamSink() async { + final dartLogSink = RustStreamSink(); + + Timer.periodic(const Duration(milliseconds: 100), (timer) { + try { + dartLogSink.stream.listen( + (log) { + if (log.contains('INFO ')) { + Log.info(log.split('INFO ')[1]); + } else if (log.contains('DEBUG ')) { + Log.info(log.split('DEBUG ')[1]); + } else if (kDebugMode) { + print(log); + } + }, + onDone: () => Log.error('Log stream closed'), + ); + timer.cancel(); + } catch (e) { + // stream not yet initialized + } + }); + + return dartLogSink; + } +} diff --git a/lib/src/callbacks/user_discovery.callbacks.dart b/lib/src/callbacks/user_discovery.callbacks.dart new file mode 100644 index 00000000..8d4964db --- /dev/null +++ b/lib/src/callbacks/user_discovery.callbacks.dart @@ -0,0 +1,294 @@ +import 'package:drift/drift.dart'; +import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart' + show Curve, IdentityKey; +// ignore: implementation_imports +import 'package:libsignal_protocol_dart/src/ecc/ed25519.dart'; +import 'package:twonly/core/bridge.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/database/twonly.db.dart'; +import 'package:twonly/src/services/signal/identity.signal.dart'; +import 'package:twonly/src/services/signal/session.signal.dart'; +import 'package:twonly/src/utils/log.dart'; +import 'package:twonly/src/utils/misc.dart'; + +class UserDiscoveryCallbacks { + static Future signData( + Uint8List inputData, + ) async { + var privKey = (await getSignalIdentityKeyPair())?.getPrivateKey(); + if (privKey == null) return null; + final random = getRandomUint8List(32); + final signature = sign( + privKey.serialize(), + inputData, + random, + ); + privKey = null; + return signature; + } + + static Future verifySignature( + Uint8List inputData, + Uint8List pubKey, + Uint8List signature, + ) async { + return Curve.verifySignature( + IdentityKey.fromBytes(pubKey, 0).publicKey, + inputData, + signature, + ); + } + + static Future verifyStoredPubKey( + int contactId, + Uint8List pubKey, + ) async { + final storedPublicKey = await getPublicKeyFromContact(contactId); + if (storedPublicKey != null) { + return storedPublicKey == pubKey; + } else { + return false; + } + } + + static Future setShares(List shares) async { + try { + // First remove all old shares then insert all the new shares + await twonlyDB.delete(twonlyDB.userDiscoveryShares).go(); + await twonlyDB.batch((b) { + b.insertAll( + twonlyDB.userDiscoveryShares, + shares + .map((s) => UserDiscoverySharesCompanion(share: Value(s))) + .toList(), + ); + }); + return true; + } catch (e) { + Log.error(e); + return false; + } + } + + static Future userDiscoveryGetShareForContact( + int contactId, + ) async { + return twonlyDB.transaction(() async { + // 1. Check if this contact already has a share assigned + final existing = + await (twonlyDB.select(twonlyDB.userDiscoveryShares) + ..where((tbl) => tbl.contactId.equals(contactId)) + ..limit(1)) + .getSingleOrNull(); + + if (existing != null) { + return existing.share; + } + + // 2. No share found. Find an available one (where contactId is null) + final available = + await (twonlyDB.select(twonlyDB.userDiscoveryShares) + ..where((tbl) => tbl.contactId.isNull()) + ..limit(1)) + .getSingleOrNull(); + + if (available != null) { + // 3. Assign the contactId to this available share + await (twonlyDB.update( + twonlyDB.userDiscoveryShares, + )..where((tbl) => tbl.shareId.equals(available.shareId))).write( + UserDiscoverySharesCompanion( + contactId: Value(contactId), + ), + ); + + return available.share; + } + + return null; // 4. No existing or available shares found + }); + } + + static Future pushOwnPromotion( + int contactId, + int version, // Maps to versionId or logic control + Uint8List promotion, + ) async { + try { + await twonlyDB + .into(twonlyDB.userDiscoveryOwnPromotions) + .insert( + UserDiscoveryOwnPromotionsCompanion.insert( + contactId: contactId, + promotion: promotion, + ), + ); + return true; + } catch (e) { + Log.error(e); + return false; + } + } + + static Future> getOwnPromotionsAfterVersion( + int version, + ) async { + final query = twonlyDB.select(twonlyDB.userDiscoveryOwnPromotions) + ..where((tbl) => tbl.versionId.isBiggerThanValue(version)); + + final rows = await query.get(); + return rows.map((r) => r.promotion).toList(); + } + + static Future storeOtherPromotion( + OtherPromotion promotion, + ) async { + try { + await twonlyDB + .into(twonlyDB.userDiscoveryOtherPromotions) + .insertOnConflictUpdate( + UserDiscoveryOtherPromotionsCompanion( + promotionId: Value(promotion.promotionId), + publicId: Value(promotion.publicId), + fromContactId: Value(promotion.fromContactId), + threshold: Value(promotion.threshold), + announcementShare: Value(promotion.announcementShare), + publicKeyVerifiedTimestamp: Value( + promotion.publicKeyVerifiedTimestamp == null + ? null + : DateTime.fromMillisecondsSinceEpoch( + promotion.publicKeyVerifiedTimestamp!, + ), + ), + ), + ); + return true; + } catch (e) { + Log.error(e); + return false; + } + } + + static Future> getOtherPromotionsByPublicId( + int publicId, + ) async { + final rows = await (twonlyDB.select( + twonlyDB.userDiscoveryOtherPromotions, + )..where((tbl) => tbl.publicId.equals(publicId))).get(); + + return rows + .map( + (row) => OtherPromotion( + promotionId: row.promotionId, + publicId: row.publicId, + fromContactId: row.fromContactId, + threshold: row.threshold, + announcementShare: row.announcementShare, + publicKeyVerifiedTimestamp: + row.publicKeyVerifiedTimestamp?.millisecondsSinceEpoch, + ), + ) + .toList(); + } + + static Future getAnnouncedUserByPublicId( + int publicId, + ) async { + final row = await (twonlyDB.select( + twonlyDB.userDiscoveryAnnouncedUsers, + )..where((tbl) => tbl.publicId.equals(publicId))).getSingleOrNull(); + if (row == null) return null; + return AnnouncedUser( + userId: row.announcedUserId, + publicKey: row.announcedPublicKey, + publicId: row.publicId, + ); + } + + static Future pushNewUserRelation( + int fromContactId, + AnnouncedUser announcedUser, + int? publicKeyVerifiedTimestamp, + ) async { + try { + await twonlyDB.transaction(() async { + // 1. Ensure the user exists in the AnnouncedUsers table + await twonlyDB + .into(twonlyDB.userDiscoveryAnnouncedUsers) + .insertOnConflictUpdate( + UserDiscoveryAnnouncedUser( + announcedUserId: announcedUser.userId, + announcedPublicKey: announcedUser.publicKey, + publicId: announcedUser.publicId, + ), + ); + + // 2. Insert or update the relation + await twonlyDB + .into(twonlyDB.userDiscoveryUserRelations) + .insertOnConflictUpdate( + UserDiscoveryUserRelationsCompanion.insert( + announcedUserId: announcedUser.userId, + fromContactId: fromContactId, + publicKeyVerifiedTimestamp: Value( + publicKeyVerifiedTimestamp != null + ? DateTime.fromMillisecondsSinceEpoch( + publicKeyVerifiedTimestamp, + ) + : null, + ), + ), + ); + }); + return true; + } catch (e) { + Log.error(e); + return false; + } + } + + // static Future>> + // getAllAnnouncedUsers() async { + // final query = twonlyDB.select(twonlyDB.userDiscoveryAnnouncedUsers).join([ + // innerJoin( + // twonlyDB.userDiscoveryUserRelations, + // twonlyDB.userDiscoveryUserRelations.announcedUserId.equalsExp( + // twonlyDB.userDiscoveryAnnouncedUsers.announcedUserId, + // ), + // ), + // ]); + + // final results = await query.get(); + // final map = >{}; + + // for (final row in results) { + // final user = row.readTable(twonlyDB.userDiscoveryAnnouncedUsers); + // final relation = row.readTable(twonlyDB.userDiscoveryUserRelations); + + // map.putIfAbsent(user, () => []).add( + // (relation.fromContactId, relation.publicKeyVerifiedTimestamp), + // ); + // } + + // return map; + // } + + static Future getContactVersion(int contactId) async { + final row = await (twonlyDB.select( + twonlyDB.contacts, + )..where((tbl) => tbl.userId.equals(contactId))).getSingleOrNull(); + return row?.userDiscoveryVersion; + } + + static Future setContactVersion(int contactId, Uint8List update) async { + try { + await (twonlyDB.update(twonlyDB.contacts) + ..where((tbl) => tbl.userId.equals(contactId))) + .write(ContactsCompanion(userDiscoveryVersion: Value(update))); + return true; + } catch (e) { + Log.error(e); + return false; + } + } +} diff --git a/lib/src/constants/routes.keys.dart b/lib/src/constants/routes.keys.dart index 157c27da..66a1fabb 100644 --- a/lib/src/constants/routes.keys.dart +++ b/lib/src/constants/routes.keys.dart @@ -34,6 +34,8 @@ class Routes { static const String settingsPrivacy = '/settings/privacy'; static const String settingsPrivacyBlockUsers = '/settings/privacy/block_users'; + static const String settingsPrivacyUserDiscovery = + '/settings/privacy/user_discovery'; static const String settingsNotification = '/settings/notification'; static const String settingsStorage = '/settings/storage_data'; static const String settingsStorageImport = '/settings/storage_data/import'; diff --git a/lib/src/model/json/userdata.dart b/lib/src/model/json/userdata.dart index 04f52587..f7495472 100644 --- a/lib/src/model/json/userdata.dart +++ b/lib/src/model/json/userdata.dart @@ -96,6 +96,9 @@ class UserData { @JsonKey(defaultValue: false) bool isUserDiscoveryEnabled = false; + @JsonKey(defaultValue: false) + int minimumRequiredImagesExchanged = 4; + // -- Custom DATA -- @JsonKey(defaultValue: 100_000) diff --git a/lib/src/providers/routing.provider.dart b/lib/src/providers/routing.provider.dart index d1eb1b00..cf43cedf 100644 --- a/lib/src/providers/routing.provider.dart +++ b/lib/src/providers/routing.provider.dart @@ -37,7 +37,8 @@ import 'package:twonly/src/views/settings/help/faq/verifybadge.dart'; import 'package:twonly/src/views/settings/help/help.view.dart'; import 'package:twonly/src/views/settings/notification.view.dart'; import 'package:twonly/src/views/settings/privacy.view.dart'; -import 'package:twonly/src/views/settings/privacy_view_block.view.dart'; +import 'package:twonly/src/views/settings/privacy/block_users.view.dart'; +import 'package:twonly/src/views/settings/privacy/user_discovery.view.dart'; import 'package:twonly/src/views/settings/profile/modify_avatar.view.dart'; import 'package:twonly/src/views/settings/profile/profile.view.dart'; import 'package:twonly/src/views/settings/settings_main.view.dart'; @@ -200,7 +201,11 @@ final routerProvider = GoRouter( routes: [ GoRoute( path: 'block_users', - builder: (context, state) => const PrivacyViewBlockUsersView(), + builder: (context, state) => const BlockUsersView(), + ), + GoRoute( + path: 'user_discovery', + builder: (context, state) => const UserDiscoverySettingsView(), ), ], ), diff --git a/lib/src/services/user_discovery.service.dart b/lib/src/services/user_discovery.service.dart new file mode 100644 index 00000000..742cbac3 --- /dev/null +++ b/lib/src/services/user_discovery.service.dart @@ -0,0 +1,26 @@ +import 'package:twonly/core/bridge/wrapper/user_discovery.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/utils/log.dart'; +import 'package:twonly/src/utils/qr.dart'; +import 'package:twonly/src/utils/storage.dart'; + +Future initializeOrUpdateUserDiscovery({ + required int threshold, + required int minimumRequiredImagesExchanged, +}) async { + try { + await FlutterUserDiscovery.initializeOrUpdate( + threshold: threshold, + userId: gUser.userId, + publicKey: await getUserPublicKey(), + ); + await updateUserdata((u) { + u + ..isUserDiscoveryEnabled = true + ..minimumRequiredImagesExchanged = minimumRequiredImagesExchanged; + return u; + }); + } catch (e) { + Log.error(e); + } +} diff --git a/lib/src/themes/light.dart b/lib/src/themes/light.dart index 88bfc716..a6841cd8 100644 --- a/lib/src/themes/light.dart +++ b/lib/src/themes/light.dart @@ -1,10 +1,32 @@ import 'package:flutter/material.dart'; +final primaryColor = const Color(0xFF57CC99); + final ThemeData lightTheme = ThemeData( colorScheme: ColorScheme.fromSeed( - seedColor: const Color(0xFF57CC99), + seedColor: primaryColor, ), inputDecorationTheme: const InputDecorationTheme( border: OutlineInputBorder(), ), ); + +final ButtonStyle primaryColorButtonStyle = FilledButton.styleFrom( + backgroundColor: primaryColor, + foregroundColor: Colors.black87, + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), + // Adjusting the border radius (default is usually 20+) + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), // Lower number = sharper corners + ), +); + +final ButtonStyle secondaryGreyButtonStyle = FilledButton.styleFrom( + backgroundColor: Colors.grey[200], + foregroundColor: Colors.black87, + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), + // Adjusting the border radius (default is usually 20+) + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), // Lower number = sharper corners + ), +); diff --git a/lib/src/utils/misc.dart b/lib/src/utils/misc.dart index fb35ec52..606a812d 100644 --- a/lib/src/utils/misc.dart +++ b/lib/src/utils/misc.dart @@ -404,3 +404,50 @@ Future> sha256File(File file) async { converter.close(); return sha256Sink.events.single.bytes; } + +List formattedText(String input) { + // Pattern to find text between asterisks + final regex = RegExp(r'\*(.*?)\*'); + final List spans = []; + + // Track the current position in the string + int lastMatchEnd = 0; + + for (final match in regex.allMatches(input)) { + // Add text before the match (Normal style) + if (match.start > lastMatchEnd) { + spans.add( + TextSpan( + text: input.substring(lastMatchEnd, match.start), + style: const TextStyle(color: Colors.black), + ), + ); + } + + // Add the matched text (Bold style) + // match.group(1) is the text without the asterisks + spans.add( + TextSpan( + text: match.group(1), + style: const TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ); + + lastMatchEnd = match.end; + } + + // Add any remaining text after the last match + if (lastMatchEnd < input.length) { + spans.add( + TextSpan( + text: input.substring(lastMatchEnd), + style: const TextStyle(color: Colors.black), + ), + ); + } + + return spans; +} diff --git a/lib/src/views/settings/privacy.view.dart b/lib/src/views/settings/privacy.view.dart index 3607b30a..89a92209 100644 --- a/lib/src/views/settings/privacy.view.dart +++ b/lib/src/views/settings/privacy.view.dart @@ -73,6 +73,13 @@ class _PrivacyViewState extends State { setState(() {}); }, ), + ListTile( + title: const Text('Freunde finden'), + onTap: () async { + await context.push(Routes.settingsPrivacyUserDiscovery); + setState(() {}); + }, + ), const Divider(), ListTile( title: Text(context.lang.settingsTypingIndication), diff --git a/lib/src/views/settings/privacy_view_block.view.dart b/lib/src/views/settings/privacy/block_users.view.dart similarity index 93% rename from lib/src/views/settings/privacy_view_block.view.dart rename to lib/src/views/settings/privacy/block_users.view.dart index d9b835d2..57f55c2c 100644 --- a/lib/src/views/settings/privacy_view_block.view.dart +++ b/lib/src/views/settings/privacy/block_users.view.dart @@ -7,14 +7,14 @@ import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/views/components/avatar_icon.component.dart'; import 'package:twonly/src/views/components/user_context_menu.component.dart'; -class PrivacyViewBlockUsersView extends StatefulWidget { - const PrivacyViewBlockUsersView({super.key}); +class BlockUsersView extends StatefulWidget { + const BlockUsersView({super.key}); @override - State createState() => _PrivacyViewBlockUsers(); + State createState() => _PrivacyViewBlockUsers(); } -class _PrivacyViewBlockUsers extends State { +class _PrivacyViewBlockUsers extends State { late Stream> allUsers; List filteredUsers = []; String filter = ''; diff --git a/lib/src/views/settings/privacy/user_discovery.view.dart b/lib/src/views/settings/privacy/user_discovery.view.dart new file mode 100644 index 00000000..93f9323a --- /dev/null +++ b/lib/src/views/settings/privacy/user_discovery.view.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart'; +import 'package:twonly/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart'; + +class UserDiscoverySettingsView extends StatefulWidget { + const UserDiscoverySettingsView({super.key}); + + @override + State createState() => + _UserDiscoverySettingsViewState(); +} + +class _UserDiscoverySettingsViewState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Freunde finden'), + ), + body: gUser.isUserDiscoveryEnabled + ? UserDiscoveryEnabledComponent(onUpdate: () => setState(() {})) + : UserDiscoveryDisabledComponent(onUpdate: () => setState(() {})), + ); + } +} diff --git a/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart b/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart new file mode 100644 index 00000000..519f3bb6 --- /dev/null +++ b/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:twonly/src/services/user_discovery.service.dart'; +import 'package:twonly/src/themes/light.dart'; +import 'package:twonly/src/utils/misc.dart'; + +class UserDiscoveryDisabledComponent extends StatefulWidget { + const UserDiscoveryDisabledComponent({required this.onUpdate, super.key}); + + final VoidCallback onUpdate; + + @override + State createState() => + _UserDiscoveryDisabledComponentState(); +} + +class _UserDiscoveryDisabledComponentState + extends State { + Future initializeUserDiscoveryWithDefaultSettings() async { + await initializeOrUpdateUserDiscovery( + threshold: 2, + minimumRequiredImagesExchanged: 4, + ); + widget.onUpdate(); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 40), + child: ListView( + children: [ + const SizedBox(height: 45), + const Text( + 'twonly verzichten auf Telefonnummern, daher schlagen wir dir Freunde stattdessen über gemeinsame Kontakte vor – sicher und privat.', + textAlign: TextAlign.center, + ), + const SizedBox(height: 30), + RichText( + text: TextSpan( + children: formattedText( + 'Deine Freundesliste ist für *Fremde komplett unsichtbar*. Nur deine Freunde können Teile davon sehen – und zwar nur die Personen, mit denen sie selbst *gemeinsame Freunde* haben.', + ), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 35), + const Text( + 'Du hast die Kontrolle', + style: TextStyle(fontSize: 17), + textAlign: TextAlign.center, + ), + const SizedBox(height: 20), + const Text( + 'Entscheide selbst, wer deine Freunde sehen darf. Du kannst deine Meinung jederzeit ändern oder bestimmte Personen verstecken.', + textAlign: TextAlign.center, + ), + + const SizedBox(height: 50), + + FilledButton( + onPressed: initializeUserDiscoveryWithDefaultSettings, + style: primaryColorButtonStyle.merge( + FilledButton.styleFrom( + padding: EdgeInsets.symmetric(horizontal: 32, vertical: 24), + ), + ), + child: const Text('Mit Standardeinstellungen aktivieren'), + ), + + const SizedBox(height: 20), + + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: FilledButton( + onPressed: () {}, + style: secondaryGreyButtonStyle, + child: const Text('Einstellungen anpassen'), + ), + ), + const SizedBox(height: 15), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: FilledButton( + onPressed: () {}, + style: secondaryGreyButtonStyle, + child: const Text('Mehr erfahren'), + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart b/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart new file mode 100644 index 00000000..91e50ade --- /dev/null +++ b/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; + +class UserDiscoveryEnabledComponent extends StatefulWidget { + const UserDiscoveryEnabledComponent({required this.onUpdate, super.key}); + + final VoidCallback onUpdate; + + @override + State createState() => + _UserDiscoveryEnabledComponentState(); +} + +class _UserDiscoveryEnabledComponentState + extends State { + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(top: 10), + child: ListView( + children: [ + const ExpansionTile( + shape: RoundedRectangleBorder(), + collapsedShape: RoundedRectangleBorder(), + tilePadding: EdgeInsets.symmetric(horizontal: 17), + title: Text('Freunde die du teilst'), + subtitle: Text( + 'Du teilst nur Freunde, die diese Funktion ebenfalls aktiviert haben und die den von dir festgelegten Schwellenwert erreicht haben.', + style: TextStyle(fontSize: 10), + ), + children: [], + ), + ListTile( + title: Text('Einstellungen ändern'), + // onTap: () {}, + ), + const Divider(), + ListTile( + title: Text('Deaktivieren'), + onTap: () {}, + ), + ], + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index e4208c58..09b74374 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -412,26 +412,26 @@ packages: dependency: "direct main" description: name: drift - sha256: "970cd188fddb111b26ea6a9b07a62bf5c2432d74147b8122c67044ae3b97e99e" + sha256: "055c249d1f91be5a47fe447f88afc24c4ca6f4cd6c5ed66767b4797d48acc2e5" url: "https://pub.dev" source: hosted - version: "2.31.0" + version: "2.32.1" drift_dev: dependency: "direct dev" description: name: drift_dev - sha256: "917184b2fb867b70a548a83bf0d36268423b38d39968c06cce4905683da49587" + sha256: "88a9de3af8571518148a6d8a513b57779fd1e60a026d3ab8a481a878fba01d91" url: "https://pub.dev" source: hosted - version: "2.31.0" + version: "2.32.1" drift_flutter: dependency: "direct main" description: name: drift_flutter - sha256: c07120854742a0cae2f7501a0da02493addde550db6641d284983c08762e60a7 + sha256: "887fdec622174dc7eaefd0048403e34ee07cc18626ac8a7544cc3b8a4a172166" url: "https://pub.dev" source: hosted - version: "0.2.8" + version: "0.3.0" ed25519_edwards: dependency: "direct overridden" description: @@ -1809,30 +1809,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" - sqlite3: - dependency: "direct main" + sqlcipher_flutter_libs: + dependency: transitive description: - name: sqlite3 - sha256: "3145bd74dcdb4fd6f5c6dda4d4e4490a8087d7f286a14dee5d37087290f0f8a2" + name: sqlcipher_flutter_libs + sha256: "38d62d659d2fb8739bf25a42c9a350d1fdd6c29a5a61f13a946778ec75d27929" url: "https://pub.dev" source: hosted - version: "2.9.4" + version: "0.7.0+eol" + sqlite3: + dependency: transitive + description: + name: sqlite3 + sha256: "56da3e13ed7d28a66f930aa2b2b29db6736a233f08283326e96321dd812030f5" + url: "https://pub.dev" + source: hosted + version: "3.3.1" sqlite3_flutter_libs: dependency: transitive description: name: sqlite3_flutter_libs - sha256: eeb9e3a45207649076b808f8a5a74d68770d0b7f26ccef6d5f43106eee5375ad + sha256: "3ed7553eee7bb368f8950f58ba29f634e06e813c029aff6a0d60862b96de8454" url: "https://pub.dev" source: hosted - version: "0.5.42" + version: "0.6.0+eol" sqlparser: dependency: transitive description: name: sqlparser - sha256: "337e9997f7141ffdd054259128553c348635fa318f7ca492f07a4ab76f850d19" + sha256: ab2b467425f1d4f3acfa5fd11a08226f7d6c26ff102c06be1807e1dff34e050b url: "https://pub.dev" source: hosted - version: "0.43.1" + version: "0.44.3" stack_trace: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 2d2d621a..e719188a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,9 +58,8 @@ dependencies: json_annotation: ^4.9.0 # google.dev protobuf: ^4.0.0 # google.dev scrollable_positioned_list: ^0.3.8 # google.dev - drift: ^2.25.1 - drift_flutter: ^0.2.4 - sqlite3: ^2.9.4 + drift: ^2.32.0 + drift_flutter: ^0.3.0 # Flutter Favorite diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 5823bc53..0fccb096 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -305,6 +305,15 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -392,6 +401,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + [[package]] name = "digest" version = "0.10.7" @@ -1071,9 +1089,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.35.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -1107,6 +1125,15 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "md-5" version = "0.10.6" @@ -1149,6 +1176,15 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "num-bigint-dig" version = "0.8.6" @@ -1165,6 +1201,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + [[package]] name = "num-integer" version = "0.1.46" @@ -1260,6 +1302,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1340,6 +1388,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -1582,7 +1636,7 @@ name = "rust_lib_twonly" version = "0.1.0" dependencies = [ "flutter_rust_bridge", - "parking_lot", + "paste", "pretty_env_logger", "prost-build", "protocols", @@ -1592,6 +1646,8 @@ dependencies = [ "thiserror", "tokio", "tracing", + "tracing-appender", + "tracing-subscriber", ] [[package]] @@ -1725,6 +1781,15 @@ dependencies = [ "digest 0.11.2", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -2009,6 +2074,12 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "2.0.117" @@ -2073,6 +2144,15 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "threadpool" version = "1.8.1" @@ -2082,6 +2162,37 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinystr" version = "0.8.3" @@ -2158,6 +2269,19 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" @@ -2176,6 +2300,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -2235,6 +2389,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 274b4676..47ab6cf6 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,3 +1,35 @@ -[workspace] -members = ["protocols", "core"] -resolver = "3" +[package] +name = "rust_lib_twonly" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "staticlib"] + +[dependencies] +flutter_rust_bridge = "=2.12.0" +thiserror = "2.0.18" +sqlx = { version = "0.9.0-alpha.1", default-features = false, features = [ + "runtime-tokio", + "sqlite", + "migrate", + "macros", + "chrono", + "derive", + "json", +] } +tokio = { version = "1.44", features = ["full"] } +tracing = "0.1.44" +rand = "0.10.1" +protocols = { path = "../rust_dependencies/protocols" } +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tracing-appender = "0.2.5" +paste = "1.0.15" + +[dev-dependencies] +pretty_env_logger = "0.5.0" +tempfile = "3.27.0" + + +[build-dependencies] +prost-build = "0.14.1" diff --git a/rust/src/bridge/callbacks.rs b/rust/src/bridge/callbacks.rs new file mode 100644 index 00000000..297ccb90 --- /dev/null +++ b/rust/src/bridge/callbacks.rs @@ -0,0 +1,47 @@ +pub(crate) mod log; +mod macros; +pub(crate) mod user_discovery; + +use flutter_rust_bridge::DartFnFuture; +use protocols::user_discovery::traits::{AnnouncedUser, OtherPromotion}; + +use super::error::Result; +use crate::{callback_generator, frb_generated::StreamSink}; +use std::sync::{Arc, OnceLock}; + +use crate::bridge::error::TwonlyError; + +static FLUTTER_CALLBACKS: OnceLock = OnceLock::new(); + +// This will also generate the function init_flutter_callbacks which MUST be called from Flutter to initialize the callbacks +callback_generator! { + FlutterCallbacks { + Logging logging { + get_stream_sink: () => StreamSink + }, + UserDiscoveryCallbacks user_discovery { + // UserDiscoveryUtils + sign_data: (Vec) => Option>, + verify_signature: (Vec, Vec, Vec) => bool, + verify_stored_pubkey: (i64, Vec) => bool, + + // UserDiscoveryStore + set_shares: (Vec>) => bool, + get_share_for_contact: (i64) => Option>, + push_own_promotion: (i64, i64, Vec) => bool, + get_own_promotions_after_version: (i64) => Option>>, + store_other_promotion: (OtherPromotion) => bool, + get_other_promotions_by_public_id: (i64) => Option>, + get_announced_user_by_public_id: (i64) => Option, + get_contact_version: (i64) => Option>, + set_contact_version: (i64, Vec) => bool, + push_new_user_relation: (i64, AnnouncedUser, Option) => bool, + } + } +} + +pub(crate) fn get_callbacks() -> Result<&'static FlutterCallbacks> { + FLUTTER_CALLBACKS + .get() + .ok_or(TwonlyError::MissingCallbackInitialization) +} diff --git a/rust/src/bridge/callbacks/log.rs b/rust/src/bridge/callbacks/log.rs new file mode 100644 index 00000000..e1525ed2 --- /dev/null +++ b/rust/src/bridge/callbacks/log.rs @@ -0,0 +1,28 @@ +use crate::frb_generated::StreamSink; +use tracing_subscriber::fmt::MakeWriter; + +#[derive(Clone)] +pub(crate) struct DartWriter { + pub(crate) sink: StreamSink, +} + +impl std::io::Write for DartWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + if let Ok(msg) = std::str::from_utf8(buf) { + let _ = self.sink.add(msg.trim_end().to_string()); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +impl<'a> MakeWriter<'a> for DartWriter { + type Writer = DartWriter; + + fn make_writer(&'a self) -> Self::Writer { + self.clone() + } +} diff --git a/rust/src/bridge/callbacks/macros.rs b/rust/src/bridge/callbacks/macros.rs new file mode 100644 index 00000000..bd5fa8aa --- /dev/null +++ b/rust/src/bridge/callbacks/macros.rs @@ -0,0 +1,57 @@ +#[macro_export] +macro_rules! callback_generator { + ( + $struct_name:ident { + $( + $sub_struct_name:ident $sub_struct_field:ident { + $( + $fn_name:ident : ($($input:ty),*) => $output:ty + ),* $(,)? + } + ),* $(,)? + } + ) => { + // 1. Generate the Nested Sub-Structs + $( + pub(crate) struct $sub_struct_name { + $( + pub(crate) $fn_name: Arc DartFnFuture<$output> + Send + Sync + 'static>, + )* + } + )* + + // 2. Generate the Main Container Struct + pub(crate) struct $struct_name { + $( + pub(crate) $sub_struct_field: $sub_struct_name, + )* + } + + // 3. Generate the Automated Init Function + paste::paste! { + pub async fn init_flutter_callbacks( + $( + $( + // Parameters: sub-struct_field + _ + fn_name + [<$sub_struct_field _ $fn_name>]: impl Fn($($input),*) -> DartFnFuture<$output> + Send + Sync + 'static, + )* + )* + ) { + let callbacks = $struct_name { + $( + $sub_struct_field: $sub_struct_name { + $( + $fn_name: Arc::new([<$sub_struct_field _ $fn_name>]), + )* + }, + )* + }; + + // Use the static global strictly named FLUTTER_CALLBACKS + FLUTTER_CALLBACKS.set(callbacks).unwrap_or_else(|_| { + println!("Callbacks were already initialized!"); + }); + } + } + }; +} diff --git a/rust/src/bridge/callbacks/user_discovery.rs b/rust/src/bridge/callbacks/user_discovery.rs new file mode 100644 index 00000000..b10fb247 --- /dev/null +++ b/rust/src/bridge/callbacks/user_discovery.rs @@ -0,0 +1,169 @@ +use crate::bridge::callbacks::get_callbacks; +use crate::bridge::error::TwonlyError; +use crate::bridge::get_twonly_flutter; +use protocols::user_discovery::error::{Result, UserDiscoveryError}; +use protocols::user_discovery::traits::UserDiscoveryUtils; +use protocols::user_discovery::traits::{AnnouncedUser, OtherPromotion, UserDiscoveryStore}; +use std::collections::HashMap; +use std::path::PathBuf; + +#[derive(Clone)] +pub(crate) struct UserDiscoveryStoreFlutter {} +pub(crate) struct UserDiscoveryUtilsFlutter {} + +impl UserDiscoveryUtils for UserDiscoveryUtilsFlutter { + async fn sign_data(&self, input_data: &[u8]) -> Result> { + match (get_callbacks()?.user_discovery.sign_data)(input_data.to_vec()).await { + Some(signature) => Ok(signature), + None => Err(TwonlyError::DartError)?, + } + } + + async fn verify_signature( + &self, + input_data: &[u8], + pubkey: &[u8], + signature: &[u8], + ) -> Result { + Ok((get_callbacks()?.user_discovery.verify_signature)( + input_data.to_vec(), + pubkey.to_vec(), + signature.to_vec(), + ) + .await) + } + + async fn verify_stored_pubkey(&self, from_contact_id: i64, pubkey: &[u8]) -> Result { + Ok( + (get_callbacks()?.user_discovery.verify_stored_pubkey)( + from_contact_id, + pubkey.to_vec(), + ) + .await, + ) + } +} + +impl UserDiscoveryStore for UserDiscoveryStoreFlutter { + async fn get_config(&self) -> Result { + let ws = get_twonly_flutter().unwrap(); + let config_path = + PathBuf::from(&ws.config.data_directory).join("user_discovery_config.json"); + + if !config_path.is_file() { + return Err(UserDiscoveryError::NotInitialized); + } + + tracing::debug!("Loading Config from {}", config_path.display()); + Ok(std::fs::read_to_string(&config_path)?) + } + + async fn update_config(&self, update: String) -> Result<()> { + tracing::debug!("Updating configuration file."); + let ws = get_twonly_flutter().unwrap(); + let config_path = + PathBuf::from(&ws.config.data_directory).join("user_discovery_config.json"); + std::fs::write(config_path, &update)?; + Ok(()) + } + + async fn set_shares(&self, shares: Vec>) -> Result<()> { + (get_callbacks()?.user_discovery.set_shares)(shares).await; + Ok(()) + } + + async fn get_share_for_contact(&self, contact_id: i64) -> Result> { + match (get_callbacks()?.user_discovery.get_share_for_contact)(contact_id).await { + Some(share) => Ok(share), + None => Err(UserDiscoveryError::NoSharesLeft), + } + } + + async fn push_own_promotion( + &self, + contact_id: i64, + version: u32, + promotion: Vec, + ) -> Result<()> { + (get_callbacks()?.user_discovery.push_own_promotion)(contact_id, version as i64, promotion) + .await + .then_some(()) + .ok_or(TwonlyError::DartError.into()) + } + + async fn get_own_promotions_after_version(&self, version: u32) -> Result>> { + match (get_callbacks()? + .user_discovery + .get_own_promotions_after_version)(version as i64) + .await + { + Some(share) => Ok(share), + None => Err(TwonlyError::DartError)?, + } + } + + async fn store_other_promotion(&self, promotion: OtherPromotion) -> Result<()> { + (get_callbacks()?.user_discovery.store_other_promotion)(promotion) + .await + .then_some(()) + .ok_or(TwonlyError::DartError.into()) + } + + async fn get_other_promotions_by_public_id( + &self, + public_id: i64, + ) -> Result> { + match (get_callbacks()? + .user_discovery + .get_other_promotions_by_public_id)(public_id) + .await + { + Some(promotions) => Ok(promotions), + None => Err(TwonlyError::DartError)?, + } + } + + async fn get_announced_user_by_public_id( + &self, + public_id: i64, + ) -> Result> { + Ok((get_callbacks()? + .user_discovery + .get_announced_user_by_public_id)(public_id) + .await) + } + + async fn push_new_user_relation( + &self, + from_contact_id: i64, + announced_user: AnnouncedUser, + public_key_verified_timestamp: Option, + ) -> Result<()> { + (get_callbacks()?.user_discovery.push_new_user_relation)( + from_contact_id, + announced_user, + public_key_verified_timestamp, + ) + .await + .then_some(()) + .ok_or(TwonlyError::DartError.into()) + } + + async fn get_all_announced_users( + &self, + ) -> Result)>>> { + // This is never called from the RUST code. + Err(TwonlyError::DartError)? + } + + async fn get_contact_version(&self, contact_id: i64) -> Result>> { + Ok((get_callbacks()?.user_discovery.get_contact_version)(contact_id).await) + } + + async fn set_contact_version(&self, contact_id: i64, update: Vec) -> Result<()> { + (get_callbacks()?.user_discovery.set_contact_version)(contact_id, update) + .await + .then_some(()) + .ok_or(TwonlyError::DartError.into()) + } +} diff --git a/rust/src/bridge/error.rs b/rust/src/bridge/error.rs index b77e8f03..7ad74628 100644 --- a/rust/src/bridge/error.rs +++ b/rust/src/bridge/error.rs @@ -7,9 +7,15 @@ pub type Result = core::result::Result; pub enum TwonlyError { #[error("global twonly is not initialized")] Initialization, + #[error("init_flutter_callbacks was not called")] + MissingCallbackInitialization, #[error("Could not find the given database")] DatabaseNotFound, #[error("{0}")] + UserDiscoveryError(#[from] UserDiscoveryError), + #[error("Error in dart callback")] + DartError, + #[error("{0}")] SqliteError(#[from] sqlx::Error), } diff --git a/rust/src/bridge/log.rs b/rust/src/bridge/log.rs new file mode 100644 index 00000000..db6a0935 --- /dev/null +++ b/rust/src/bridge/log.rs @@ -0,0 +1,73 @@ +use crate::bridge::callbacks::{get_callbacks, log::DartWriter}; +use std::sync::{Mutex, OnceLock}; +use tracing_appender::non_blocking::{NonBlocking, WorkerGuard}; +use tracing_subscriber::{ + fmt::Layer, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry, +}; + +static TRACING_GUARDS: OnceLock>> = OnceLock::new(); +static TRACING_INIT: OnceLock<()> = OnceLock::new(); + +pub(crate) async fn init_tracing(logs_dir: &std::path::Path, is_dart_available: bool) { + let _ = std::fs::create_dir_all(logs_dir); + + let mut dart_sink = None; + + if is_dart_available { + if let Ok(callbacks) = get_callbacks() { + dart_sink = Some((callbacks.logging.get_stream_sink)().await); + } + } + + TRACING_INIT.get_or_init(|| { + let (non_blocking_stdout, _non_blocking_file) = build_writers(logs_dir); + + let stdout_layer = Layer::new() + .with_writer(non_blocking_stdout) + .with_ansi(true) + .with_target(true); + + // let file_layer = Layer::new() + // .with_writer(non_blocking_file) + // .with_ansi(false) + // .with_target(true); + + // Replace stdout with our new DartWriter! + + let registry = Registry::default() + .with( + EnvFilter::try_from_default_env() + .unwrap_or_else(|_| EnvFilter::new("debug,refinery_core=warn,refinery=warn")), + ) + .with(stdout_layer); + + if let Some(sink) = dart_sink { + let dart_writer = DartWriter { sink }; + let dart_layer = tracing_subscriber::fmt::Layer::new() + .with_writer(dart_writer) + .with_ansi(false) + .with_target(true); + let _ = registry.with(dart_layer).try_init(); + } else { + let _ = registry.try_init(); + } + }); +} + +fn build_writers(logs_dir: &std::path::Path) -> (NonBlocking, NonBlocking) { + let file_appender = tracing_appender::rolling::RollingFileAppender::builder() + .rotation(tracing_appender::rolling::Rotation::DAILY) + .filename_prefix("twonly") + .filename_suffix("log") + .build(logs_dir) + .expect("Failed to create file appender"); + + let (non_blocking_file, file_guard) = tracing_appender::non_blocking(file_appender); + let (non_blocking_stdout, stdout_guard) = tracing_appender::non_blocking(std::io::stdout()); + + TRACING_GUARDS + .set(Mutex::new(Some((file_guard, stdout_guard)))) + .ok(); + + (non_blocking_stdout, non_blocking_file) +} diff --git a/rust/src/bridge/log/mod.rs b/rust/src/bridge/log/mod.rs deleted file mode 100644 index 528f989b..00000000 --- a/rust/src/bridge/log/mod.rs +++ /dev/null @@ -1,44 +0,0 @@ -static TRACING_INIT: OnceLock<()> = OnceLock::new(); - -pub(crate) fn init_tracing(logs_dir: &std::path::Path) { - TRACING_INIT.get_or_init(|| { - let (non_blocking_stdout, non_blocking_file) = build_writers(logs_dir); - - let stdout_layer = Layer::new() - .with_writer(non_blocking_stdout) - .with_ansi(true) - .with_target(true); - - let file_layer = Layer::new() - .with_writer(non_blocking_file) - .with_ansi(false) - .with_target(true); - - Registry::default() - .with( - EnvFilter::try_from_default_env() - .unwrap_or_else(|_| EnvFilter::new("info,refinery_core=warn,refinery=warn")), - ) - .with(stdout_layer) - .with(file_layer) - .init(); - }); -} - -fn build_writers(logs_dir: &std::path::Path) -> (NonBlocking, NonBlocking) { - let file_appender = tracing_appender::rolling::RollingFileAppender::builder() - .rotation(tracing_appender::rolling::Rotation::DAILY) - .filename_prefix("twonly") - .filename_suffix("log") - .build(logs_dir) - .expect("Failed to create file appender"); - - let (non_blocking_file, file_guard) = tracing_appender::non_blocking(file_appender); - let (non_blocking_stdout, stdout_guard) = tracing_appender::non_blocking(std::io::stdout()); - - TRACING_GUARDS - .set(Mutex::new(Some((file_guard, stdout_guard)))) - .ok(); - - (non_blocking_stdout, non_blocking_file) -} diff --git a/rust/src/bridge/mod.rs b/rust/src/bridge/mod.rs index fdb518dc..5b5c6422 100644 --- a/rust/src/bridge/mod.rs +++ b/rust/src/bridge/mod.rs @@ -1,18 +1,22 @@ #![allow(unexpected_cfgs)] +pub mod callbacks; pub mod error; -mod user_discovery_utils; -use crate::bridge::user_discovery_utils::UserDiscoveryUtilsFlutter; -use crate::database::contact::Contact; -use crate::database::Database; -use crate::user_discovery_store::UserDiscoveryDatabaseStore; +pub mod log; +pub mod wrapper; + +use crate::bridge::callbacks::user_discovery::{ + UserDiscoveryStoreFlutter, UserDiscoveryUtilsFlutter, +}; +use crate::bridge::log::init_tracing; use crate::utils::Shared; use error::Result; use error::TwonlyError; use flutter_rust_bridge::frb; use protocols::user_discovery::UserDiscovery; -use std::sync::Arc; +use std::path::PathBuf; use tokio::sync::OnceCell; +pub use protocols::user_discovery::traits::AnnouncedUser; pub use protocols::user_discovery::traits::OtherPromotion; #[frb(mirror(OtherPromotion))] @@ -25,34 +29,56 @@ pub struct _OtherPromotion { pub public_key_verified_timestamp: Option, } +#[frb(mirror(AnnouncedUser))] +pub struct _AnnouncedUser { + pub user_id: i64, + pub public_key: Vec, + pub public_id: i64, +} + pub struct TwonlyConfig { pub database_path: String, pub data_directory: String, } -pub(crate) struct Twonly { +pub(crate) struct TwonlyFlutter { #[allow(dead_code)] pub(crate) config: TwonlyConfig, - pub(crate) database: Arc, + // /// Rust runs in the same process as drift, the database can only be opened in readonly mode + // pub(crate) twonly_db_readonly: Arc, pub(crate) user_discovery: - Shared>>, + Shared>, } -static GLOBAL_TWONLY: OnceCell = OnceCell::const_new(); +static GLOBAL_TWONLY: OnceCell = OnceCell::const_new(); -pub(crate) fn get_workspace() -> Result<&'static Twonly> { +pub(super) fn get_twonly_flutter() -> Result<&'static TwonlyFlutter> { GLOBAL_TWONLY.get().ok_or(TwonlyError::Initialization) } -pub async fn initialize_twonly(config: TwonlyConfig) -> Result<()> { - tracing::debug!("Initialized twonly workspace."); - let twonly_res: Result<&'static Twonly> = GLOBAL_TWONLY +pub async fn initialize_twonly_flutter(config: TwonlyConfig) -> Result<()> { + let log_dir = PathBuf::from(&config.data_directory).join("log"); + init_tracing(&log_dir, true).await; + tracing::info!("Initialized twonly workspace."); + let twonly_res: Result<&'static TwonlyFlutter> = GLOBAL_TWONLY .get_or_try_init(|| async { - let database = Arc::new(Database::new(&config.database_path).await?); - Ok(Twonly { + // let database_dir = PathBuf::from(&config.database_path.clone()); + // let Some(rust_db_path) = database_dir.parent() else { + // return Err(TwonlyError::DatabaseNotFound); + // }; + // let rust_db_path = rust_db_path.join("rust_db.sqlite").display().to_string(); + + // let twonly_db_readonly = Arc::new(Database::new(&config.database_path, true).await?); + // let rust_db = Arc::new(Database::new(&rust_db_path, false).await?); + + Ok(TwonlyFlutter { config, - database, - user_discovery: Shared::default(), + // twonly_db_readonly, + // rust_db, + user_discovery: Shared::new(UserDiscovery::new( + UserDiscoveryStoreFlutter {}, + UserDiscoveryUtilsFlutter {}, + )?), }) }) .await; @@ -61,102 +87,3 @@ pub async fn initialize_twonly(config: TwonlyConfig) -> Result<()> { Ok(()) } - -pub async fn get_all_contacts() -> Result> { - let twonly = get_workspace()?; - Contact::get_all_contacts(twonly.database.as_ref()).await -} - -pub fn load_promotions() -> OtherPromotion { - todo!() -} - -#[cfg(test)] -pub(crate) mod tests { - use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; - use tempfile::{NamedTempFile, TempDir}; - use tokio::sync::OnceCell; - - use crate::{database::Database, utils::Shared}; - - use super::error::Result; - use super::Twonly; - use std::{path::PathBuf, sync::Arc}; - use tokio::sync::Mutex; - - use super::{get_workspace, initialize_twonly, TwonlyConfig}; - - static TWONLY_TESTING: [OnceCell; 10] = [ - OnceCell::const_new(), - OnceCell::const_new(), - OnceCell::const_new(), - OnceCell::const_new(), - OnceCell::const_new(), - OnceCell::const_new(), - OnceCell::const_new(), - OnceCell::const_new(), - OnceCell::const_new(), - OnceCell::const_new(), - ]; - - static TWONLY_TESTING_INDEX: OnceCell>> = OnceCell::const_new(); - - pub(crate) async fn initialize_twonly_for_testing(use_global: bool) -> Result<&'static Twonly> { - let default_twonly_database = PathBuf::from("tests/testing.db"); - - if !default_twonly_database.is_file() { - panic!("{} not found!", default_twonly_database.display()) - } - - let temp_file = NamedTempFile::new().unwrap().path().to_owned(); - - tracing::info!("Crated db copy: {}", temp_file.display()); - - let conn = SqlitePoolOptions::new() - .connect_with( - format!("sqlite://{}", default_twonly_database.display()) - .parse::() - .unwrap(), - ) - .await - .unwrap(); - - let path_str = temp_file.display().to_string(); - sqlx::query("VACUUM INTO $1") - .bind(path_str) - .execute(&conn) - .await - .expect("Failed to backup database"); - - let tmp_dir = TempDir::new().unwrap().path().to_owned(); - std::fs::create_dir_all(&tmp_dir).unwrap(); - let config = TwonlyConfig { - database_path: temp_file.display().to_string(), - data_directory: tmp_dir.to_str().unwrap().to_string(), - }; - - if use_global { - initialize_twonly(config).await.unwrap(); - - get_workspace() - } else { - let index = TWONLY_TESTING_INDEX - .get_or_init(|| async { Arc::default() }) - .await; - let mut index = index.lock().await; - let res: Result<&'static Twonly> = TWONLY_TESTING[*index] - .get_or_try_init(|| async { - let database = Arc::new(Database::new(&config.database_path).await?); - Ok(Twonly { - config, - database, - user_discovery: Shared::default(), - }) - }) - .await; - tracing::debug!("TWONLY_TESTING_INDEX: {index}"); - *index += 1; - res - } - } -} diff --git a/rust/src/bridge/user_discovery_utils.rs b/rust/src/bridge/user_discovery_utils.rs deleted file mode 100644 index fe83916e..00000000 --- a/rust/src/bridge/user_discovery_utils.rs +++ /dev/null @@ -1,27 +0,0 @@ -use protocols::user_discovery::error::Result; -use protocols::user_discovery::traits::UserDiscoveryUtils; - -pub(crate) struct UserDiscoveryUtilsFlutter {} - -impl UserDiscoveryUtils for UserDiscoveryUtilsFlutter { - async fn sign_data(&self, input_data: &[u8]) -> Result> { - todo!() - } - - async fn verify_signature( - &self, - input_data: &[u8], - pubkey: &[u8], - signature: &[u8], - ) -> Result { - todo!() - } - - async fn verify_stored_pubkey( - &self, - from_contact_id: protocols::user_discovery::UserID, - pubkey: &[u8], - ) -> Result { - todo!() - } -} diff --git a/rust/src/bridge/wrapper/mod.rs b/rust/src/bridge/wrapper/mod.rs new file mode 100644 index 00000000..16456710 --- /dev/null +++ b/rust/src/bridge/wrapper/mod.rs @@ -0,0 +1 @@ +pub mod user_discovery; diff --git a/rust/src/bridge/wrapper/user_discovery.rs b/rust/src/bridge/wrapper/user_discovery.rs new file mode 100644 index 00000000..6aa24137 --- /dev/null +++ b/rust/src/bridge/wrapper/user_discovery.rs @@ -0,0 +1,61 @@ +use crate::bridge::error::Result; +use crate::bridge::get_twonly_flutter; + +pub struct FlutterUserDiscovery {} + +impl FlutterUserDiscovery { + pub async fn initialize_or_update( + threshold: u8, + user_id: i64, + public_key: Vec, + ) -> Result<()> { + Ok(get_twonly_flutter()? + .user_discovery + .get() + .await + .initialize_or_update(threshold, user_id, public_key) + .await?) + } + + pub async fn get_current_version() -> Result> { + Ok(get_twonly_flutter()? + .user_discovery + .get() + .await + .get_current_version() + .await?) + } + + pub async fn get_new_messages( + contact_id: i64, + received_version: &[u8], + ) -> Result>> { + Ok(get_twonly_flutter()? + .user_discovery + .get() + .await + .get_new_messages(contact_id, received_version) + .await?) + } + + pub async fn should_request_new_messages(contact_id: i64, version: &[u8]) -> Result { + Ok(get_twonly_flutter()? + .user_discovery + .get() + .await + .should_request_new_messages(contact_id, version) + .await?) + } + + pub async fn handle_user_discovery_messages( + contact_id: i64, + messages: Vec>, + ) -> Result<()> { + Ok(get_twonly_flutter()? + .user_discovery + .get() + .await + .handle_user_discovery_messages(contact_id, messages) + .await?) + } +} diff --git a/rust/src/database/contact.rs b/rust/src/database/contact.rs deleted file mode 100644 index f6833366..00000000 --- a/rust/src/database/contact.rs +++ /dev/null @@ -1,58 +0,0 @@ -// use sqlx::types::chrono::{DateTime, Utc}; -use sqlx::FromRow; - -use super::Database; -use crate::bridge::error::Result; - -#[derive(FromRow, Clone, Debug)] -struct ContactRow { - pub(crate) user_id: i64, - pub(crate) username: String, - // pub(crate) created_at: DateTime, -} - -pub struct Contact { - pub user_id: i64, - pub username: String, - // pub created_at: DateTime, -} - -impl From for Contact { - fn from(row: ContactRow) -> Self { - Self { - user_id: row.user_id, - username: row.username, - // created_at: row.created_at, - } - } -} - -impl Contact { - pub(crate) async fn get_all_contacts(db: &Database) -> Result> { - let rows = sqlx::query_as::<_, ContactRow>("SELECT * FROM contacts") - .fetch_all(&db.pool) - .await?; - Ok(rows.into_iter().map(Into::into).collect()) - } -} - -#[cfg(test)] -mod tests { - use crate::bridge::tests::initialize_twonly_for_testing; - use crate::database::contact::Contact; - - #[tokio::test] - async fn test_get_all_contacts() { - let twonly = initialize_twonly_for_testing(true).await.unwrap(); - - let contacts = Contact::get_all_contacts(&twonly.database).await.unwrap(); - - let users = vec!["alice", "bob", "charlie", "david", "frank"]; - - assert_eq!(contacts.len(), users.len()); - - for contact in contacts { - assert_eq!(users[contact.user_id as usize], &contact.username); - } - } -} diff --git a/rust/src/database/mod.rs b/rust/src/database/mod.rs index db873560..4d9f4b71 100644 --- a/rust/src/database/mod.rs +++ b/rust/src/database/mod.rs @@ -1,4 +1,3 @@ -pub(crate) mod contact; use crate::bridge::error::{Result, TwonlyError}; use sqlx::migrate::MigrateDatabase; use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; @@ -10,7 +9,7 @@ pub(crate) struct Database { } impl Database { - pub(crate) async fn new(db_path: &String) -> Result { + pub(crate) async fn new(db_path: &String, read_only: bool) -> Result { let db_url = format!("sqlite://{}", db_path); match Sqlite::database_exists(&db_url).await { @@ -41,6 +40,7 @@ impl Database { let connect_options = format!("{db_url}?mode=rwc") .parse::()? .log_statements(log_statements_level) + .read_only(read_only) .journal_mode(sqlx::sqlite::SqliteJournalMode::Wal) .foreign_keys(true) .busy_timeout(Duration::from_millis(5000)) @@ -53,6 +53,13 @@ impl Database { .connect_with(connect_options) .await?; + let row: (String, String) = sqlx::query_as("SELECT sqlite_version(), sqlite_source_id()") + .fetch_one(&pool) + .await?; + + tracing::info!("Rust SQLite Version: {}", row.0); + tracing::info!("Rust SQLite Source ID: {}", row.1); + Ok(Self { pool: pool }) } } diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs index 6a960195..7776993e 100644 --- a/rust/src/frb_generated.rs +++ b/rust/src/frb_generated.rs @@ -38,7 +38,7 @@ flutter_rust_bridge::frb_generated_boilerplate!( default_rust_auto_opaque = RustAutoOpaqueMoi, ); pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0"; -pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 776002844; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 523281685; // Section: executor @@ -46,42 +46,115 @@ flutter_rust_bridge::frb_generated_default_handler!(); // Section: wire_funcs -fn wire__crate__bridge__get_all_contacts_impl( +fn wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_get_current_version_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, rust_vec_len_: i32, data_len_: i32, ) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::( - flutter_rust_bridge::for_generated::TaskInfo { - debug_name: "get_all_contacts", - port: Some(port_), - mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, - }, - move || { - let message = unsafe { - flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( - ptr_, - rust_vec_len_, - data_len_, - ) - }; - let mut deserializer = - flutter_rust_bridge::for_generated::SseDeserializer::new(message); - deserializer.end(); - move |context| async move { - transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( - (move || async move { - let output_ok = crate::bridge::get_all_contacts().await?; - Ok(output_ok) - })() - .await, - ) - } - }, - ) + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "flutter_user_discovery_get_current_version", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { + let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + deserializer.end(); move |context| async move { + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || async move { + let output_ok = crate::bridge::wrapper::user_discovery::FlutterUserDiscovery::get_current_version().await?; Ok(output_ok) + })().await) + } }) } -fn wire__crate__bridge__initialize_twonly_impl( +fn wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_get_new_messages_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "flutter_user_discovery_get_new_messages", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { + let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_contact_id = ::sse_decode(&mut deserializer); +let api_received_version = >::sse_decode(&mut deserializer);deserializer.end(); move |context| async move { + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || async move { + let output_ok = crate::bridge::wrapper::user_discovery::FlutterUserDiscovery::get_new_messages(api_contact_id, &api_received_version).await?; Ok(output_ok) + })().await) + } }) +} +fn wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_handle_user_discovery_messages_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "flutter_user_discovery_handle_user_discovery_messages", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { + let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_contact_id = ::sse_decode(&mut deserializer); +let api_messages = >>::sse_decode(&mut deserializer);deserializer.end(); move |context| async move { + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || async move { + let output_ok = crate::bridge::wrapper::user_discovery::FlutterUserDiscovery::handle_user_discovery_messages(api_contact_id, api_messages).await?; Ok(output_ok) + })().await) + } }) +} +fn wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_initialize_or_update_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "flutter_user_discovery_initialize_or_update", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { + let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_threshold = ::sse_decode(&mut deserializer); +let api_user_id = ::sse_decode(&mut deserializer); +let api_public_key = >::sse_decode(&mut deserializer);deserializer.end(); move |context| async move { + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || async move { + let output_ok = crate::bridge::wrapper::user_discovery::FlutterUserDiscovery::initialize_or_update(api_threshold, api_user_id, api_public_key).await?; Ok(output_ok) + })().await) + } }) +} +fn wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_should_request_new_messages_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "flutter_user_discovery_should_request_new_messages", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { + let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_contact_id = ::sse_decode(&mut deserializer); +let api_version = >::sse_decode(&mut deserializer);deserializer.end(); move |context| async move { + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || async move { + let output_ok = crate::bridge::wrapper::user_discovery::FlutterUserDiscovery::should_request_new_messages(api_contact_id, &api_version).await?; Ok(output_ok) + })().await) + } }) +} +fn wire__crate__bridge__callbacks__init_flutter_callbacks_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "init_flutter_callbacks", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { + let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_logging_get_stream_sink = decode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_sign_data = decode_DartFn_Inputs_list_prim_u_8_strict_Output_opt_list_prim_u_8_strict_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_verify_signature = decode_DartFn_Inputs_list_prim_u_8_strict_list_prim_u_8_strict_list_prim_u_8_strict_Output_bool_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_verify_stored_pubkey = decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_set_shares = decode_DartFn_Inputs_list_list_prim_u_8_strict_Output_bool_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_get_share_for_contact = decode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_push_own_promotion = decode_DartFn_Inputs_i_64_i_64_list_prim_u_8_strict_Output_bool_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_get_own_promotions_after_version = decode_DartFn_Inputs_i_64_Output_opt_list_list_prim_u_8_strict_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_store_other_promotion = decode_DartFn_Inputs_other_promotion_Output_bool_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_get_other_promotions_by_public_id = decode_DartFn_Inputs_i_64_Output_opt_list_other_promotion_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_get_announced_user_by_public_id = decode_DartFn_Inputs_i_64_Output_opt_box_autoadd_announced_user_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_get_contact_version = decode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_set_contact_version = decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException(::sse_decode(&mut deserializer)); +let api_user_discovery_push_new_user_relation = decode_DartFn_Inputs_i_64_announced_user_opt_box_autoadd_i_64_Output_bool_AnyhowException(::sse_decode(&mut deserializer));deserializer.end(); move |context| async move { + transform_result_sse::<_, ()>((move || async move { + let output_ok = Result::<_,()>::Ok({ crate::bridge::callbacks::init_flutter_callbacks(api_logging_get_stream_sink, api_user_discovery_sign_data, api_user_discovery_verify_signature, api_user_discovery_verify_stored_pubkey, api_user_discovery_set_shares, api_user_discovery_get_share_for_contact, api_user_discovery_push_own_promotion, api_user_discovery_get_own_promotions_after_version, api_user_discovery_store_other_promotion, api_user_discovery_get_other_promotions_by_public_id, api_user_discovery_get_announced_user_by_public_id, api_user_discovery_get_contact_version, api_user_discovery_set_contact_version, api_user_discovery_push_new_user_relation).await; })?; Ok(output_ok) + })().await) + } }) +} +fn wire__crate__bridge__initialize_twonly_flutter_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, rust_vec_len_: i32, @@ -89,7 +162,7 @@ fn wire__crate__bridge__initialize_twonly_impl( ) { FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::( flutter_rust_bridge::for_generated::TaskInfo { - debug_name: "initialize_twonly", + debug_name: "initialize_twonly_flutter", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, }, @@ -108,7 +181,8 @@ fn wire__crate__bridge__initialize_twonly_impl( move |context| async move { transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( (move || async move { - let output_ok = crate::bridge::initialize_twonly(api_config).await?; + let output_ok = + crate::bridge::initialize_twonly_flutter(api_config).await?; Ok(output_ok) })() .await, @@ -117,52 +191,470 @@ fn wire__crate__bridge__initialize_twonly_impl( }, ) } -fn wire__crate__bridge__load_promotions_impl( - port_: flutter_rust_bridge::for_generated::MessagePort, - ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, - rust_vec_len_: i32, - data_len_: i32, -) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( - flutter_rust_bridge::for_generated::TaskInfo { - debug_name: "load_promotions", - port: Some(port_), - mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, - }, - move || { - let message = unsafe { - flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( - ptr_, - rust_vec_len_, - data_len_, - ) - }; - let mut deserializer = - flutter_rust_bridge::for_generated::SseDeserializer::new(message); - deserializer.end(); - move |context| { - transform_result_sse::<_, ()>((move || { - let output_ok = Result::<_, ()>::Ok(crate::bridge::load_promotions())?; - Ok(output_ok) - })()) - } - }, - ) -} // Section: static_checks #[allow(clippy::unnecessary_literal_unwrap)] const _: fn() = || { - let OtherPromotion = None::.unwrap(); - let _: u32 = OtherPromotion.promotion_id; - let _: i64 = OtherPromotion.public_id; - let _: i64 = OtherPromotion.from_contact_id; - let _: u8 = OtherPromotion.threshold; - let _: Vec = OtherPromotion.announcement_share; - let _: Option = OtherPromotion.public_key_verified_timestamp; + { + let AnnouncedUser = None::.unwrap(); + let _: i64 = AnnouncedUser.user_id; + let _: Vec = AnnouncedUser.public_key; + let _: i64 = AnnouncedUser.public_id; + } + { + let OtherPromotion = None::.unwrap(); + let _: u32 = OtherPromotion.promotion_id; + let _: i64 = OtherPromotion.public_id; + let _: i64 = OtherPromotion.from_contact_id; + let _: u8 = OtherPromotion.threshold; + let _: Vec = OtherPromotion.announcement_share; + let _: Option = OtherPromotion.public_key_verified_timestamp; + } }; +// Section: related_funcs + +fn decode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn() -> flutter_rust_bridge::DartFnFuture< + StreamSink, +> { + use flutter_rust_bridge::IntoDart; + + async fn body( + dart_opaque: flutter_rust_bridge::DartOpaque, + ) -> StreamSink { + let args = vec![]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(>::sse_decode(&mut deserializer)), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move || { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body(dart_opaque.clone())) + } +} +fn decode_DartFn_Inputs_i_64_Output_opt_box_autoadd_announced_user_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn(i64) -> flutter_rust_bridge::DartFnFuture> { + use flutter_rust_bridge::IntoDart; + + async fn body( + dart_opaque: flutter_rust_bridge::DartOpaque, + arg0: i64, + ) -> Option { + let args = vec![arg0.into_into_dart().into_dart()]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(>::sse_decode( + &mut deserializer, + )), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move |arg0: i64| { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( + dart_opaque.clone(), + arg0, + )) + } +} +fn decode_DartFn_Inputs_i_64_Output_opt_list_list_prim_u_8_strict_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn(i64) -> flutter_rust_bridge::DartFnFuture>>> { + use flutter_rust_bridge::IntoDart; + + async fn body(dart_opaque: flutter_rust_bridge::DartOpaque, arg0: i64) -> Option>> { + let args = vec![arg0.into_into_dart().into_dart()]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(>>>::sse_decode(&mut deserializer)), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move |arg0: i64| { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( + dart_opaque.clone(), + arg0, + )) + } +} +fn decode_DartFn_Inputs_i_64_Output_opt_list_other_promotion_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn(i64) -> flutter_rust_bridge::DartFnFuture>> { + use flutter_rust_bridge::IntoDart; + + async fn body( + dart_opaque: flutter_rust_bridge::DartOpaque, + arg0: i64, + ) -> Option> { + let args = vec![arg0.into_into_dart().into_dart()]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(>>::sse_decode( + &mut deserializer, + )), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move |arg0: i64| { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( + dart_opaque.clone(), + arg0, + )) + } +} +fn decode_DartFn_Inputs_i_64_Output_opt_list_prim_u_8_strict_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn(i64) -> flutter_rust_bridge::DartFnFuture>> { + use flutter_rust_bridge::IntoDart; + + async fn body(dart_opaque: flutter_rust_bridge::DartOpaque, arg0: i64) -> Option> { + let args = vec![arg0.into_into_dart().into_dart()]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(>>::sse_decode(&mut deserializer)), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move |arg0: i64| { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( + dart_opaque.clone(), + arg0, + )) + } +} +fn decode_DartFn_Inputs_i_64_announced_user_opt_box_autoadd_i_64_Output_bool_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn(i64, crate::bridge::AnnouncedUser, Option) -> flutter_rust_bridge::DartFnFuture +{ + use flutter_rust_bridge::IntoDart; + + async fn body( + dart_opaque: flutter_rust_bridge::DartOpaque, + arg0: i64, + arg1: crate::bridge::AnnouncedUser, + arg2: Option, + ) -> bool { + let args = vec![ + arg0.into_into_dart().into_dart(), + arg1.into_into_dart().into_dart(), + arg2.into_into_dart().into_dart(), + ]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(::sse_decode(&mut deserializer)), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move |arg0: i64, arg1: crate::bridge::AnnouncedUser, arg2: Option| { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( + dart_opaque.clone(), + arg0, + arg1, + arg2, + )) + } +} +fn decode_DartFn_Inputs_i_64_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn(i64, i64, Vec) -> flutter_rust_bridge::DartFnFuture { + use flutter_rust_bridge::IntoDart; + + async fn body( + dart_opaque: flutter_rust_bridge::DartOpaque, + arg0: i64, + arg1: i64, + arg2: Vec, + ) -> bool { + let args = vec![ + arg0.into_into_dart().into_dart(), + arg1.into_into_dart().into_dart(), + arg2.into_into_dart().into_dart(), + ]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(::sse_decode(&mut deserializer)), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move |arg0: i64, arg1: i64, arg2: Vec| { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( + dart_opaque.clone(), + arg0, + arg1, + arg2, + )) + } +} +fn decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_bool_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn(i64, Vec) -> flutter_rust_bridge::DartFnFuture { + use flutter_rust_bridge::IntoDart; + + async fn body(dart_opaque: flutter_rust_bridge::DartOpaque, arg0: i64, arg1: Vec) -> bool { + let args = vec![ + arg0.into_into_dart().into_dart(), + arg1.into_into_dart().into_dart(), + ]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(::sse_decode(&mut deserializer)), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move |arg0: i64, arg1: Vec| { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( + dart_opaque.clone(), + arg0, + arg1, + )) + } +} +fn decode_DartFn_Inputs_list_list_prim_u_8_strict_Output_bool_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn(Vec>) -> flutter_rust_bridge::DartFnFuture { + use flutter_rust_bridge::IntoDart; + + async fn body(dart_opaque: flutter_rust_bridge::DartOpaque, arg0: Vec>) -> bool { + let args = vec![arg0.into_into_dart().into_dart()]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(::sse_decode(&mut deserializer)), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move |arg0: Vec>| { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( + dart_opaque.clone(), + arg0, + )) + } +} +fn decode_DartFn_Inputs_list_prim_u_8_strict_Output_opt_list_prim_u_8_strict_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn(Vec) -> flutter_rust_bridge::DartFnFuture>> { + use flutter_rust_bridge::IntoDart; + + async fn body(dart_opaque: flutter_rust_bridge::DartOpaque, arg0: Vec) -> Option> { + let args = vec![arg0.into_into_dart().into_dart()]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(>>::sse_decode(&mut deserializer)), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move |arg0: Vec| { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( + dart_opaque.clone(), + arg0, + )) + } +} +fn decode_DartFn_Inputs_list_prim_u_8_strict_list_prim_u_8_strict_list_prim_u_8_strict_Output_bool_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn(Vec, Vec, Vec) -> flutter_rust_bridge::DartFnFuture { + use flutter_rust_bridge::IntoDart; + + async fn body( + dart_opaque: flutter_rust_bridge::DartOpaque, + arg0: Vec, + arg1: Vec, + arg2: Vec, + ) -> bool { + let args = vec![ + arg0.into_into_dart().into_dart(), + arg1.into_into_dart().into_dart(), + arg2.into_into_dart().into_dart(), + ]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(::sse_decode(&mut deserializer)), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move |arg0: Vec, arg1: Vec, arg2: Vec| { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( + dart_opaque.clone(), + arg0, + arg1, + arg2, + )) + } +} +fn decode_DartFn_Inputs_other_promotion_Output_bool_AnyhowException( + dart_opaque: flutter_rust_bridge::DartOpaque, +) -> impl Fn(crate::bridge::OtherPromotion) -> flutter_rust_bridge::DartFnFuture { + use flutter_rust_bridge::IntoDart; + + async fn body( + dart_opaque: flutter_rust_bridge::DartOpaque, + arg0: crate::bridge::OtherPromotion, + ) -> bool { + let args = vec![arg0.into_into_dart().into_dart()]; + let message = FLUTTER_RUST_BRIDGE_HANDLER + .dart_fn_invoke(dart_opaque, args) + .await; + + let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let action = deserializer.cursor.read_u8().unwrap(); + let ans = match action { + 0 => std::result::Result::Ok(::sse_decode(&mut deserializer)), + 1 => std::result::Result::Err( + ::sse_decode(&mut deserializer), + ), + _ => unreachable!(), + }; + deserializer.end(); + let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); + ans + } + + move |arg0: crate::bridge::OtherPromotion| { + flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( + dart_opaque.clone(), + arg0, + )) + } +} + // Section: dart2rust impl SseDecode for flutter_rust_bridge::for_generated::anyhow::Error { @@ -173,6 +665,22 @@ impl SseDecode for flutter_rust_bridge::for_generated::anyhow::Error { } } +impl SseDecode for flutter_rust_bridge::DartOpaque { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = ::sse_decode(deserializer); + return unsafe { flutter_rust_bridge::for_generated::sse_decode_dart_opaque(inner) }; + } +} + +impl SseDecode for StreamSink { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = ::sse_decode(deserializer); + return StreamSink::deserialize(inner); + } +} + impl SseDecode for String { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -181,18 +689,34 @@ impl SseDecode for String { } } -impl SseDecode for crate::database::contact::Contact { +impl SseDecode for crate::bridge::AnnouncedUser { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { let mut var_userId = ::sse_decode(deserializer); - let mut var_username = ::sse_decode(deserializer); - return crate::database::contact::Contact { + let mut var_publicKey = >::sse_decode(deserializer); + let mut var_publicId = ::sse_decode(deserializer); + return crate::bridge::AnnouncedUser { user_id: var_userId, - username: var_username, + public_key: var_publicKey, + public_id: var_publicId, }; } } +impl SseDecode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u8().unwrap() != 0 + } +} + +impl SseDecode for crate::bridge::wrapper::user_discovery::FlutterUserDiscovery { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + return crate::bridge::wrapper::user_discovery::FlutterUserDiscovery {}; + } +} + impl SseDecode for i64 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -200,15 +724,32 @@ impl SseDecode for i64 { } } -impl SseDecode for Vec { +impl SseDecode for isize { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_i64::().unwrap() as _ + } +} + +impl SseDecode for Vec> { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { let mut len_ = ::sse_decode(deserializer); let mut ans_ = Vec::with_capacity(len_ as usize); for idx_ in 0..len_ { - ans_.push(::sse_decode( - deserializer, - )); + ans_.push(>::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = Vec::with_capacity(len_ as usize); + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); } return ans_; } @@ -226,6 +767,17 @@ impl SseDecode for Vec { } } +impl SseDecode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + if (::sse_decode(deserializer)) { + return Some(::sse_decode(deserializer)); + } else { + return None; + } + } +} + impl SseDecode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -237,6 +789,41 @@ impl SseDecode for Option { } } +impl SseDecode for Option>> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + if (::sse_decode(deserializer)) { + return Some(>>::sse_decode(deserializer)); + } else { + return None; + } + } +} + +impl SseDecode for Option> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + if (::sse_decode(deserializer)) { + return Some(>::sse_decode( + deserializer, + )); + } else { + return None; + } + } +} + +impl SseDecode for Option> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + if (::sse_decode(deserializer)) { + return Some(>::sse_decode(deserializer)); + } else { + return None; + } + } +} + impl SseDecode for crate::bridge::OtherPromotion { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -288,6 +875,13 @@ impl SseDecode for () { fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {} } +impl SseDecode for usize { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u64::().unwrap() as _ + } +} + impl SseDecode for i32 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -295,13 +889,6 @@ impl SseDecode for i32 { } } -impl SseDecode for bool { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { - deserializer.cursor.read_u8().unwrap() != 0 - } -} - fn pde_ffi_dispatcher_primary_impl( func_id: i32, port: flutter_rust_bridge::for_generated::MessagePort, @@ -311,11 +898,15 @@ fn pde_ffi_dispatcher_primary_impl( ) { // Codec=Pde (Serialization + dispatch), see doc to use other codecs match func_id { - 1 => wire__crate__bridge__get_all_contacts_impl(port, ptr, rust_vec_len, data_len), - 2 => wire__crate__bridge__initialize_twonly_impl(port, ptr, rust_vec_len, data_len), - 3 => wire__crate__bridge__load_promotions_impl(port, ptr, rust_vec_len, data_len), - _ => unreachable!(), - } + 1 => wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_get_current_version_impl(port, ptr, rust_vec_len, data_len), +2 => wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_get_new_messages_impl(port, ptr, rust_vec_len, data_len), +3 => wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_handle_user_discovery_messages_impl(port, ptr, rust_vec_len, data_len), +4 => wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_initialize_or_update_impl(port, ptr, rust_vec_len, data_len), +5 => wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_should_request_new_messages_impl(port, ptr, rust_vec_len, data_len), +6 => wire__crate__bridge__callbacks__init_flutter_callbacks_impl(port, ptr, rust_vec_len, data_len), +7 => wire__crate__bridge__initialize_twonly_flutter_impl(port, ptr, rust_vec_len, data_len), + _ => unreachable!(), + } } fn pde_ffi_dispatcher_sync_impl( @@ -333,23 +924,43 @@ fn pde_ffi_dispatcher_sync_impl( // Section: rust2dart // Codec=Dco (DartCObject based), see doc to use other codecs -impl flutter_rust_bridge::IntoDart for crate::database::contact::Contact { +impl flutter_rust_bridge::IntoDart for FrbWrapper { fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { [ - self.user_id.into_into_dart().into_dart(), - self.username.into_into_dart().into_dart(), + self.0.user_id.into_into_dart().into_dart(), + self.0.public_key.into_into_dart().into_dart(), + self.0.public_id.into_into_dart().into_dart(), ] .into_dart() } } impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive - for crate::database::contact::Contact + for FrbWrapper { } -impl flutter_rust_bridge::IntoIntoDart - for crate::database::contact::Contact +impl flutter_rust_bridge::IntoIntoDart> + for crate::bridge::AnnouncedUser { - fn into_into_dart(self) -> crate::database::contact::Contact { + fn into_into_dart(self) -> FrbWrapper { + self.into() + } +} +// Codec=Dco (DartCObject based), see doc to use other codecs +impl flutter_rust_bridge::IntoDart + for crate::bridge::wrapper::user_discovery::FlutterUserDiscovery +{ + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + Vec::::new().into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive + for crate::bridge::wrapper::user_discovery::FlutterUserDiscovery +{ +} +impl flutter_rust_bridge::IntoIntoDart + for crate::bridge::wrapper::user_discovery::FlutterUserDiscovery +{ + fn into_into_dart(self) -> crate::bridge::wrapper::user_discovery::FlutterUserDiscovery { self } } @@ -407,6 +1018,20 @@ impl SseEncode for flutter_rust_bridge::for_generated::anyhow::Error { } } +impl SseEncode for flutter_rust_bridge::DartOpaque { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.encode(), serializer); + } +} + +impl SseEncode for StreamSink { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + unimplemented!("") + } +} + impl SseEncode for String { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -414,14 +1039,27 @@ impl SseEncode for String { } } -impl SseEncode for crate::database::contact::Contact { +impl SseEncode for crate::bridge::AnnouncedUser { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { ::sse_encode(self.user_id, serializer); - ::sse_encode(self.username, serializer); + >::sse_encode(self.public_key, serializer); + ::sse_encode(self.public_id, serializer); } } +impl SseEncode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u8(self as _).unwrap(); + } +} + +impl SseEncode for crate::bridge::wrapper::user_discovery::FlutterUserDiscovery { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {} +} + impl SseEncode for i64 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -429,12 +1067,32 @@ impl SseEncode for i64 { } } -impl SseEncode for Vec { +impl SseEncode for isize { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer + .cursor + .write_i64::(self as _) + .unwrap(); + } +} + +impl SseEncode for Vec> { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { ::sse_encode(self.len() as _, serializer); for item in self { - ::sse_encode(item, serializer); + >::sse_encode(item, serializer); + } + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); } } } @@ -449,6 +1107,16 @@ impl SseEncode for Vec { } } +impl SseEncode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.is_some(), serializer); + if let Some(value) = self { + ::sse_encode(value, serializer); + } + } +} + impl SseEncode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -459,6 +1127,36 @@ impl SseEncode for Option { } } +impl SseEncode for Option>> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.is_some(), serializer); + if let Some(value) = self { + >>::sse_encode(value, serializer); + } + } +} + +impl SseEncode for Option> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.is_some(), serializer); + if let Some(value) = self { + >::sse_encode(value, serializer); + } + } +} + +impl SseEncode for Option> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.is_some(), serializer); + if let Some(value) = self { + >::sse_encode(value, serializer); + } + } +} + impl SseEncode for crate::bridge::OtherPromotion { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -498,6 +1196,16 @@ impl SseEncode for () { fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {} } +impl SseEncode for usize { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer + .cursor + .write_u64::(self as _) + .unwrap(); + } +} + impl SseEncode for i32 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -505,13 +1213,6 @@ impl SseEncode for i32 { } } -impl SseEncode for bool { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { - serializer.cursor.write_u8(self as _).unwrap(); - } -} - #[cfg(not(target_family = "wasm"))] mod io { // This file is automatically generated, so please do not edit it. diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 519a5714..39c49fb0 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,5 +1,5 @@ pub mod bridge; mod database; mod frb_generated; -mod user_discovery_store; +mod standalone; mod utils; diff --git a/rust/src/standalone/mod.rs b/rust/src/standalone/mod.rs new file mode 100644 index 00000000..09822bc7 --- /dev/null +++ b/rust/src/standalone/mod.rs @@ -0,0 +1,9 @@ +use crate::{bridge::TwonlyConfig, database::Database}; +use std::sync::Arc; + +pub(crate) struct TwonlyStandalone { + #[allow(dead_code)] + pub(crate) config: TwonlyConfig, + /// Because Rust is called from a different process it is safe to write to the twonly_db. + pub(crate) twonly_db: Arc, +} diff --git a/rust/src/user_discovery_store.rs b/rust/src/user_discovery_store.rs deleted file mode 100644 index 1cee04e1..00000000 --- a/rust/src/user_discovery_store.rs +++ /dev/null @@ -1,349 +0,0 @@ -#[allow(async_fn_in_trait)] -use protocols::user_discovery::error::{Result, UserDiscoveryError}; -use protocols::user_discovery::traits::{AnnouncedUser, OtherPromotion, UserDiscoveryStore}; -use protocols::user_discovery::UserID; -use sqlx::{QueryBuilder, Row, Sqlite, Transaction}; -use std::collections::HashMap; -use std::path::PathBuf; -use std::sync::Arc; - -use crate::bridge::error::TwonlyError; -use crate::bridge::{get_workspace, Twonly}; - -#[derive(Clone)] -pub(crate) struct UserDiscoveryDatabaseStore { - ws: Arc<&'static Twonly>, -} - -impl UserDiscoveryStore for UserDiscoveryDatabaseStore { - async fn new() -> Self { - #[cfg(test)] - return Self { - ws: Arc::new( - crate::bridge::tests::initialize_twonly_for_testing(false) - .await - .unwrap(), - ), - }; - #[allow(unreachable_code)] - Self { - ws: Arc::new(get_workspace().unwrap()), - } - } - async fn get_config(&self) -> Result { - let config_path = - PathBuf::from(&self.ws.config.data_directory).join("user_discovery_config.json"); - - if !config_path.is_file() { - return Err(UserDiscoveryError::NotInitialized); - } - - tracing::debug!("Loading Config from {}", config_path.display()); - Ok(std::fs::read_to_string(&config_path)?) - } - - async fn update_config(&self, update: String) -> Result<()> { - tracing::debug!("Updating configuration file."); - let config_path = - PathBuf::from(&self.ws.config.data_directory).join("user_discovery_config.json"); - std::fs::write(config_path, &update)?; - Ok(()) - } - - async fn set_shares(&self, shares: Vec>) -> Result<()> { - let mut query_builder: QueryBuilder = - QueryBuilder::new("INSERT INTO user_discovery_shares (share) "); - - query_builder.push_values(shares, |mut b, share| { - b.push_bind(share); - }); - - query_builder - .build() - .execute(&self.ws.database.pool) - .await - .map_err(TwonlyError::from)?; - - Ok(()) - } - - async fn get_share_for_contact(&self, contact_id: UserID) -> Result> { - let mut tx: Transaction<'_, Sqlite> = self - .ws - .database - .pool - .begin() - .await - .map_err(TwonlyError::from)?; - - // 1. Check if the user already has a share assigned - let existing: Option> = - sqlx::query_scalar("SELECT share FROM user_discovery_shares WHERE contact_id = ?") - .bind(contact_id) - .fetch_optional(&mut *tx) - .await - .map_err(TwonlyError::from)?; - - if let Some(share) = existing { - tx.commit().await.map_err(TwonlyError::from)?; - return Ok(share); - } - - // 2. No share found. Try to assign an available one (where contact_id is NULL) - let rows_affected = sqlx::query( - "UPDATE user_discovery_shares - SET contact_id = ? - WHERE share_id = ( - SELECT share_id FROM user_discovery_shares - WHERE contact_id IS NULL - LIMIT 1 - )", - ) - .bind(contact_id) - .execute(&mut *tx) - .await - .map_err(TwonlyError::from)? - .rows_affected(); - - if rows_affected == 0 { - return Err(UserDiscoveryError::NoSharesLeft); - } - - // 3. Retrieve the newly assigned share - let assigned_share: Vec = - sqlx::query_scalar("SELECT share FROM user_discovery_shares WHERE contact_id = ?") - .bind(contact_id) - .fetch_one(&mut *tx) - .await - .map_err(TwonlyError::from)?; - - tx.commit().await.map_err(TwonlyError::from)?; - Ok(assigned_share) - } - - async fn push_own_promotion( - &self, - contact_id: UserID, - version: u32, - promotion: Vec, - ) -> Result<()> { - sqlx::query( - r#" - INSERT INTO user_discovery_own_promotions (contact_id, promotion, version_id) - VALUES (?1, ?2, ?3) - "#, - ) - .bind(contact_id) - .bind(promotion) - .bind(version as i64) // SQLite integers are usually i32/i64 - .execute(&self.ws.database.pool) - .await - .map_err(TwonlyError::from)?; - Ok(()) - } - - async fn get_own_promotions_after_version(&self, version: u32) -> Result>> { - let promotions: Vec> = sqlx::query_scalar( - "SELECT promotion FROM user_discovery_own_promotions - WHERE version_id > ? - ORDER BY version_id ASC", - ) - .bind(version as i64) - .fetch_all(&self.ws.database.pool) - .await - .map_err(TwonlyError::from)?; - Ok(promotions) - } - - async fn store_other_promotion(&self, promotion: OtherPromotion) -> Result<()> { - sqlx::query( - r" - INSERT INTO user_discovery_other_promotions ( - from_contact_id, - promotion_id, - public_id, - threshold, - announcement_share, - public_key_verified_timestamp - ) - VALUES (?1, ?2, ?3, ?4, ?5, ?6) - ", - ) - .bind(promotion.from_contact_id) - .bind(promotion.promotion_id as i64) - .bind(promotion.public_id) - .bind(promotion.threshold as i64) - .bind(promotion.announcement_share) - .bind(promotion.public_key_verified_timestamp) // Option maps to NULLable - .execute(&self.ws.database.pool) - .await - .map_err(TwonlyError::from)?; - - Ok(()) - } - - async fn get_other_promotions_by_public_id( - &self, - public_id: i64, - ) -> Result> { - let promotions = sqlx::query_as::<_, OtherPromotion>( - "SELECT * FROM user_discovery_other_promotions WHERE public_id = ?", - ) - .bind(public_id) - .fetch_all(&self.ws.database.pool) - .await - .map_err(TwonlyError::from)?; - Ok(promotions) - } - - async fn get_announced_user_by_public_id( - &self, - public_id: i64, - ) -> Result> { - let row = sqlx::query("SELECT * FROM user_discovery_announced_users WHERE public_id = ?") - .bind(public_id) - .fetch_optional(&self.ws.database.pool) - .await - .map_err(TwonlyError::from)?; - match row { - Some(r) => Ok(Some(AnnouncedUser { - user_id: r.get::("announced_user_id"), - public_key: r.get::, _>("announced_public_key"), - public_id: r.get::("public_id"), - })), - None => Ok(None), - } - } - - async fn push_new_user_relation( - &self, - from_contact_id: UserID, - announced_user: AnnouncedUser, - public_key_verified_timestamp: Option, - ) -> Result<()> { - let mut tx = self - .ws - .database - .pool - .begin() - .await - .map_err(TwonlyError::from)?; - - sqlx::query( - r" - INSERT INTO user_discovery_announced_users (announced_user_id, announced_public_key, public_id) - VALUES (?1, ?2, ?3) - ON CONFLICT(announced_user_id) DO NOTHING - ") - .bind(announced_user.user_id) - .bind(announced_user.public_key) - .bind(announced_user.public_id) - .execute(&mut *tx) - .await.map_err(TwonlyError::from)?; - - if from_contact_id != announced_user.user_id { - tracing::debug!( - "INSERTING THAT {} KNOWS {}", - from_contact_id, - announced_user.user_id - ); - sqlx::query( - r"INSERT INTO user_discovery_user_relations ( - announced_user_id, - from_contact_id, - public_key_verified_timestamp - ) - VALUES (?1, ?2, ?3) - ON CONFLICT(announced_user_id, from_contact_id) DO UPDATE SET - public_key_verified_timestamp = excluded.public_key_verified_timestamp - ", - ) - .bind(announced_user.user_id) - .bind(from_contact_id) - .bind(public_key_verified_timestamp) - .execute(&mut *tx) - .await - .map_err(TwonlyError::from)?; - } - - tx.commit().await.map_err(TwonlyError::from)?; - - Ok(()) - } - - async fn get_all_announced_users( - &self, - ) -> Result)>>> { - let rows = sqlx::query( - r#" - SELECT - u.announced_user_id, - u.announced_public_key, - u.public_id, - r.from_contact_id, - r.public_key_verified_timestamp - FROM user_discovery_announced_users u - LEFT JOIN user_discovery_user_relations r - ON u.announced_user_id = r.announced_user_id - ORDER BY u.announced_user_id - "#, - ) - .fetch_all(&self.ws.database.pool) - .await - .map_err(TwonlyError::from)?; - - let mut map: HashMap)>> = HashMap::new(); - - for row in rows { - let announced_user = AnnouncedUser { - user_id: row.get::("announced_user_id"), - public_key: row.get::, _>("announced_public_key"), - public_id: row.get::("public_id"), - }; - - let relations_list = map.entry(announced_user).or_insert_with(Vec::new); - - // SQLX returns NULL for columns in a LEFT JOIN where no match is found. - if let Ok(Some(contact_id)) = row.try_get::, _>("from_contact_id") { - let timestamp = row.get::, _>("public_key_verified_timestamp"); - relations_list.push((contact_id, timestamp)); - } - } - - Ok(map) - } - - async fn get_contact_version(&self, contact_id: UserID) -> Result>> { - let version: Option> = - sqlx::query_scalar("SELECT user_discovery_version FROM contacts WHERE user_id = ?") - .bind(contact_id) - .fetch_optional(&self.ws.database.pool) - .await - .map_err(TwonlyError::from)?; - - Ok(version) - } - - async fn set_contact_version(&self, contact_id: UserID, update: Vec) -> Result<()> { - sqlx::query("UPDATE contacts SET user_discovery_version = ? WHERE user_id = ?") - .bind(update) - .bind(contact_id) - .execute(&self.ws.database.pool) - .await - .map_err(TwonlyError::from)?; - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use crate::user_discovery_store::UserDiscoveryDatabaseStore; - use protocols::user_discovery::tests::test_initialize_user_discovery; - - #[tokio::test] - async fn test_initialize_user_discovery_database_store() { - let _ = pretty_env_logger::try_init(); - test_initialize_user_discovery::().await; - } -} diff --git a/rust/src/utils.rs b/rust/src/utils.rs index 7ec8da6d..c4bba078 100644 --- a/rust/src/utils.rs +++ b/rust/src/utils.rs @@ -1,22 +1,16 @@ -use parking_lot::{RwLock, RwLockReadGuard}; use std::sync::Arc; +use tokio::sync::{RwLock, RwLockReadGuard}; #[derive(Default, Clone)] pub(crate) struct Shared(Arc>); -impl Shared -where - T: Clone, -{ +impl Shared { pub(crate) fn new(value: T) -> Self { Self(Arc::new(RwLock::new(value))) } - pub(crate) fn get(&self) -> RwLockReadGuard<'_, T> { - self.0.read() - } - pub(crate) fn cloned(&self) -> T { - self.0.read().clone() - } - pub(crate) fn set(&self, value: T) { - *self.0.write() = value; + pub(crate) async fn get(&self) -> RwLockReadGuard<'_, T> { + self.0.read().await } + // pub(crate) async fn set(&self, value: T) { + // *self.0.write().await = value; + // } } diff --git a/rust_dependencies/protocols/src/user_discovery/stores/in_memory_store.rs b/rust_dependencies/protocols/src/user_discovery/stores/in_memory_store.rs index e1befe8e..3d3b8450 100644 --- a/rust_dependencies/protocols/src/user_discovery/stores/in_memory_store.rs +++ b/rust_dependencies/protocols/src/user_discovery/stores/in_memory_store.rs @@ -27,9 +27,6 @@ impl InMemoryStore { } impl UserDiscoveryStore for InMemoryStore { - async fn new() -> Self { - Self::default() - } async fn get_config(&self) -> Result { if let Some(storage) = self.storage().config.clone() { return Ok(storage); diff --git a/rust_dependencies/protocols/src/user_discovery/tests.rs b/rust_dependencies/protocols/src/user_discovery/tests.rs index 58b957af..43b7db1f 100644 --- a/rust_dependencies/protocols/src/user_discovery/tests.rs +++ b/rust_dependencies/protocols/src/user_discovery/tests.rs @@ -12,8 +12,10 @@ fn get_version_bytes(announcement: u32, promotion: u32) -> Vec { .encode_to_vec() } -async fn get_ud(user_id: usize) -> UserDiscovery { - let store = S::new().await; +async fn get_ud( + user_id: usize, +) -> UserDiscovery { + let store = S::default(); let ud = UserDiscovery::new(store.to_owned(), TestingUtils::default()).unwrap(); ud.initialize_or_update(2, user_id as UserID, vec![user_id as u8; 32]) @@ -97,7 +99,7 @@ struct TestUsers { uds: Vec>, } -impl TestUsers { +impl TestUsers { async fn get() -> Self { let names = ["ALICE", "BOB", "CHARLIE", "DAVID", "FRANK"]; let mut uds = vec![]; @@ -119,7 +121,7 @@ impl TestUsers { } } -pub async fn test_initialize_user_discovery() { +pub async fn test_initialize_user_discovery() { #[cfg(test)] let _ = pretty_env_logger::try_init(); diff --git a/rust_dependencies/protocols/src/user_discovery/traits.rs b/rust_dependencies/protocols/src/user_discovery/traits.rs index 8e88573a..8c4c51d3 100644 --- a/rust_dependencies/protocols/src/user_discovery/traits.rs +++ b/rust_dependencies/protocols/src/user_discovery/traits.rs @@ -22,7 +22,6 @@ pub struct AnnouncedUser { } pub trait UserDiscoveryStore { - fn new() -> impl std::future::Future + Send; fn get_config(&self) -> impl Future> + Send; fn update_config(&self, update: String) -> impl Future> + Send; fn set_shares(&self, shares: Vec>) -> impl Future> + Send; @@ -88,6 +87,9 @@ pub trait UserDiscoveryUtils { pubkey: &[u8], signature: &[u8], ) -> impl Future> + Send; + /// In case the the user does not exists yet return false. + /// If this happens this should trigger an error, as this functions is only when a message was received from this user... + /// This is used to verify that the share of the promotions contains the same public key and the user is not secretly announcing a different one fn verify_stored_pubkey( &self, from_contact_id: UserID, From 2ec8d144398b2657f7c22a28f2962c3e5fed98cc Mon Sep 17 00:00:00 2001 From: otsmr Date: Sun, 19 Apr 2026 20:41:10 +0200 Subject: [PATCH 11/86] delete receipts where the message got deleted --- lib/src/services/api/mediafiles/upload.service.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/src/services/api/mediafiles/upload.service.dart b/lib/src/services/api/mediafiles/upload.service.dart index 806bce57..db485966 100644 --- a/lib/src/services/api/mediafiles/upload.service.dart +++ b/lib/src/services/api/mediafiles/upload.service.dart @@ -102,6 +102,12 @@ Future reuploadMediaFiles() async { .getMessageById(messageId) .getSingleOrNull(); if (message == null || message.mediaId == null) { + // The message or media file does not exists any more, so delete the receipt... + if (message != null) { + // The media file of the message does not exist anymore. Removing it... + await twonlyDB.messagesDao.deleteMessagesById(messageId); + } + await twonlyDB.receiptsDao.deleteReceipt(receipt.receiptId); Log.error( 'Message not found for reupload of the receipt (${message == null} - ${message?.mediaId}).', ); From cd2a254d233fb8fb1c35d15a98752502dd84e9ca Mon Sep 17 00:00:00 2001 From: otsmr Date: Sun, 19 Apr 2026 21:00:40 +0200 Subject: [PATCH 12/86] fix: issue with image could not be inserted --- lib/src/database/daos/mediafiles.dao.dart | 8 ++++---- lib/src/services/api/client2client/media.c2c.dart | 10 +++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/src/database/daos/mediafiles.dao.dart b/lib/src/database/daos/mediafiles.dao.dart index 01752edd..5ff7cb67 100644 --- a/lib/src/database/daos/mediafiles.dao.dart +++ b/lib/src/database/daos/mediafiles.dao.dart @@ -24,13 +24,13 @@ class MediaFilesDao extends DatabaseAccessor ); } - final rowId = await into( - mediaFiles, - ).insertOnConflictUpdate(insertMediaFile); + await into(mediaFiles).insertOnConflictUpdate(insertMediaFile); + + final mediaId = insertMediaFile.mediaId.value; return await (select( mediaFiles, - )..where((t) => t.rowId.equals(rowId))).getSingle(); + )..where((t) => t.mediaId.equals(mediaId))).getSingle(); } catch (e) { Log.error('Could not insert media file: $e'); return null; diff --git a/lib/src/services/api/client2client/media.c2c.dart b/lib/src/services/api/client2client/media.c2c.dart index 4f08d913..496ac0bc 100644 --- a/lib/src/services/api/client2client/media.c2c.dart +++ b/lib/src/services/api/client2client/media.c2c.dart @@ -117,8 +117,8 @@ Future handleMedia( } } - late MediaFile? mediaFile; - late Message? message; + MediaFile? mediaFile; + Message? message; await twonlyDB.transaction(() async { mediaFile = await twonlyDB.mediaFilesDao.insertOrUpdateMedia( @@ -163,7 +163,7 @@ Future handleMedia( ); }); - if (message != null) { + if (message != null && mediaFile != null) { await twonlyDB.groupsDao.increaseLastMessageExchange( groupId, fromTimestamp(media.timestamp), @@ -176,6 +176,10 @@ Future handleMedia( ); unawaited(startDownloadMedia(mediaFile!, false)); + } else { + Log.error( + 'Could not insert new message as both the message and mediaFile are empty.', + ); } } From 1629b8b1a905b883b154f335dbc5afb5b019288a Mon Sep 17 00:00:00 2001 From: otsmr Date: Sun, 19 Apr 2026 22:57:24 +0200 Subject: [PATCH 13/86] add user discovery settings view --- lib/src/database/daos/contacts.dao.dart | 11 + .../schemas/twonly_db/drift_schema_v13.json | 2675 +++++ lib/src/database/tables/contacts.table.dart | 4 + lib/src/database/twonly.db.dart | 12 +- lib/src/database/twonly.db.g.dart | 152 +- lib/src/database/twonly.db.steps.dart | 461 + lib/src/model/json/userdata.dart | 5 +- lib/src/model/json/userdata.g.dart | 6 + .../generated/user_discovery/types.pb.dart | 695 ++ .../user_discovery/types.pbenum.dart | 11 + .../user_discovery/types.pbjson.dart | 207 + lib/src/services/flame.service.dart | 19 + lib/src/services/user_discovery.service.dart | 57 +- lib/src/themes/light.dart | 25 +- lib/src/utils/misc.dart | 3 - .../user_discovery_disabled.component.dart | 6 +- .../user_discovery_enabled.component.dart | 109 +- .../user_discovery_settings.view.dart | 137 + scripts/generate_proto.sh | 3 + test/drift/twonly_db/generated/schema.dart | 5 +- .../drift/twonly_db/generated/schema_v13.dart | 9439 +++++++++++++++++ 21 files changed, 13992 insertions(+), 50 deletions(-) create mode 100644 lib/src/database/schemas/twonly_db/drift_schema_v13.json create mode 100644 lib/src/model/protobuf/client/generated/user_discovery/types.pb.dart create mode 100644 lib/src/model/protobuf/client/generated/user_discovery/types.pbenum.dart create mode 100644 lib/src/model/protobuf/client/generated/user_discovery/types.pbjson.dart create mode 100644 lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart create mode 100644 test/drift/twonly_db/generated/schema_v13.dart diff --git a/lib/src/database/daos/contacts.dao.dart b/lib/src/database/daos/contacts.dao.dart index ce26eb2a..272b8ce4 100644 --- a/lib/src/database/daos/contacts.dao.dart +++ b/lib/src/database/daos/contacts.dao.dart @@ -134,6 +134,17 @@ class ContactsDao extends DatabaseAccessor with _$ContactsDaoMixin { .watch(); } + Stream> watchContactsAnnouncedViaUserDiscovery() { + return (select(contacts)..where( + (t) => + t.userDiscoveryVersion.isNotNull() & + t.mediaSendCounter.isBiggerOrEqualValue( + gUser.minimumRequiredImagesExchanged, + ), + )) + .watch(); + } + Stream> watchAllContacts() { return select(contacts).watch(); } diff --git a/lib/src/database/schemas/twonly_db/drift_schema_v13.json b/lib/src/database/schemas/twonly_db/drift_schema_v13.json new file mode 100644 index 00000000..b9e1f48b --- /dev/null +++ b/lib/src/database/schemas/twonly_db/drift_schema_v13.json @@ -0,0 +1,2675 @@ +{ + "_meta": { + "description": "This file contains a serialized version of schema entities for drift.", + "version": "1.3.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, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "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_compressed", + "getter_name": "avatarSvgCompressed", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_profile_counter", + "getter_name": "senderProfileCounter", + "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": "deleted_by_user", + "getter_name": "deletedByUser", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"deleted_by_user\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"deleted_by_user\" 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": "account_deleted", + "getter_name": "accountDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"account_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"account_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "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": "user_discovery_version", + "getter_name": "userDiscoveryVersion", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "media_send_counter", + "getter_name": "mediaSendCounter", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "media_received_counter", + "getter_name": "mediaReceivedCounter", + "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": [], + "type": "table", + "data": { + "name": "groups", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_group_admin", + "getter_name": "isGroupAdmin", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_group_admin\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_group_admin\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_direct_chat", + "getter_name": "isDirectChat", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_direct_chat\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_direct_chat\" 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": "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": "joined_group", + "getter_name": "joinedGroup", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"joined_group\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"joined_group\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "left_group", + "getter_name": "leftGroup", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"left_group\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"left_group\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "deleted_content", + "getter_name": "deletedContent", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"deleted_content\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"deleted_content\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "state_version_id", + "getter_name": "stateVersionId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "state_encryption_key", + "getter_name": "stateEncryptionKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "my_group_private_key", + "getter_name": "myGroupPrivateKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "group_name", + "getter_name": "groupName", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "draft_message", + "getter_name": "draftMessage", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "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": "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_milliseconds", + "getter_name": "deleteMessagesAfterMilliseconds", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('86400000')", + "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": "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": "flame_counter", + "getter_name": "flameCounter", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "max_flame_counter", + "getter_name": "maxFlameCounter", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "max_flame_counter_from", + "getter_name": "maxFlameCounterFrom", + "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": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "group_id" + ] + } + }, + { + "id": 2, + "references": [], + "type": "table", + "data": { + "name": "media_files", + "was_declared_in_moor": false, + "columns": [ + { + "name": "media_id", + "getter_name": "mediaId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MediaType.values)", + "dart_type_name": "MediaType" + } + }, + { + "name": "upload_state", + "getter_name": "uploadState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(UploadState.values)", + "dart_type_name": "UploadState" + } + }, + { + "name": "download_state", + "getter_name": "downloadState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(DownloadState.values)", + "dart_type_name": "DownloadState" + } + }, + { + "name": "requires_authentication", + "getter_name": "requiresAuthentication", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"requires_authentication\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"requires_authentication\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "stored", + "getter_name": "stored", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"stored\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"stored\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_draft_media", + "getter_name": "isDraftMedia", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_draft_media\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_draft_media\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pre_progressing_process", + "getter_name": "preProgressingProcess", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "reupload_requested_by", + "getter_name": "reuploadRequestedBy", + "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": "display_limit_in_milliseconds", + "getter_name": "displayLimitInMilliseconds", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "remove_audio", + "getter_name": "removeAudio", + "moor_type": "bool", + "nullable": true, + "customConstraints": null, + "defaultConstraints": "CHECK (\"remove_audio\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"remove_audio\" IN (0, 1))" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "download_token", + "getter_name": "downloadToken", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_key", + "getter_name": "encryptionKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_mac", + "getter_name": "encryptionMac", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_nonce", + "getter_name": "encryptionNonce", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "stored_file_hash", + "getter_name": "storedFileHash", + "moor_type": "blob", + "nullable": true, + "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": [ + "media_id" + ] + } + }, + { + "id": 3, + "references": [ + 1, + 0, + 2 + ], + "type": "table", + "data": { + "name": "messages", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_id", + "getter_name": "senderId", + "moor_type": "int", + "nullable": true, + "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "content", + "getter_name": "content", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "media_id", + "getter_name": "mediaId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "defaultConstraints": "REFERENCES media_files (media_id) ON DELETE SET NULL", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES media_files (media_id) ON DELETE SET NULL" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "media_files", + "column": "media_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "setNull" + } + } + ] + }, + { + "name": "additional_message_data", + "getter_name": "additionalMessageData", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "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": "media_reopened", + "getter_name": "mediaReopened", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"media_reopened\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"media_reopened\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "download_token", + "getter_name": "downloadToken", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quotes_message_id", + "getter_name": "quotesMessageId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted_from_sender", + "getter_name": "isDeletedFromSender", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted_from_sender\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted_from_sender\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "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": "opened_by_all", + "getter_name": "openedByAll", + "moor_type": "dateTime", + "nullable": true, + "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": [] + }, + { + "name": "modified_at", + "getter_name": "modifiedAt", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_user", + "getter_name": "ackByUser", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_server", + "getter_name": "ackByServer", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "message_id" + ] + } + }, + { + "id": 4, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "message_histories", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "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_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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": "content", + "getter_name": "content", + "moor_type": "string", + "nullable": true, + "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": [] + } + }, + { + "id": 5, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "reactions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "emoji", + "getter_name": "emoji", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_id", + "getter_name": "senderId", + "moor_type": "int", + "nullable": true, + "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": "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": [ + "message_id", + "sender_id", + "emoji" + ] + } + }, + { + "id": 6, + "references": [ + 1, + 0 + ], + "type": "table", + "data": { + "name": "group_members", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "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": "member_state", + "getter_name": "memberState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MemberState.values)", + "dart_type_name": "MemberState" + } + }, + { + "name": "group_public_key", + "getter_name": "groupPublicKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_chat_opened", + "getter_name": "lastChatOpened", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_type_indicator", + "getter_name": "lastTypeIndicator", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_message", + "getter_name": "lastMessage", + "moor_type": "dateTime", + "nullable": true, + "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": [ + "group_id", + "contact_id" + ] + } + }, + { + "id": 7, + "references": [ + 0, + 3 + ], + "type": "table", + "data": { + "name": "receipts", + "was_declared_in_moor": false, + "columns": [ + { + "name": "receipt_id", + "getter_name": "receiptId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "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": "string", + "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": "message", + "getter_name": "message", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "contact_will_sends_receipt", + "getter_name": "contactWillSendsReceipt", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"contact_will_sends_receipt\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"contact_will_sends_receipt\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "will_be_retried_by_media_upload", + "getter_name": "willBeRetriedByMediaUpload", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"will_be_retried_by_media_upload\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"will_be_retried_by_media_upload\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mark_for_retry", + "getter_name": "markForRetry", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mark_for_retry_after_accepted", + "getter_name": "markForRetryAfterAccepted", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_server_at", + "getter_name": "ackByServerAt", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "retry_count", + "getter_name": "retryCount", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_retry", + "getter_name": "lastRetry", + "moor_type": "dateTime", + "nullable": true, + "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": [ + "receipt_id" + ] + } + }, + { + "id": 8, + "references": [], + "type": "table", + "data": { + "name": "received_receipts", + "was_declared_in_moor": false, + "columns": [ + { + "name": "receipt_id", + "getter_name": "receiptId", + "moor_type": "string", + "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": [ + "receipt_id" + ] + } + }, + { + "id": 9, + "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": 10, + "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": 11, + "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": 12, + "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": 13, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "message_actions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MessageActionType.values)", + "dart_type_name": "MessageActionType" + } + }, + { + "name": "action_at", + "getter_name": "actionAt", + "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": [ + "message_id", + "contact_id", + "type" + ] + } + }, + { + "id": 14, + "references": [ + 1, + 0 + ], + "type": "table", + "data": { + "name": "group_histories", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_history_id", + "getter_name": "groupHistoryId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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": "affected_contact_id", + "getter_name": "affectedContactId", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "old_group_name", + "getter_name": "oldGroupName", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "new_group_name", + "getter_name": "newGroupName", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "new_delete_messages_after_milliseconds", + "getter_name": "newDeleteMessagesAfterMilliseconds", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(GroupActionType.values)", + "dart_type_name": "GroupActionType" + } + }, + { + "name": "action_at", + "getter_name": "actionAt", + "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": [ + "group_history_id" + ] + } + }, + { + "id": 15, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "key_verifications", + "was_declared_in_moor": false, + "columns": [ + { + "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(VerificationType.values)", + "dart_type_name": "VerificationType" + } + }, + { + "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": 16, + "references": [], + "type": "table", + "data": { + "name": "verification_tokens", + "was_declared_in_moor": false, + "columns": [ + { + "name": "token_id", + "getter_name": "tokenId", + "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": "token", + "getter_name": "token", + "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": [] + } + }, + { + "id": 17, + "references": [], + "type": "table", + "data": { + "name": "user_discovery_announced_users", + "was_declared_in_moor": false, + "columns": [ + { + "name": "announced_user_id", + "getter_name": "announcedUserId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "announced_public_key", + "getter_name": "announcedPublicKey", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_id", + "getter_name": "publicId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "UNIQUE", + "dialectAwareDefaultConstraints": { + "sqlite": "UNIQUE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + "unique" + ] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "announced_user_id" + ] + } + }, + { + "id": 18, + "references": [ + 17, + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_user_relations", + "was_declared_in_moor": false, + "columns": [ + { + "name": "announced_user_id", + "getter_name": "announcedUserId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "user_discovery_announced_users", + "column": "announced_user_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "from_contact_id", + "getter_name": "fromContactId", + "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": "public_key_verified_timestamp", + "getter_name": "publicKeyVerifiedTimestamp", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "announced_user_id", + "from_contact_id" + ] + } + }, + { + "id": 19, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_other_promotions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "from_contact_id", + "getter_name": "fromContactId", + "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": "promotion_id", + "getter_name": "promotionId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_id", + "getter_name": "publicId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "threshold", + "getter_name": "threshold", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "announcement_share", + "getter_name": "announcementShare", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_key_verified_timestamp", + "getter_name": "publicKeyVerifiedTimestamp", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "from_contact_id", + "promotion_id" + ] + } + }, + { + "id": 20, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_own_promotions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "version_id", + "getter_name": "versionId", + "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": "promotion", + "getter_name": "promotion", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [] + } + }, + { + "id": 21, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_shares", + "was_declared_in_moor": false, + "columns": [ + { + "name": "share_id", + "getter_name": "shareId", + "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": "share", + "getter_name": "share", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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" + } + } + ] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [] + } + } + ], + "fixed_sql": [ + { + "name": "contacts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"contacts\" (\"user_id\" INTEGER NOT NULL, \"username\" TEXT NOT NULL, \"display_name\" TEXT NULL, \"nick_name\" TEXT NULL, \"avatar_svg_compressed\" BLOB NULL, \"sender_profile_counter\" INTEGER NOT NULL DEFAULT 0, \"accepted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"accepted\" IN (0, 1)), \"deleted_by_user\" INTEGER NOT NULL DEFAULT 0 CHECK (\"deleted_by_user\" IN (0, 1)), \"requested\" INTEGER NOT NULL DEFAULT 0 CHECK (\"requested\" IN (0, 1)), \"blocked\" INTEGER NOT NULL DEFAULT 0 CHECK (\"blocked\" IN (0, 1)), \"verified\" INTEGER NOT NULL DEFAULT 0 CHECK (\"verified\" IN (0, 1)), \"account_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"account_deleted\" IN (0, 1)), \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"user_discovery_version\" BLOB NULL, \"media_send_counter\" INTEGER NOT NULL DEFAULT 0, \"media_received_counter\" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (\"user_id\"));" + } + ] + }, + { + "name": "groups", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"groups\" (\"group_id\" TEXT NOT NULL, \"is_group_admin\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_group_admin\" IN (0, 1)), \"is_direct_chat\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_direct_chat\" IN (0, 1)), \"pinned\" INTEGER NOT NULL DEFAULT 0 CHECK (\"pinned\" IN (0, 1)), \"archived\" INTEGER NOT NULL DEFAULT 0 CHECK (\"archived\" IN (0, 1)), \"joined_group\" INTEGER NOT NULL DEFAULT 0 CHECK (\"joined_group\" IN (0, 1)), \"left_group\" INTEGER NOT NULL DEFAULT 0 CHECK (\"left_group\" IN (0, 1)), \"deleted_content\" INTEGER NOT NULL DEFAULT 0 CHECK (\"deleted_content\" IN (0, 1)), \"state_version_id\" INTEGER NOT NULL DEFAULT 0, \"state_encryption_key\" BLOB NULL, \"my_group_private_key\" BLOB NULL, \"group_name\" TEXT NOT NULL, \"draft_message\" TEXT NULL, \"total_media_counter\" INTEGER NOT NULL DEFAULT 0, \"also_best_friend\" INTEGER NOT NULL DEFAULT 0 CHECK (\"also_best_friend\" IN (0, 1)), \"delete_messages_after_milliseconds\" INTEGER NOT NULL DEFAULT 86400000, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"last_message_send\" INTEGER NULL, \"last_message_received\" INTEGER NULL, \"last_flame_counter_change\" INTEGER NULL, \"last_flame_sync\" INTEGER NULL, \"flame_counter\" INTEGER NOT NULL DEFAULT 0, \"max_flame_counter\" INTEGER NOT NULL DEFAULT 0, \"max_flame_counter_from\" INTEGER NULL, \"last_message_exchange\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_id\"));" + } + ] + }, + { + "name": "media_files", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"media_files\" (\"media_id\" TEXT NOT NULL, \"type\" TEXT NOT NULL, \"upload_state\" TEXT NULL, \"download_state\" TEXT NULL, \"requires_authentication\" INTEGER NOT NULL DEFAULT 0 CHECK (\"requires_authentication\" IN (0, 1)), \"stored\" INTEGER NOT NULL DEFAULT 0 CHECK (\"stored\" IN (0, 1)), \"is_draft_media\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_draft_media\" IN (0, 1)), \"pre_progressing_process\" INTEGER NULL, \"reupload_requested_by\" TEXT NULL, \"display_limit_in_milliseconds\" INTEGER NULL, \"remove_audio\" INTEGER NULL CHECK (\"remove_audio\" IN (0, 1)), \"download_token\" BLOB NULL, \"encryption_key\" BLOB NULL, \"encryption_mac\" BLOB NULL, \"encryption_nonce\" BLOB NULL, \"stored_file_hash\" BLOB NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"media_id\"));" + } + ] + }, + { + "name": "messages", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"messages\" (\"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"message_id\" TEXT NOT NULL, \"sender_id\" INTEGER NULL REFERENCES contacts (user_id), \"type\" TEXT NOT NULL, \"content\" TEXT NULL, \"media_id\" TEXT NULL REFERENCES media_files (media_id) ON DELETE SET NULL, \"additional_message_data\" BLOB NULL, \"media_stored\" INTEGER NOT NULL DEFAULT 0 CHECK (\"media_stored\" IN (0, 1)), \"media_reopened\" INTEGER NOT NULL DEFAULT 0 CHECK (\"media_reopened\" IN (0, 1)), \"download_token\" BLOB NULL, \"quotes_message_id\" TEXT NULL, \"is_deleted_from_sender\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted_from_sender\" IN (0, 1)), \"opened_at\" INTEGER NULL, \"opened_by_all\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"modified_at\" INTEGER NULL, \"ack_by_user\" INTEGER NULL, \"ack_by_server\" INTEGER NULL, PRIMARY KEY (\"message_id\"));" + } + ] + }, + { + "name": "message_histories", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"message_histories\" (\"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"content\" TEXT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)));" + } + ] + }, + { + "name": "reactions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"reactions\" (\"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"emoji\" TEXT NOT NULL, \"sender_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"message_id\", \"sender_id\", \"emoji\"));" + } + ] + }, + { + "name": "group_members", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"group_members\" (\"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id), \"member_state\" TEXT NULL, \"group_public_key\" BLOB NULL, \"last_chat_opened\" INTEGER NULL, \"last_type_indicator\" INTEGER NULL, \"last_message\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_id\", \"contact_id\"));" + } + ] + }, + { + "name": "receipts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"receipts\" (\"receipt_id\" TEXT NOT NULL, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"message_id\" TEXT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"message\" BLOB NOT NULL, \"contact_will_sends_receipt\" INTEGER NOT NULL DEFAULT 1 CHECK (\"contact_will_sends_receipt\" IN (0, 1)), \"will_be_retried_by_media_upload\" INTEGER NOT NULL DEFAULT 0 CHECK (\"will_be_retried_by_media_upload\" IN (0, 1)), \"mark_for_retry\" INTEGER NULL, \"mark_for_retry_after_accepted\" INTEGER NULL, \"ack_by_server_at\" INTEGER NULL, \"retry_count\" INTEGER NOT NULL DEFAULT 0, \"last_retry\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"receipt_id\"));" + } + ] + }, + { + "name": "received_receipts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"received_receipts\" (\"receipt_id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"receipt_id\"));" + } + ] + }, + { + "name": "signal_identity_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_identity_key_stores\" (\"device_id\" INTEGER NOT NULL, \"name\" TEXT NOT NULL, \"identity_key\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"device_id\", \"name\"));" + } + ] + }, + { + "name": "signal_pre_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_pre_key_stores\" (\"pre_key_id\" INTEGER NOT NULL, \"pre_key\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"pre_key_id\"));" + } + ] + }, + { + "name": "signal_sender_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_sender_key_stores\" (\"sender_key_name\" TEXT NOT NULL, \"sender_key\" BLOB NOT NULL, PRIMARY KEY (\"sender_key_name\"));" + } + ] + }, + { + "name": "signal_session_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_session_stores\" (\"device_id\" INTEGER NOT NULL, \"name\" TEXT NOT NULL, \"session_record\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"device_id\", \"name\"));" + } + ] + }, + { + "name": "message_actions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"message_actions\" (\"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"type\" TEXT NOT NULL, \"action_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"message_id\", \"contact_id\", \"type\"));" + } + ] + }, + { + "name": "group_histories", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"group_histories\" (\"group_history_id\" TEXT NOT NULL, \"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id), \"affected_contact_id\" INTEGER NULL, \"old_group_name\" TEXT NULL, \"new_group_name\" TEXT NULL, \"new_delete_messages_after_milliseconds\" INTEGER NULL, \"type\" TEXT NOT NULL, \"action_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_history_id\"));" + } + ] + }, + { + "name": "key_verifications", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"key_verifications\" (\"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"type\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"contact_id\"));" + } + ] + }, + { + "name": "verification_tokens", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"verification_tokens\" (\"token_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"token\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)));" + } + ] + }, + { + "name": "user_discovery_announced_users", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_announced_users\" (\"announced_user_id\" INTEGER NOT NULL, \"announced_public_key\" BLOB NOT NULL, \"public_id\" INTEGER NOT NULL UNIQUE, PRIMARY KEY (\"announced_user_id\"));" + } + ] + }, + { + "name": "user_discovery_user_relations", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_user_relations\" (\"announced_user_id\" INTEGER NOT NULL REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE, \"from_contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"public_key_verified_timestamp\" INTEGER NULL, PRIMARY KEY (\"announced_user_id\", \"from_contact_id\"));" + } + ] + }, + { + "name": "user_discovery_other_promotions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_other_promotions\" (\"from_contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"promotion_id\" INTEGER NOT NULL, \"public_id\" INTEGER NOT NULL, \"threshold\" INTEGER NOT NULL, \"announcement_share\" BLOB NOT NULL, \"public_key_verified_timestamp\" INTEGER NULL, PRIMARY KEY (\"from_contact_id\", \"promotion_id\"));" + } + ] + }, + { + "name": "user_discovery_own_promotions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_own_promotions\" (\"version_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"promotion\" BLOB NOT NULL);" + } + ] + }, + { + "name": "user_discovery_shares", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_shares\" (\"share_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"share\" BLOB NOT NULL, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE);" + } + ] + } + ] +} \ No newline at end of file diff --git a/lib/src/database/tables/contacts.table.dart b/lib/src/database/tables/contacts.table.dart index c66cf61c..3d321c45 100644 --- a/lib/src/database/tables/contacts.table.dart +++ b/lib/src/database/tables/contacts.table.dart @@ -26,6 +26,10 @@ class Contacts extends Table { // contact_versions: HashMap>, BlobColumn get userDiscoveryVersion => blob().nullable()(); + IntColumn get mediaSendCounter => integer().withDefault(const Constant(0))(); + IntColumn get mediaReceivedCounter => + integer().withDefault(const Constant(0))(); + @override Set get primaryKey => {userId}; } diff --git a/lib/src/database/twonly.db.dart b/lib/src/database/twonly.db.dart index bf28d801..44e7f9f6 100644 --- a/lib/src/database/twonly.db.dart +++ b/lib/src/database/twonly.db.dart @@ -72,7 +72,7 @@ class TwonlyDB extends _$TwonlyDB { TwonlyDB.forTesting(DatabaseConnection super.connection); @override - int get schemaVersion => 12; + int get schemaVersion => 13; static QueryExecutor _openConnection() { return driftDatabase( @@ -181,6 +181,16 @@ class TwonlyDB extends _$TwonlyDB { schema.contacts.userDiscoveryVersion, ); }, + from12To13: (m, schema) async { + await m.addColumn( + schema.contacts, + schema.contacts.mediaReceivedCounter, + ); + await m.addColumn( + schema.contacts, + schema.contacts.mediaSendCounter, + ); + }, )(m, from, to); }, ); diff --git a/lib/src/database/twonly.db.g.dart b/lib/src/database/twonly.db.g.dart index 44ea5d1e..1dced0bc 100644 --- a/lib/src/database/twonly.db.g.dart +++ b/lib/src/database/twonly.db.g.dart @@ -185,6 +185,29 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { type: DriftSqlType.blob, requiredDuringInsert: false, ); + static const VerificationMeta _mediaSendCounterMeta = const VerificationMeta( + 'mediaSendCounter', + ); + @override + late final GeneratedColumn mediaSendCounter = GeneratedColumn( + 'media_send_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(0), + ); + static const VerificationMeta _mediaReceivedCounterMeta = + const VerificationMeta('mediaReceivedCounter'); + @override + late final GeneratedColumn mediaReceivedCounter = GeneratedColumn( + 'media_received_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(0), + ); @override List get $columns => [ userId, @@ -201,6 +224,8 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { accountDeleted, createdAt, userDiscoveryVersion, + mediaSendCounter, + mediaReceivedCounter, ]; @override String get aliasedName => _alias ?? actualTableName; @@ -318,6 +343,24 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { ), ); } + if (data.containsKey('media_send_counter')) { + context.handle( + _mediaSendCounterMeta, + mediaSendCounter.isAcceptableOrUnknown( + data['media_send_counter']!, + _mediaSendCounterMeta, + ), + ); + } + if (data.containsKey('media_received_counter')) { + context.handle( + _mediaReceivedCounterMeta, + mediaReceivedCounter.isAcceptableOrUnknown( + data['media_received_counter']!, + _mediaReceivedCounterMeta, + ), + ); + } return context; } @@ -383,6 +426,14 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { DriftSqlType.blob, data['${effectivePrefix}user_discovery_version'], ), + mediaSendCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_send_counter'], + )!, + mediaReceivedCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_received_counter'], + )!, ); } @@ -407,6 +458,8 @@ class Contact extends DataClass implements Insertable { final bool accountDeleted; final DateTime createdAt; final Uint8List? userDiscoveryVersion; + final int mediaSendCounter; + final int mediaReceivedCounter; const Contact({ required this.userId, required this.username, @@ -422,6 +475,8 @@ class Contact extends DataClass implements Insertable { required this.accountDeleted, required this.createdAt, this.userDiscoveryVersion, + required this.mediaSendCounter, + required this.mediaReceivedCounter, }); @override Map toColumns(bool nullToAbsent) { @@ -448,6 +503,8 @@ class Contact extends DataClass implements Insertable { if (!nullToAbsent || userDiscoveryVersion != null) { map['user_discovery_version'] = Variable(userDiscoveryVersion); } + map['media_send_counter'] = Variable(mediaSendCounter); + map['media_received_counter'] = Variable(mediaReceivedCounter); return map; } @@ -475,6 +532,8 @@ class Contact extends DataClass implements Insertable { userDiscoveryVersion: userDiscoveryVersion == null && nullToAbsent ? const Value.absent() : Value(userDiscoveryVersion), + mediaSendCounter: Value(mediaSendCounter), + mediaReceivedCounter: Value(mediaReceivedCounter), ); } @@ -504,6 +563,10 @@ class Contact extends DataClass implements Insertable { userDiscoveryVersion: serializer.fromJson( json['userDiscoveryVersion'], ), + mediaSendCounter: serializer.fromJson(json['mediaSendCounter']), + mediaReceivedCounter: serializer.fromJson( + json['mediaReceivedCounter'], + ), ); } @override @@ -526,6 +589,8 @@ class Contact extends DataClass implements Insertable { 'userDiscoveryVersion': serializer.toJson( userDiscoveryVersion, ), + 'mediaSendCounter': serializer.toJson(mediaSendCounter), + 'mediaReceivedCounter': serializer.toJson(mediaReceivedCounter), }; } @@ -544,6 +609,8 @@ class Contact extends DataClass implements Insertable { bool? accountDeleted, DateTime? createdAt, Value userDiscoveryVersion = const Value.absent(), + int? mediaSendCounter, + int? mediaReceivedCounter, }) => Contact( userId: userId ?? this.userId, username: username ?? this.username, @@ -563,6 +630,8 @@ class Contact extends DataClass implements Insertable { userDiscoveryVersion: userDiscoveryVersion.present ? userDiscoveryVersion.value : this.userDiscoveryVersion, + mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter, + mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter, ); Contact copyWithCompanion(ContactsCompanion data) { return Contact( @@ -592,6 +661,12 @@ class Contact extends DataClass implements Insertable { userDiscoveryVersion: data.userDiscoveryVersion.present ? data.userDiscoveryVersion.value : this.userDiscoveryVersion, + mediaSendCounter: data.mediaSendCounter.present + ? data.mediaSendCounter.value + : this.mediaSendCounter, + mediaReceivedCounter: data.mediaReceivedCounter.present + ? data.mediaReceivedCounter.value + : this.mediaReceivedCounter, ); } @@ -611,7 +686,9 @@ class Contact extends DataClass implements Insertable { ..write('verified: $verified, ') ..write('accountDeleted: $accountDeleted, ') ..write('createdAt: $createdAt, ') - ..write('userDiscoveryVersion: $userDiscoveryVersion') + ..write('userDiscoveryVersion: $userDiscoveryVersion, ') + ..write('mediaSendCounter: $mediaSendCounter, ') + ..write('mediaReceivedCounter: $mediaReceivedCounter') ..write(')')) .toString(); } @@ -632,6 +709,8 @@ class Contact extends DataClass implements Insertable { accountDeleted, createdAt, $driftBlobEquality.hash(userDiscoveryVersion), + mediaSendCounter, + mediaReceivedCounter, ); @override bool operator ==(Object other) => @@ -656,7 +735,9 @@ class Contact extends DataClass implements Insertable { $driftBlobEquality.equals( other.userDiscoveryVersion, this.userDiscoveryVersion, - )); + ) && + other.mediaSendCounter == this.mediaSendCounter && + other.mediaReceivedCounter == this.mediaReceivedCounter); } class ContactsCompanion extends UpdateCompanion { @@ -674,6 +755,8 @@ class ContactsCompanion extends UpdateCompanion { final Value accountDeleted; final Value createdAt; final Value userDiscoveryVersion; + final Value mediaSendCounter; + final Value mediaReceivedCounter; const ContactsCompanion({ this.userId = const Value.absent(), this.username = const Value.absent(), @@ -689,6 +772,8 @@ class ContactsCompanion extends UpdateCompanion { this.accountDeleted = const Value.absent(), this.createdAt = const Value.absent(), this.userDiscoveryVersion = const Value.absent(), + this.mediaSendCounter = const Value.absent(), + this.mediaReceivedCounter = const Value.absent(), }); ContactsCompanion.insert({ this.userId = const Value.absent(), @@ -705,6 +790,8 @@ class ContactsCompanion extends UpdateCompanion { this.accountDeleted = const Value.absent(), this.createdAt = const Value.absent(), this.userDiscoveryVersion = const Value.absent(), + this.mediaSendCounter = const Value.absent(), + this.mediaReceivedCounter = const Value.absent(), }) : username = Value(username); static Insertable custom({ Expression? userId, @@ -721,6 +808,8 @@ class ContactsCompanion extends UpdateCompanion { Expression? accountDeleted, Expression? createdAt, Expression? userDiscoveryVersion, + Expression? mediaSendCounter, + Expression? mediaReceivedCounter, }) { return RawValuesInsertable({ if (userId != null) 'user_id': userId, @@ -740,6 +829,9 @@ class ContactsCompanion extends UpdateCompanion { if (createdAt != null) 'created_at': createdAt, if (userDiscoveryVersion != null) 'user_discovery_version': userDiscoveryVersion, + if (mediaSendCounter != null) 'media_send_counter': mediaSendCounter, + if (mediaReceivedCounter != null) + 'media_received_counter': mediaReceivedCounter, }); } @@ -758,6 +850,8 @@ class ContactsCompanion extends UpdateCompanion { Value? accountDeleted, Value? createdAt, Value? userDiscoveryVersion, + Value? mediaSendCounter, + Value? mediaReceivedCounter, }) { return ContactsCompanion( userId: userId ?? this.userId, @@ -774,6 +868,8 @@ class ContactsCompanion extends UpdateCompanion { accountDeleted: accountDeleted ?? this.accountDeleted, createdAt: createdAt ?? this.createdAt, userDiscoveryVersion: userDiscoveryVersion ?? this.userDiscoveryVersion, + mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter, + mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter, ); } @@ -826,6 +922,12 @@ class ContactsCompanion extends UpdateCompanion { userDiscoveryVersion.value, ); } + if (mediaSendCounter.present) { + map['media_send_counter'] = Variable(mediaSendCounter.value); + } + if (mediaReceivedCounter.present) { + map['media_received_counter'] = Variable(mediaReceivedCounter.value); + } return map; } @@ -845,7 +947,9 @@ class ContactsCompanion extends UpdateCompanion { ..write('verified: $verified, ') ..write('accountDeleted: $accountDeleted, ') ..write('createdAt: $createdAt, ') - ..write('userDiscoveryVersion: $userDiscoveryVersion') + ..write('userDiscoveryVersion: $userDiscoveryVersion, ') + ..write('mediaSendCounter: $mediaSendCounter, ') + ..write('mediaReceivedCounter: $mediaReceivedCounter') ..write(')')) .toString(); } @@ -11241,6 +11345,8 @@ typedef $$ContactsTableCreateCompanionBuilder = Value accountDeleted, Value createdAt, Value userDiscoveryVersion, + Value mediaSendCounter, + Value mediaReceivedCounter, }); typedef $$ContactsTableUpdateCompanionBuilder = ContactsCompanion Function({ @@ -11258,6 +11364,8 @@ typedef $$ContactsTableUpdateCompanionBuilder = Value accountDeleted, Value createdAt, Value userDiscoveryVersion, + Value mediaSendCounter, + Value mediaReceivedCounter, }); final class $$ContactsTableReferences @@ -11632,6 +11740,16 @@ class $$ContactsTableFilterComposer builder: (column) => ColumnFilters(column), ); + ColumnFilters get mediaSendCounter => $composableBuilder( + column: $table.mediaSendCounter, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get mediaReceivedCounter => $composableBuilder( + column: $table.mediaReceivedCounter, + builder: (column) => ColumnFilters(column), + ); + Expression messagesRefs( Expression Function($$MessagesTableFilterComposer f) f, ) { @@ -12019,6 +12137,16 @@ class $$ContactsTableOrderingComposer column: $table.userDiscoveryVersion, builder: (column) => ColumnOrderings(column), ); + + ColumnOrderings get mediaSendCounter => $composableBuilder( + column: $table.mediaSendCounter, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get mediaReceivedCounter => $composableBuilder( + column: $table.mediaReceivedCounter, + builder: (column) => ColumnOrderings(column), + ); } class $$ContactsTableAnnotationComposer @@ -12084,6 +12212,16 @@ class $$ContactsTableAnnotationComposer builder: (column) => column, ); + GeneratedColumn get mediaSendCounter => $composableBuilder( + column: $table.mediaSendCounter, + builder: (column) => column, + ); + + GeneratedColumn get mediaReceivedCounter => $composableBuilder( + column: $table.mediaReceivedCounter, + builder: (column) => column, + ); + Expression messagesRefs( Expression Function($$MessagesTableAnnotationComposer a) f, ) { @@ -12453,6 +12591,8 @@ class $$ContactsTableTableManager Value accountDeleted = const Value.absent(), Value createdAt = const Value.absent(), Value userDiscoveryVersion = const Value.absent(), + Value mediaSendCounter = const Value.absent(), + Value mediaReceivedCounter = const Value.absent(), }) => ContactsCompanion( userId: userId, username: username, @@ -12468,6 +12608,8 @@ class $$ContactsTableTableManager accountDeleted: accountDeleted, createdAt: createdAt, userDiscoveryVersion: userDiscoveryVersion, + mediaSendCounter: mediaSendCounter, + mediaReceivedCounter: mediaReceivedCounter, ), createCompanionCallback: ({ @@ -12485,6 +12627,8 @@ class $$ContactsTableTableManager Value accountDeleted = const Value.absent(), Value createdAt = const Value.absent(), Value userDiscoveryVersion = const Value.absent(), + Value mediaSendCounter = const Value.absent(), + Value mediaReceivedCounter = const Value.absent(), }) => ContactsCompanion.insert( userId: userId, username: username, @@ -12500,6 +12644,8 @@ class $$ContactsTableTableManager accountDeleted: accountDeleted, createdAt: createdAt, userDiscoveryVersion: userDiscoveryVersion, + mediaSendCounter: mediaSendCounter, + mediaReceivedCounter: mediaReceivedCounter, ), withReferenceMapper: (p0) => p0 .map( diff --git a/lib/src/database/twonly.db.steps.dart b/lib/src/database/twonly.db.steps.dart index 85e6cec2..9bc0f029 100644 --- a/lib/src/database/twonly.db.steps.dart +++ b/lib/src/database/twonly.db.steps.dart @@ -6479,6 +6479,459 @@ i1.GeneratedColumn _column_227(String aliasedName) => type: i1.DriftSqlType.blob, $customConstraints: 'NOT NULL', ); + +final class Schema13 extends i0.VersionedSchema { + Schema13({required super.database}) : super(version: 13); + @override + late final List entities = [ + contacts, + groups, + mediaFiles, + messages, + messageHistories, + reactions, + groupMembers, + receipts, + receivedReceipts, + signalIdentityKeyStores, + signalPreKeyStores, + signalSenderKeyStores, + signalSessionStores, + messageActions, + groupHistories, + keyVerifications, + verificationTokens, + userDiscoveryAnnouncedUsers, + userDiscoveryUserRelations, + userDiscoveryOtherPromotions, + userDiscoveryOwnPromotions, + userDiscoveryShares, + ]; + late final Shape47 contacts = Shape47( + source: i0.VersionedTable( + entityName: 'contacts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(user_id)'], + columns: [ + _column_106, + _column_107, + _column_108, + _column_109, + _column_110, + _column_111, + _column_112, + _column_113, + _column_114, + _column_115, + _column_116, + _column_117, + _column_118, + _column_211, + _column_228, + _column_229, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape23 groups = Shape23( + source: i0.VersionedTable( + entityName: 'groups', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_id)'], + columns: [ + _column_119, + _column_120, + _column_121, + _column_122, + _column_123, + _column_124, + _column_125, + _column_126, + _column_127, + _column_128, + _column_129, + _column_130, + _column_131, + _column_132, + _column_133, + _column_134, + _column_118, + _column_135, + _column_136, + _column_137, + _column_138, + _column_139, + _column_140, + _column_141, + _column_142, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape36 mediaFiles = Shape36( + source: i0.VersionedTable( + entityName: 'media_files', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(media_id)'], + columns: [ + _column_143, + _column_144, + _column_145, + _column_146, + _column_147, + _column_148, + _column_149, + _column_207, + _column_150, + _column_151, + _column_152, + _column_153, + _column_154, + _column_155, + _column_156, + _column_157, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape25 messages = Shape25( + source: i0.VersionedTable( + entityName: 'messages', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id)'], + columns: [ + _column_158, + _column_159, + _column_160, + _column_144, + _column_161, + _column_162, + _column_163, + _column_164, + _column_165, + _column_153, + _column_166, + _column_167, + _column_168, + _column_169, + _column_118, + _column_170, + _column_171, + _column_172, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape26 messageHistories = Shape26( + source: i0.VersionedTable( + entityName: 'message_histories', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_173, + _column_174, + _column_175, + _column_161, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape27 reactions = Shape27( + source: i0.VersionedTable( + entityName: 'reactions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id, sender_id, emoji)'], + columns: [_column_174, _column_176, _column_177, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape38 groupMembers = Shape38( + source: i0.VersionedTable( + entityName: 'group_members', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_id, contact_id)'], + columns: [ + _column_158, + _column_178, + _column_179, + _column_180, + _column_209, + _column_210, + _column_181, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape37 receipts = Shape37( + source: i0.VersionedTable( + entityName: 'receipts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(receipt_id)'], + columns: [ + _column_182, + _column_183, + _column_184, + _column_185, + _column_186, + _column_208, + _column_187, + _column_188, + _column_189, + _column_190, + _column_191, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape30 receivedReceipts = Shape30( + source: i0.VersionedTable( + entityName: 'received_receipts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(receipt_id)'], + columns: [_column_182, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape31 signalIdentityKeyStores = Shape31( + source: i0.VersionedTable( + entityName: 'signal_identity_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(device_id, name)'], + columns: [_column_192, _column_193, _column_194, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape32 signalPreKeyStores = Shape32( + source: i0.VersionedTable( + entityName: 'signal_pre_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(pre_key_id)'], + columns: [_column_195, _column_196, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape11 signalSenderKeyStores = Shape11( + source: i0.VersionedTable( + entityName: 'signal_sender_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(sender_key_name)'], + columns: [_column_197, _column_198], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape33 signalSessionStores = Shape33( + source: i0.VersionedTable( + entityName: 'signal_session_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(device_id, name)'], + columns: [_column_192, _column_193, _column_199, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape34 messageActions = Shape34( + source: i0.VersionedTable( + entityName: 'message_actions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id, contact_id, type)'], + columns: [_column_174, _column_183, _column_144, _column_200], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape35 groupHistories = Shape35( + source: i0.VersionedTable( + entityName: 'group_histories', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_history_id)'], + columns: [ + _column_201, + _column_158, + _column_202, + _column_203, + _column_204, + _column_205, + _column_206, + _column_144, + _column_200, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape40 keyVerifications = Shape40( + source: i0.VersionedTable( + entityName: 'key_verifications', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(contact_id)'], + columns: [_column_183, _column_144, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape41 verificationTokens = Shape41( + source: i0.VersionedTable( + entityName: 'verification_tokens', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_212, _column_213, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape42 userDiscoveryAnnouncedUsers = Shape42( + source: i0.VersionedTable( + entityName: 'user_discovery_announced_users', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(announced_user_id)'], + columns: [_column_214, _column_215, _column_216], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape43 userDiscoveryUserRelations = Shape43( + source: i0.VersionedTable( + entityName: 'user_discovery_user_relations', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(announced_user_id, from_contact_id)'], + columns: [_column_217, _column_218, _column_219], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape44 userDiscoveryOtherPromotions = Shape44( + source: i0.VersionedTable( + entityName: 'user_discovery_other_promotions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(from_contact_id, promotion_id)'], + columns: [ + _column_218, + _column_220, + _column_221, + _column_222, + _column_223, + _column_219, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape45 userDiscoveryOwnPromotions = Shape45( + source: i0.VersionedTable( + entityName: 'user_discovery_own_promotions', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_224, _column_183, _column_225], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape46 userDiscoveryShares = Shape46( + source: i0.VersionedTable( + entityName: 'user_discovery_shares', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_226, _column_227, _column_175], + attachedDatabase: database, + ), + alias: null, + ); +} + +class Shape47 extends i0.VersionedTable { + Shape47({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get userId => + columnsByName['user_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get username => + columnsByName['username']! as i1.GeneratedColumn; + i1.GeneratedColumn get displayName => + columnsByName['display_name']! as i1.GeneratedColumn; + i1.GeneratedColumn get nickName => + columnsByName['nick_name']! as i1.GeneratedColumn; + i1.GeneratedColumn get avatarSvgCompressed => + columnsByName['avatar_svg_compressed']! + as i1.GeneratedColumn; + i1.GeneratedColumn get senderProfileCounter => + columnsByName['sender_profile_counter']! as i1.GeneratedColumn; + i1.GeneratedColumn get accepted => + columnsByName['accepted']! as i1.GeneratedColumn; + i1.GeneratedColumn get deletedByUser => + columnsByName['deleted_by_user']! as i1.GeneratedColumn; + i1.GeneratedColumn get requested => + columnsByName['requested']! as i1.GeneratedColumn; + i1.GeneratedColumn get blocked => + columnsByName['blocked']! as i1.GeneratedColumn; + i1.GeneratedColumn get verified => + columnsByName['verified']! as i1.GeneratedColumn; + i1.GeneratedColumn get accountDeleted => + columnsByName['account_deleted']! as i1.GeneratedColumn; + i1.GeneratedColumn get createdAt => + columnsByName['created_at']! as i1.GeneratedColumn; + i1.GeneratedColumn get userDiscoveryVersion => + columnsByName['user_discovery_version']! + as i1.GeneratedColumn; + i1.GeneratedColumn get mediaSendCounter => + columnsByName['media_send_counter']! as i1.GeneratedColumn; + i1.GeneratedColumn get mediaReceivedCounter => + columnsByName['media_received_counter']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_228(String aliasedName) => + i1.GeneratedColumn( + 'media_send_counter', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const i1.CustomExpression('0'), + ); +i1.GeneratedColumn _column_229(String aliasedName) => + i1.GeneratedColumn( + 'media_received_counter', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const i1.CustomExpression('0'), + ); i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema2 schema) from1To2, required Future Function(i1.Migrator m, Schema3 schema) from2To3, @@ -6491,6 +6944,7 @@ i0.MigrationStepWithVersion migrationSteps({ 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, + required Future Function(i1.Migrator m, Schema13 schema) from12To13, }) { return (currentVersion, database) async { switch (currentVersion) { @@ -6549,6 +7003,11 @@ i0.MigrationStepWithVersion migrationSteps({ final migrator = i1.Migrator(database, schema); await from11To12(migrator, schema); return 12; + case 12: + final schema = Schema13(database: database); + final migrator = i1.Migrator(database, schema); + await from12To13(migrator, schema); + return 13; default: throw ArgumentError.value('Unknown migration from $currentVersion'); } @@ -6567,6 +7026,7 @@ i1.OnUpgrade stepByStep({ 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, + required Future Function(i1.Migrator m, Schema13 schema) from12To13, }) => i0.VersionedSchema.stepByStepHelper( step: migrationSteps( from1To2: from1To2, @@ -6580,5 +7040,6 @@ i1.OnUpgrade stepByStep({ from9To10: from9To10, from10To11: from10To11, from11To12: from11To12, + from12To13: from12To13, ), ); diff --git a/lib/src/model/json/userdata.dart b/lib/src/model/json/userdata.dart index f7495472..e0e0585d 100644 --- a/lib/src/model/json/userdata.dart +++ b/lib/src/model/json/userdata.dart @@ -96,9 +96,12 @@ class UserData { @JsonKey(defaultValue: false) bool isUserDiscoveryEnabled = false; - @JsonKey(defaultValue: false) + @JsonKey(defaultValue: 4) int minimumRequiredImagesExchanged = 4; + @JsonKey(defaultValue: 2) + int userDiscoveryThreshold = 2; + // -- Custom DATA -- @JsonKey(defaultValue: 100_000) diff --git a/lib/src/model/json/userdata.g.dart b/lib/src/model/json/userdata.g.dart index 16e851ff..69d4b694 100644 --- a/lib/src/model/json/userdata.g.dart +++ b/lib/src/model/json/userdata.g.dart @@ -63,6 +63,10 @@ UserData _$UserDataFromJson(Map json) => ..screenLockEnabled = json['screenLockEnabled'] as bool? ?? false ..isUserDiscoveryEnabled = json['isUserDiscoveryEnabled'] as bool? ?? false + ..minimumRequiredImagesExchanged = + (json['minimumRequiredImagesExchanged'] as num?)?.toInt() ?? 4 + ..userDiscoveryThreshold = + (json['userDiscoveryThreshold'] as num?)?.toInt() ?? 2 ..currentPreKeyIndexStart = (json['currentPreKeyIndexStart'] as num?)?.toInt() ?? 100000 ..currentSignedPreKeyIndexStart = @@ -126,6 +130,8 @@ Map _$UserDataToJson(UserData instance) => { 'allowErrorTrackingViaSentry': instance.allowErrorTrackingViaSentry, 'screenLockEnabled': instance.screenLockEnabled, 'isUserDiscoveryEnabled': instance.isUserDiscoveryEnabled, + 'minimumRequiredImagesExchanged': instance.minimumRequiredImagesExchanged, + 'userDiscoveryThreshold': instance.userDiscoveryThreshold, 'currentPreKeyIndexStart': instance.currentPreKeyIndexStart, 'currentSignedPreKeyIndexStart': instance.currentSignedPreKeyIndexStart, 'lastChangeLogHash': instance.lastChangeLogHash, diff --git a/lib/src/model/protobuf/client/generated/user_discovery/types.pb.dart b/lib/src/model/protobuf/client/generated/user_discovery/types.pb.dart new file mode 100644 index 00000000..51f44273 --- /dev/null +++ b/lib/src/model/protobuf/client/generated/user_discovery/types.pb.dart @@ -0,0 +1,695 @@ +// This is a generated file - do not edit. +// +// Generated from types.proto. + +// @dart = 3.3 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: curly_braces_in_flow_control_structures +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names + +import 'dart:core' as $core; + +import 'package:fixnum/fixnum.dart' as $fixnum; +import 'package:protobuf/protobuf.dart' as $pb; + +export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions; + +class UserDiscoveryVersion extends $pb.GeneratedMessage { + factory UserDiscoveryVersion({ + $core.int? announcement, + $core.int? promotion, + }) { + final result = create(); + if (announcement != null) result.announcement = announcement; + if (promotion != null) result.promotion = promotion; + return result; + } + + UserDiscoveryVersion._(); + + factory UserDiscoveryVersion.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory UserDiscoveryVersion.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'UserDiscoveryVersion', + package: const $pb.PackageName(_omitMessageNames ? '' : 'user_discovery'), + createEmptyInstance: create) + ..a<$core.int>( + 1, _omitFieldNames ? '' : 'announcement', $pb.PbFieldType.OU3) + ..a<$core.int>(2, _omitFieldNames ? '' : 'promotion', $pb.PbFieldType.OU3) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryVersion clone() => + UserDiscoveryVersion()..mergeFromMessage(this); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryVersion copyWith(void Function(UserDiscoveryVersion) updates) => + super.copyWith((message) => updates(message as UserDiscoveryVersion)) + as UserDiscoveryVersion; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static UserDiscoveryVersion create() => UserDiscoveryVersion._(); + @$core.override + UserDiscoveryVersion createEmptyInstance() => create(); + static $pb.PbList createRepeated() => + $pb.PbList(); + @$core.pragma('dart2js:noInline') + static UserDiscoveryVersion getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static UserDiscoveryVersion? _defaultInstance; + + @$pb.TagNumber(1) + $core.int get announcement => $_getIZ(0); + @$pb.TagNumber(1) + set announcement($core.int value) => $_setUnsignedInt32(0, value); + @$pb.TagNumber(1) + $core.bool hasAnnouncement() => $_has(0); + @$pb.TagNumber(1) + void clearAnnouncement() => $_clearField(1); + + @$pb.TagNumber(2) + $core.int get promotion => $_getIZ(1); + @$pb.TagNumber(2) + set promotion($core.int value) => $_setUnsignedInt32(1, value); + @$pb.TagNumber(2) + $core.bool hasPromotion() => $_has(1); + @$pb.TagNumber(2) + void clearPromotion() => $_clearField(2); +} + +class UserDiscoveryMessage_UserDiscoveryAnnouncement + extends $pb.GeneratedMessage { + factory UserDiscoveryMessage_UserDiscoveryAnnouncement({ + $fixnum.Int64? publicId, + $core.int? threshold, + $core.List<$core.int>? announcementShare, + $core.Iterable<$core.List<$core.int>>? verificationShares, + }) { + final result = create(); + if (publicId != null) result.publicId = publicId; + if (threshold != null) result.threshold = threshold; + if (announcementShare != null) result.announcementShare = announcementShare; + if (verificationShares != null) + result.verificationShares.addAll(verificationShares); + return result; + } + + UserDiscoveryMessage_UserDiscoveryAnnouncement._(); + + factory UserDiscoveryMessage_UserDiscoveryAnnouncement.fromBuffer( + $core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory UserDiscoveryMessage_UserDiscoveryAnnouncement.fromJson( + $core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'UserDiscoveryMessage.UserDiscoveryAnnouncement', + package: const $pb.PackageName(_omitMessageNames ? '' : 'user_discovery'), + createEmptyInstance: create) + ..aInt64(1, _omitFieldNames ? '' : 'publicId') + ..a<$core.int>(2, _omitFieldNames ? '' : 'threshold', $pb.PbFieldType.OU3) + ..a<$core.List<$core.int>>( + 4, _omitFieldNames ? '' : 'announcementShare', $pb.PbFieldType.OY) + ..p<$core.List<$core.int>>( + 6, _omitFieldNames ? '' : 'verificationShares', $pb.PbFieldType.PY) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage_UserDiscoveryAnnouncement clone() => + UserDiscoveryMessage_UserDiscoveryAnnouncement()..mergeFromMessage(this); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage_UserDiscoveryAnnouncement copyWith( + void Function(UserDiscoveryMessage_UserDiscoveryAnnouncement) + updates) => + super.copyWith((message) => updates( + message as UserDiscoveryMessage_UserDiscoveryAnnouncement)) + as UserDiscoveryMessage_UserDiscoveryAnnouncement; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage_UserDiscoveryAnnouncement create() => + UserDiscoveryMessage_UserDiscoveryAnnouncement._(); + @$core.override + UserDiscoveryMessage_UserDiscoveryAnnouncement createEmptyInstance() => + create(); + static $pb.PbList + createRepeated() => + $pb.PbList(); + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage_UserDiscoveryAnnouncement getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor< + UserDiscoveryMessage_UserDiscoveryAnnouncement>(create); + static UserDiscoveryMessage_UserDiscoveryAnnouncement? _defaultInstance; + + @$pb.TagNumber(1) + $fixnum.Int64 get publicId => $_getI64(0); + @$pb.TagNumber(1) + set publicId($fixnum.Int64 value) => $_setInt64(0, value); + @$pb.TagNumber(1) + $core.bool hasPublicId() => $_has(0); + @$pb.TagNumber(1) + void clearPublicId() => $_clearField(1); + + @$pb.TagNumber(2) + $core.int get threshold => $_getIZ(1); + @$pb.TagNumber(2) + set threshold($core.int value) => $_setUnsignedInt32(1, value); + @$pb.TagNumber(2) + $core.bool hasThreshold() => $_has(1); + @$pb.TagNumber(2) + void clearThreshold() => $_clearField(2); + + @$pb.TagNumber(4) + $core.List<$core.int> get announcementShare => $_getN(2); + @$pb.TagNumber(4) + set announcementShare($core.List<$core.int> value) => $_setBytes(2, value); + @$pb.TagNumber(4) + $core.bool hasAnnouncementShare() => $_has(2); + @$pb.TagNumber(4) + void clearAnnouncementShare() => $_clearField(4); + + @$pb.TagNumber(6) + $pb.PbList<$core.List<$core.int>> get verificationShares => $_getList(3); +} + +class UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData + extends $pb.GeneratedMessage { + factory UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData({ + $fixnum.Int64? publicId, + $fixnum.Int64? userId, + $core.List<$core.int>? publicKey, + }) { + final result = create(); + if (publicId != null) result.publicId = publicId; + if (userId != null) result.userId = userId; + if (publicKey != null) result.publicKey = publicKey; + return result; + } + + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData._(); + + factory UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData.fromBuffer( + $core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData.fromJson( + $core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames + ? '' + : 'UserDiscoveryMessage.UserDiscoveryPromotion.AnnouncementShareDecrypted.SignedData', + package: const $pb.PackageName(_omitMessageNames ? '' : 'user_discovery'), + createEmptyInstance: create) + ..aInt64(1, _omitFieldNames ? '' : 'publicId') + ..aInt64(2, _omitFieldNames ? '' : 'userId') + ..a<$core.List<$core.int>>( + 3, _omitFieldNames ? '' : 'publicKey', $pb.PbFieldType.OY) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData + clone() => + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData() + ..mergeFromMessage(this); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData copyWith( + void Function( + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData) + updates) => + super.copyWith((message) => updates(message + as UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData)) + as UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData + create() => + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData + ._(); + @$core.override + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData + createEmptyInstance() => create(); + static $pb.PbList< + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData> + createRepeated() => $pb.PbList< + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData>(); + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData + getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor< + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData>( + create); + static UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData? + _defaultInstance; + + @$pb.TagNumber(1) + $fixnum.Int64 get publicId => $_getI64(0); + @$pb.TagNumber(1) + set publicId($fixnum.Int64 value) => $_setInt64(0, value); + @$pb.TagNumber(1) + $core.bool hasPublicId() => $_has(0); + @$pb.TagNumber(1) + void clearPublicId() => $_clearField(1); + + @$pb.TagNumber(2) + $fixnum.Int64 get userId => $_getI64(1); + @$pb.TagNumber(2) + set userId($fixnum.Int64 value) => $_setInt64(1, value); + @$pb.TagNumber(2) + $core.bool hasUserId() => $_has(1); + @$pb.TagNumber(2) + void clearUserId() => $_clearField(2); + + @$pb.TagNumber(3) + $core.List<$core.int> get publicKey => $_getN(2); + @$pb.TagNumber(3) + set publicKey($core.List<$core.int> value) => $_setBytes(2, value); + @$pb.TagNumber(3) + $core.bool hasPublicKey() => $_has(2); + @$pb.TagNumber(3) + void clearPublicKey() => $_clearField(3); +} + +class UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted + extends $pb.GeneratedMessage { + factory UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted({ + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData? + signedData, + $core.List<$core.int>? signature, + }) { + final result = create(); + if (signedData != null) result.signedData = signedData; + if (signature != null) result.signature = signature; + return result; + } + + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted._(); + + factory UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted.fromBuffer( + $core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted.fromJson( + $core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames + ? '' + : 'UserDiscoveryMessage.UserDiscoveryPromotion.AnnouncementShareDecrypted', + package: const $pb.PackageName(_omitMessageNames ? '' : 'user_discovery'), + createEmptyInstance: create) + ..aOM( + 1, _omitFieldNames ? '' : 'signedData', + subBuilder: + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData + .create) + ..a<$core.List<$core.int>>( + 2, _omitFieldNames ? '' : 'signature', $pb.PbFieldType.OY) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted + clone() => + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted() + ..mergeFromMessage(this); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted copyWith( + void Function( + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted) + updates) => + super.copyWith((message) => updates(message + as UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted)) + as UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted + create() => + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted + ._(); + @$core.override + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted + createEmptyInstance() => create(); + static $pb.PbList< + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted> + createRepeated() => $pb.PbList< + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted>(); + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted + getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor< + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted>( + create); + static UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted? + _defaultInstance; + + @$pb.TagNumber(1) + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData + get signedData => $_getN(0); + @$pb.TagNumber(1) + set signedData( + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData + value) => + $_setField(1, value); + @$pb.TagNumber(1) + $core.bool hasSignedData() => $_has(0); + @$pb.TagNumber(1) + void clearSignedData() => $_clearField(1); + @$pb.TagNumber(1) + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData + ensureSignedData() => $_ensure(0); + + @$pb.TagNumber(2) + $core.List<$core.int> get signature => $_getN(1); + @$pb.TagNumber(2) + set signature($core.List<$core.int> value) => $_setBytes(1, value); + @$pb.TagNumber(2) + $core.bool hasSignature() => $_has(1); + @$pb.TagNumber(2) + void clearSignature() => $_clearField(2); +} + +class UserDiscoveryMessage_UserDiscoveryPromotion extends $pb.GeneratedMessage { + factory UserDiscoveryMessage_UserDiscoveryPromotion({ + $core.int? promotionId, + $fixnum.Int64? publicId, + $core.int? threshold, + $core.List<$core.int>? announcementShare, + $fixnum.Int64? publicKeyVerifiedTimestamp, + }) { + final result = create(); + if (promotionId != null) result.promotionId = promotionId; + if (publicId != null) result.publicId = publicId; + if (threshold != null) result.threshold = threshold; + if (announcementShare != null) result.announcementShare = announcementShare; + if (publicKeyVerifiedTimestamp != null) + result.publicKeyVerifiedTimestamp = publicKeyVerifiedTimestamp; + return result; + } + + UserDiscoveryMessage_UserDiscoveryPromotion._(); + + factory UserDiscoveryMessage_UserDiscoveryPromotion.fromBuffer( + $core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory UserDiscoveryMessage_UserDiscoveryPromotion.fromJson( + $core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'UserDiscoveryMessage.UserDiscoveryPromotion', + package: const $pb.PackageName(_omitMessageNames ? '' : 'user_discovery'), + createEmptyInstance: create) + ..a<$core.int>(1, _omitFieldNames ? '' : 'promotionId', $pb.PbFieldType.OU3) + ..aInt64(2, _omitFieldNames ? '' : 'publicId') + ..a<$core.int>(3, _omitFieldNames ? '' : 'threshold', $pb.PbFieldType.OU3) + ..a<$core.List<$core.int>>( + 5, _omitFieldNames ? '' : 'announcementShare', $pb.PbFieldType.OY) + ..aInt64(6, _omitFieldNames ? '' : 'publicKeyVerifiedTimestamp') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage_UserDiscoveryPromotion clone() => + UserDiscoveryMessage_UserDiscoveryPromotion()..mergeFromMessage(this); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage_UserDiscoveryPromotion copyWith( + void Function(UserDiscoveryMessage_UserDiscoveryPromotion) updates) => + super.copyWith((message) => + updates(message as UserDiscoveryMessage_UserDiscoveryPromotion)) + as UserDiscoveryMessage_UserDiscoveryPromotion; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage_UserDiscoveryPromotion create() => + UserDiscoveryMessage_UserDiscoveryPromotion._(); + @$core.override + UserDiscoveryMessage_UserDiscoveryPromotion createEmptyInstance() => create(); + static $pb.PbList + createRepeated() => + $pb.PbList(); + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage_UserDiscoveryPromotion getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor< + UserDiscoveryMessage_UserDiscoveryPromotion>(create); + static UserDiscoveryMessage_UserDiscoveryPromotion? _defaultInstance; + + @$pb.TagNumber(1) + $core.int get promotionId => $_getIZ(0); + @$pb.TagNumber(1) + set promotionId($core.int value) => $_setUnsignedInt32(0, value); + @$pb.TagNumber(1) + $core.bool hasPromotionId() => $_has(0); + @$pb.TagNumber(1) + void clearPromotionId() => $_clearField(1); + + @$pb.TagNumber(2) + $fixnum.Int64 get publicId => $_getI64(1); + @$pb.TagNumber(2) + set publicId($fixnum.Int64 value) => $_setInt64(1, value); + @$pb.TagNumber(2) + $core.bool hasPublicId() => $_has(1); + @$pb.TagNumber(2) + void clearPublicId() => $_clearField(2); + + @$pb.TagNumber(3) + $core.int get threshold => $_getIZ(2); + @$pb.TagNumber(3) + set threshold($core.int value) => $_setUnsignedInt32(2, value); + @$pb.TagNumber(3) + $core.bool hasThreshold() => $_has(2); + @$pb.TagNumber(3) + void clearThreshold() => $_clearField(3); + + @$pb.TagNumber(5) + $core.List<$core.int> get announcementShare => $_getN(3); + @$pb.TagNumber(5) + set announcementShare($core.List<$core.int> value) => $_setBytes(3, value); + @$pb.TagNumber(5) + $core.bool hasAnnouncementShare() => $_has(3); + @$pb.TagNumber(5) + void clearAnnouncementShare() => $_clearField(5); + + @$pb.TagNumber(6) + $fixnum.Int64 get publicKeyVerifiedTimestamp => $_getI64(4); + @$pb.TagNumber(6) + set publicKeyVerifiedTimestamp($fixnum.Int64 value) => $_setInt64(4, value); + @$pb.TagNumber(6) + $core.bool hasPublicKeyVerifiedTimestamp() => $_has(4); + @$pb.TagNumber(6) + void clearPublicKeyVerifiedTimestamp() => $_clearField(6); +} + +class UserDiscoveryMessage_UserDiscoveryRecall extends $pb.GeneratedMessage { + factory UserDiscoveryMessage_UserDiscoveryRecall({ + $fixnum.Int64? promotionId, + }) { + final result = create(); + if (promotionId != null) result.promotionId = promotionId; + return result; + } + + UserDiscoveryMessage_UserDiscoveryRecall._(); + + factory UserDiscoveryMessage_UserDiscoveryRecall.fromBuffer( + $core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory UserDiscoveryMessage_UserDiscoveryRecall.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'UserDiscoveryMessage.UserDiscoveryRecall', + package: const $pb.PackageName(_omitMessageNames ? '' : 'user_discovery'), + createEmptyInstance: create) + ..aInt64(1, _omitFieldNames ? '' : 'promotionId') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage_UserDiscoveryRecall clone() => + UserDiscoveryMessage_UserDiscoveryRecall()..mergeFromMessage(this); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage_UserDiscoveryRecall copyWith( + void Function(UserDiscoveryMessage_UserDiscoveryRecall) updates) => + super.copyWith((message) => + updates(message as UserDiscoveryMessage_UserDiscoveryRecall)) + as UserDiscoveryMessage_UserDiscoveryRecall; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage_UserDiscoveryRecall create() => + UserDiscoveryMessage_UserDiscoveryRecall._(); + @$core.override + UserDiscoveryMessage_UserDiscoveryRecall createEmptyInstance() => create(); + static $pb.PbList + createRepeated() => + $pb.PbList(); + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage_UserDiscoveryRecall getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor< + UserDiscoveryMessage_UserDiscoveryRecall>(create); + static UserDiscoveryMessage_UserDiscoveryRecall? _defaultInstance; + + @$pb.TagNumber(1) + $fixnum.Int64 get promotionId => $_getI64(0); + @$pb.TagNumber(1) + set promotionId($fixnum.Int64 value) => $_setInt64(0, value); + @$pb.TagNumber(1) + $core.bool hasPromotionId() => $_has(0); + @$pb.TagNumber(1) + void clearPromotionId() => $_clearField(1); +} + +class UserDiscoveryMessage extends $pb.GeneratedMessage { + factory UserDiscoveryMessage({ + UserDiscoveryVersion? version, + UserDiscoveryMessage_UserDiscoveryAnnouncement? userDiscoveryAnnouncement, + UserDiscoveryMessage_UserDiscoveryPromotion? userDiscoveryPromotion, + UserDiscoveryMessage_UserDiscoveryRecall? userDiscoveryRecall, + }) { + final result = create(); + if (version != null) result.version = version; + if (userDiscoveryAnnouncement != null) + result.userDiscoveryAnnouncement = userDiscoveryAnnouncement; + if (userDiscoveryPromotion != null) + result.userDiscoveryPromotion = userDiscoveryPromotion; + if (userDiscoveryRecall != null) + result.userDiscoveryRecall = userDiscoveryRecall; + return result; + } + + UserDiscoveryMessage._(); + + factory UserDiscoveryMessage.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory UserDiscoveryMessage.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'UserDiscoveryMessage', + package: const $pb.PackageName(_omitMessageNames ? '' : 'user_discovery'), + createEmptyInstance: create) + ..aOM(1, _omitFieldNames ? '' : 'version', + subBuilder: UserDiscoveryVersion.create) + ..aOM( + 2, _omitFieldNames ? '' : 'userDiscoveryAnnouncement', + subBuilder: UserDiscoveryMessage_UserDiscoveryAnnouncement.create) + ..aOM( + 3, _omitFieldNames ? '' : 'userDiscoveryPromotion', + subBuilder: UserDiscoveryMessage_UserDiscoveryPromotion.create) + ..aOM( + 4, _omitFieldNames ? '' : 'userDiscoveryRecall', + subBuilder: UserDiscoveryMessage_UserDiscoveryRecall.create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage clone() => + UserDiscoveryMessage()..mergeFromMessage(this); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UserDiscoveryMessage copyWith(void Function(UserDiscoveryMessage) updates) => + super.copyWith((message) => updates(message as UserDiscoveryMessage)) + as UserDiscoveryMessage; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage create() => UserDiscoveryMessage._(); + @$core.override + UserDiscoveryMessage createEmptyInstance() => create(); + static $pb.PbList createRepeated() => + $pb.PbList(); + @$core.pragma('dart2js:noInline') + static UserDiscoveryMessage getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static UserDiscoveryMessage? _defaultInstance; + + @$pb.TagNumber(1) + UserDiscoveryVersion get version => $_getN(0); + @$pb.TagNumber(1) + set version(UserDiscoveryVersion value) => $_setField(1, value); + @$pb.TagNumber(1) + $core.bool hasVersion() => $_has(0); + @$pb.TagNumber(1) + void clearVersion() => $_clearField(1); + @$pb.TagNumber(1) + UserDiscoveryVersion ensureVersion() => $_ensure(0); + + @$pb.TagNumber(2) + UserDiscoveryMessage_UserDiscoveryAnnouncement + get userDiscoveryAnnouncement => $_getN(1); + @$pb.TagNumber(2) + set userDiscoveryAnnouncement( + UserDiscoveryMessage_UserDiscoveryAnnouncement value) => + $_setField(2, value); + @$pb.TagNumber(2) + $core.bool hasUserDiscoveryAnnouncement() => $_has(1); + @$pb.TagNumber(2) + void clearUserDiscoveryAnnouncement() => $_clearField(2); + @$pb.TagNumber(2) + UserDiscoveryMessage_UserDiscoveryAnnouncement + ensureUserDiscoveryAnnouncement() => $_ensure(1); + + @$pb.TagNumber(3) + UserDiscoveryMessage_UserDiscoveryPromotion get userDiscoveryPromotion => + $_getN(2); + @$pb.TagNumber(3) + set userDiscoveryPromotion( + UserDiscoveryMessage_UserDiscoveryPromotion value) => + $_setField(3, value); + @$pb.TagNumber(3) + $core.bool hasUserDiscoveryPromotion() => $_has(2); + @$pb.TagNumber(3) + void clearUserDiscoveryPromotion() => $_clearField(3); + @$pb.TagNumber(3) + UserDiscoveryMessage_UserDiscoveryPromotion ensureUserDiscoveryPromotion() => + $_ensure(2); + + @$pb.TagNumber(4) + UserDiscoveryMessage_UserDiscoveryRecall get userDiscoveryRecall => $_getN(3); + @$pb.TagNumber(4) + set userDiscoveryRecall(UserDiscoveryMessage_UserDiscoveryRecall value) => + $_setField(4, value); + @$pb.TagNumber(4) + $core.bool hasUserDiscoveryRecall() => $_has(3); + @$pb.TagNumber(4) + void clearUserDiscoveryRecall() => $_clearField(4); + @$pb.TagNumber(4) + UserDiscoveryMessage_UserDiscoveryRecall ensureUserDiscoveryRecall() => + $_ensure(3); +} + +const $core.bool _omitFieldNames = + $core.bool.fromEnvironment('protobuf.omit_field_names'); +const $core.bool _omitMessageNames = + $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/lib/src/model/protobuf/client/generated/user_discovery/types.pbenum.dart b/lib/src/model/protobuf/client/generated/user_discovery/types.pbenum.dart new file mode 100644 index 00000000..f3d3952c --- /dev/null +++ b/lib/src/model/protobuf/client/generated/user_discovery/types.pbenum.dart @@ -0,0 +1,11 @@ +// This is a generated file - do not edit. +// +// Generated from types.proto. + +// @dart = 3.3 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: curly_braces_in_flow_control_structures +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names diff --git a/lib/src/model/protobuf/client/generated/user_discovery/types.pbjson.dart b/lib/src/model/protobuf/client/generated/user_discovery/types.pbjson.dart new file mode 100644 index 00000000..27fe7de8 --- /dev/null +++ b/lib/src/model/protobuf/client/generated/user_discovery/types.pbjson.dart @@ -0,0 +1,207 @@ +// This is a generated file - do not edit. +// +// Generated from types.proto. + +// @dart = 3.3 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: curly_braces_in_flow_control_structures +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names, unused_import + +import 'dart:convert' as $convert; +import 'dart:core' as $core; +import 'dart:typed_data' as $typed_data; + +@$core.Deprecated('Use userDiscoveryVersionDescriptor instead') +const UserDiscoveryVersion$json = { + '1': 'UserDiscoveryVersion', + '2': [ + {'1': 'announcement', '3': 1, '4': 1, '5': 13, '10': 'announcement'}, + {'1': 'promotion', '3': 2, '4': 1, '5': 13, '10': 'promotion'}, + ], +}; + +/// Descriptor for `UserDiscoveryVersion`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List userDiscoveryVersionDescriptor = $convert.base64Decode( + 'ChRVc2VyRGlzY292ZXJ5VmVyc2lvbhIiCgxhbm5vdW5jZW1lbnQYASABKA1SDGFubm91bmNlbW' + 'VudBIcCglwcm9tb3Rpb24YAiABKA1SCXByb21vdGlvbg=='); + +@$core.Deprecated('Use userDiscoveryMessageDescriptor instead') +const UserDiscoveryMessage$json = { + '1': 'UserDiscoveryMessage', + '2': [ + { + '1': 'version', + '3': 1, + '4': 1, + '5': 11, + '6': '.user_discovery.UserDiscoveryVersion', + '10': 'version' + }, + { + '1': 'user_discovery_announcement', + '3': 2, + '4': 1, + '5': 11, + '6': '.user_discovery.UserDiscoveryMessage.UserDiscoveryAnnouncement', + '9': 0, + '10': 'userDiscoveryAnnouncement', + '17': true + }, + { + '1': 'user_discovery_promotion', + '3': 3, + '4': 1, + '5': 11, + '6': '.user_discovery.UserDiscoveryMessage.UserDiscoveryPromotion', + '9': 1, + '10': 'userDiscoveryPromotion', + '17': true + }, + { + '1': 'user_discovery_recall', + '3': 4, + '4': 1, + '5': 11, + '6': '.user_discovery.UserDiscoveryMessage.UserDiscoveryRecall', + '9': 2, + '10': 'userDiscoveryRecall', + '17': true + }, + ], + '3': [ + UserDiscoveryMessage_UserDiscoveryAnnouncement$json, + UserDiscoveryMessage_UserDiscoveryPromotion$json, + UserDiscoveryMessage_UserDiscoveryRecall$json + ], + '8': [ + {'1': '_user_discovery_announcement'}, + {'1': '_user_discovery_promotion'}, + {'1': '_user_discovery_recall'}, + ], +}; + +@$core.Deprecated('Use userDiscoveryMessageDescriptor instead') +const UserDiscoveryMessage_UserDiscoveryAnnouncement$json = { + '1': 'UserDiscoveryAnnouncement', + '2': [ + {'1': 'public_id', '3': 1, '4': 1, '5': 3, '10': 'publicId'}, + {'1': 'threshold', '3': 2, '4': 1, '5': 13, '10': 'threshold'}, + { + '1': 'announcement_share', + '3': 4, + '4': 1, + '5': 12, + '10': 'announcementShare' + }, + { + '1': 'verification_shares', + '3': 6, + '4': 3, + '5': 12, + '10': 'verificationShares' + }, + ], +}; + +@$core.Deprecated('Use userDiscoveryMessageDescriptor instead') +const UserDiscoveryMessage_UserDiscoveryPromotion$json = { + '1': 'UserDiscoveryPromotion', + '2': [ + {'1': 'promotion_id', '3': 1, '4': 1, '5': 13, '10': 'promotionId'}, + {'1': 'public_id', '3': 2, '4': 1, '5': 3, '10': 'publicId'}, + {'1': 'threshold', '3': 3, '4': 1, '5': 13, '10': 'threshold'}, + { + '1': 'announcement_share', + '3': 5, + '4': 1, + '5': 12, + '10': 'announcementShare' + }, + { + '1': 'public_key_verified_timestamp', + '3': 6, + '4': 1, + '5': 3, + '9': 0, + '10': 'publicKeyVerifiedTimestamp', + '17': true + }, + ], + '3': [ + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted$json + ], + '8': [ + {'1': '_public_key_verified_timestamp'}, + ], +}; + +@$core.Deprecated('Use userDiscoveryMessageDescriptor instead') +const UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted$json = + { + '1': 'AnnouncementShareDecrypted', + '2': [ + { + '1': 'signed_data', + '3': 1, + '4': 1, + '5': 11, + '6': + '.user_discovery.UserDiscoveryMessage.UserDiscoveryPromotion.AnnouncementShareDecrypted.SignedData', + '10': 'signedData' + }, + {'1': 'signature', '3': 2, '4': 1, '5': 12, '10': 'signature'}, + ], + '3': [ + UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData$json + ], +}; + +@$core.Deprecated('Use userDiscoveryMessageDescriptor instead') +const UserDiscoveryMessage_UserDiscoveryPromotion_AnnouncementShareDecrypted_SignedData$json = + { + '1': 'SignedData', + '2': [ + {'1': 'public_id', '3': 1, '4': 1, '5': 3, '10': 'publicId'}, + {'1': 'user_id', '3': 2, '4': 1, '5': 3, '10': 'userId'}, + {'1': 'public_key', '3': 3, '4': 1, '5': 12, '10': 'publicKey'}, + ], +}; + +@$core.Deprecated('Use userDiscoveryMessageDescriptor instead') +const UserDiscoveryMessage_UserDiscoveryRecall$json = { + '1': 'UserDiscoveryRecall', + '2': [ + {'1': 'promotion_id', '3': 1, '4': 1, '5': 3, '10': 'promotionId'}, + ], +}; + +/// Descriptor for `UserDiscoveryMessage`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List userDiscoveryMessageDescriptor = $convert.base64Decode( + 'ChRVc2VyRGlzY292ZXJ5TWVzc2FnZRI+Cgd2ZXJzaW9uGAEgASgLMiQudXNlcl9kaXNjb3Zlcn' + 'kuVXNlckRpc2NvdmVyeVZlcnNpb25SB3ZlcnNpb24SgwEKG3VzZXJfZGlzY292ZXJ5X2Fubm91' + 'bmNlbWVudBgCIAEoCzI+LnVzZXJfZGlzY292ZXJ5LlVzZXJEaXNjb3ZlcnlNZXNzYWdlLlVzZX' + 'JEaXNjb3ZlcnlBbm5vdW5jZW1lbnRIAFIZdXNlckRpc2NvdmVyeUFubm91bmNlbWVudIgBARJ6' + 'Chh1c2VyX2Rpc2NvdmVyeV9wcm9tb3Rpb24YAyABKAsyOy51c2VyX2Rpc2NvdmVyeS5Vc2VyRG' + 'lzY292ZXJ5TWVzc2FnZS5Vc2VyRGlzY292ZXJ5UHJvbW90aW9uSAFSFnVzZXJEaXNjb3ZlcnlQ' + 'cm9tb3Rpb26IAQEScQoVdXNlcl9kaXNjb3ZlcnlfcmVjYWxsGAQgASgLMjgudXNlcl9kaXNjb3' + 'ZlcnkuVXNlckRpc2NvdmVyeU1lc3NhZ2UuVXNlckRpc2NvdmVyeVJlY2FsbEgCUhN1c2VyRGlz' + 'Y292ZXJ5UmVjYWxsiAEBGrYBChlVc2VyRGlzY292ZXJ5QW5ub3VuY2VtZW50EhsKCXB1YmxpY1' + '9pZBgBIAEoA1IIcHVibGljSWQSHAoJdGhyZXNob2xkGAIgASgNUgl0aHJlc2hvbGQSLQoSYW5u' + 'b3VuY2VtZW50X3NoYXJlGAQgASgMUhFhbm5vdW5jZW1lbnRTaGFyZRIvChN2ZXJpZmljYXRpb2' + '5fc2hhcmVzGAYgAygMUhJ2ZXJpZmljYXRpb25TaGFyZXMatAQKFlVzZXJEaXNjb3ZlcnlQcm9t' + 'b3Rpb24SIQoMcHJvbW90aW9uX2lkGAEgASgNUgtwcm9tb3Rpb25JZBIbCglwdWJsaWNfaWQYAi' + 'ABKANSCHB1YmxpY0lkEhwKCXRocmVzaG9sZBgDIAEoDVIJdGhyZXNob2xkEi0KEmFubm91bmNl' + 'bWVudF9zaGFyZRgFIAEoDFIRYW5ub3VuY2VtZW50U2hhcmUSRgodcHVibGljX2tleV92ZXJpZm' + 'llZF90aW1lc3RhbXAYBiABKANIAFIacHVibGljS2V5VmVyaWZpZWRUaW1lc3RhbXCIAQEaogIK' + 'GkFubm91bmNlbWVudFNoYXJlRGVjcnlwdGVkEoIBCgtzaWduZWRfZGF0YRgBIAEoCzJhLnVzZX' + 'JfZGlzY292ZXJ5LlVzZXJEaXNjb3ZlcnlNZXNzYWdlLlVzZXJEaXNjb3ZlcnlQcm9tb3Rpb24u' + 'QW5ub3VuY2VtZW50U2hhcmVEZWNyeXB0ZWQuU2lnbmVkRGF0YVIKc2lnbmVkRGF0YRIcCglzaW' + 'duYXR1cmUYAiABKAxSCXNpZ25hdHVyZRphCgpTaWduZWREYXRhEhsKCXB1YmxpY19pZBgBIAEo' + 'A1IIcHVibGljSWQSFwoHdXNlcl9pZBgCIAEoA1IGdXNlcklkEh0KCnB1YmxpY19rZXkYAyABKA' + 'xSCXB1YmxpY0tleUIgCh5fcHVibGljX2tleV92ZXJpZmllZF90aW1lc3RhbXAaOAoTVXNlckRp' + 'c2NvdmVyeVJlY2FsbBIhCgxwcm9tb3Rpb25faWQYASABKANSC3Byb21vdGlvbklkQh4KHF91c2' + 'VyX2Rpc2NvdmVyeV9hbm5vdW5jZW1lbnRCGwoZX3VzZXJfZGlzY292ZXJ5X3Byb21vdGlvbkIY' + 'ChZfdXNlcl9kaXNjb3ZlcnlfcmVjYWxs'); diff --git a/lib/src/services/flame.service.dart b/lib/src/services/flame.service.dart index f25a5df8..a7172ce1 100644 --- a/lib/src/services/flame.service.dart +++ b/lib/src/services/flame.service.dart @@ -89,6 +89,25 @@ Future incFlameCounter( final group = await twonlyDB.groupsDao.getGroup(groupId); if (group == null) return; + if (group.isDirectChat) { + final contacts = await twonlyDB.groupsDao.getGroupContact( + group.groupId, + ); + if (contacts.length == 1) { + await twonlyDB.contactsDao.updateContact( + contacts.first.userId, + ContactsCompanion( + mediaReceivedCounter: Value( + contacts.first.mediaReceivedCounter + (received ? 1 : 0), + ), + mediaSendCounter: Value( + contacts.first.mediaSendCounter + (received ? 0 : 1), + ), + ), + ); + } + } + final totalMediaCounter = group.totalMediaCounter + 1; var flameCounter = group.flameCounter; var maxFlameCounter = group.maxFlameCounter; diff --git a/lib/src/services/user_discovery.service.dart b/lib/src/services/user_discovery.service.dart index 742cbac3..0f341fce 100644 --- a/lib/src/services/user_discovery.service.dart +++ b/lib/src/services/user_discovery.service.dart @@ -1,26 +1,53 @@ +import 'dart:typed_data'; + import 'package:twonly/core/bridge/wrapper/user_discovery.dart'; import 'package:twonly/globals.dart'; +import 'package:twonly/src/model/protobuf/client/generated/user_discovery/types.pb.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/qr.dart'; import 'package:twonly/src/utils/storage.dart'; -Future initializeOrUpdateUserDiscovery({ - required int threshold, - required int minimumRequiredImagesExchanged, -}) async { - try { - await FlutterUserDiscovery.initializeOrUpdate( - threshold: threshold, - userId: gUser.userId, - publicKey: await getUserPublicKey(), - ); +class UserDiscoveryService { + static Future initializeOrUpdate({ + required int threshold, + required int minimumRequiredImagesExchanged, + }) async { + try { + await FlutterUserDiscovery.initializeOrUpdate( + threshold: threshold, + userId: gUser.userId, + publicKey: await getUserPublicKey(), + ); + await updateUserdata((u) { + u + ..isUserDiscoveryEnabled = true + ..minimumRequiredImagesExchanged = minimumRequiredImagesExchanged; + return u; + }); + } catch (e) { + Log.error(e); + } + } + + static Future getCurrentVersion() async { + try { + return await FlutterUserDiscovery.getCurrentVersion(); + } catch (e) { + Log.error(e); + return null; + } + } + + static Future getCurrentVersionTyped() async { + final version = await getCurrentVersion(); + if (version == null) return null; + return UserDiscoveryVersion.fromBuffer(version); + } + + static Future disable() async { await updateUserdata((u) { - u - ..isUserDiscoveryEnabled = true - ..minimumRequiredImagesExchanged = minimumRequiredImagesExchanged; + u.isUserDiscoveryEnabled = false; return u; }); - } catch (e) { - Log.error(e); } } diff --git a/lib/src/themes/light.dart b/lib/src/themes/light.dart index a6841cd8..e7a0df8d 100644 --- a/lib/src/themes/light.dart +++ b/lib/src/themes/light.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:twonly/src/utils/misc.dart'; -final primaryColor = const Color(0xFF57CC99); +const primaryColor = Color(0xFF57CC99); final ThemeData lightTheme = ThemeData( colorScheme: ColorScheme.fromSeed( @@ -15,18 +16,18 @@ final ButtonStyle primaryColorButtonStyle = FilledButton.styleFrom( backgroundColor: primaryColor, foregroundColor: Colors.black87, padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), - // Adjusting the border radius (default is usually 20+) shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), // Lower number = sharper corners + borderRadius: BorderRadius.circular(8), ), ); -final ButtonStyle secondaryGreyButtonStyle = FilledButton.styleFrom( - backgroundColor: Colors.grey[200], - foregroundColor: Colors.black87, - padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), - // Adjusting the border radius (default is usually 20+) - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), // Lower number = sharper corners - ), -); +ButtonStyle secondaryGreyButtonStyle(BuildContext context) { + return FilledButton.styleFrom( + backgroundColor: isDarkMode(context) ? Colors.grey[800] : Colors.grey[200], + foregroundColor: isDarkMode(context) ? Colors.white : Colors.black87, + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ); +} diff --git a/lib/src/utils/misc.dart b/lib/src/utils/misc.dart index 606a812d..d36d39ae 100644 --- a/lib/src/utils/misc.dart +++ b/lib/src/utils/misc.dart @@ -419,7 +419,6 @@ List formattedText(String input) { spans.add( TextSpan( text: input.substring(lastMatchEnd, match.start), - style: const TextStyle(color: Colors.black), ), ); } @@ -431,7 +430,6 @@ List formattedText(String input) { text: match.group(1), style: const TextStyle( fontWeight: FontWeight.bold, - color: Colors.black, ), ), ); @@ -444,7 +442,6 @@ List formattedText(String input) { spans.add( TextSpan( text: input.substring(lastMatchEnd), - style: const TextStyle(color: Colors.black), ), ); } diff --git a/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart b/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart index 519f3bb6..4840a242 100644 --- a/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart +++ b/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart @@ -16,7 +16,7 @@ class UserDiscoveryDisabledComponent extends StatefulWidget { class _UserDiscoveryDisabledComponentState extends State { Future initializeUserDiscoveryWithDefaultSettings() async { - await initializeOrUpdateUserDiscovery( + await UserDiscoveryService.initializeOrUpdate( threshold: 2, minimumRequiredImagesExchanged: 4, ); @@ -73,7 +73,7 @@ class _UserDiscoveryDisabledComponentState padding: const EdgeInsets.symmetric(horizontal: 24), child: FilledButton( onPressed: () {}, - style: secondaryGreyButtonStyle, + style: secondaryGreyButtonStyle(context), child: const Text('Einstellungen anpassen'), ), ), @@ -82,7 +82,7 @@ class _UserDiscoveryDisabledComponentState padding: const EdgeInsets.symmetric(horizontal: 24), child: FilledButton( onPressed: () {}, - style: secondaryGreyButtonStyle, + style: secondaryGreyButtonStyle(context), child: const Text('Mehr erfahren'), ), ), diff --git a/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart b/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart index 91e50ade..10c6971a 100644 --- a/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart +++ b/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart @@ -1,4 +1,13 @@ +import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/database/daos/contacts.dao.dart'; +import 'package:twonly/src/database/twonly.db.dart'; +import 'package:twonly/src/model/protobuf/client/generated/user_discovery/types.pb.dart'; +import 'package:twonly/src/services/user_discovery.service.dart'; +import 'package:twonly/src/utils/misc.dart'; +import 'package:twonly/src/views/components/alert_dialog.dart'; +import 'package:twonly/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart'; class UserDiscoveryEnabledComponent extends StatefulWidget { const UserDiscoveryEnabledComponent({required this.onUpdate, super.key}); @@ -12,32 +21,110 @@ class UserDiscoveryEnabledComponent extends StatefulWidget { class _UserDiscoveryEnabledComponentState extends State { + UserDiscoveryVersion? _version; + + List _contactsGettingAnnounced = []; + late StreamSubscription> _contactsGettingAnnouncedStream; + + @override + void initState() { + _contactsGettingAnnouncedStream = twonlyDB.contactsDao + .watchContactsAnnouncedViaUserDiscovery() + .listen((contacts) { + setState(() { + _contactsGettingAnnounced = contacts; + }); + }); + _initAsync(); + super.initState(); + } + + @override + void dispose() { + _contactsGettingAnnouncedStream.cancel(); + super.dispose(); + } + + Future _initAsync() async { + final version = await UserDiscoveryService.getCurrentVersionTyped(); + if (mounted) { + setState(() { + _version = version; + }); + } + } + + Future _disableUserDiscovery() async { + final ok = await showAlertDialog( + context, + 'Wirklich deaktivieren?', + 'Wenn du das Feature „Freunde finden“ deaktivierst, werden dir keine Vorschläge mehr angezeigt. Du teilst neuen Kontakten dann auch nicht mehr deine Freunde.', + ); + + if (ok) { + await UserDiscoveryService.disable(); + } + + // This will show the DisabledComponent as the gUser has been updated... + widget.onUpdate(); + } + @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(top: 10), child: ListView( children: [ - const ExpansionTile( - shape: RoundedRectangleBorder(), - collapsedShape: RoundedRectangleBorder(), - tilePadding: EdgeInsets.symmetric(horizontal: 17), - title: Text('Freunde die du teilst'), - subtitle: Text( + ExpansionTile( + shape: const RoundedRectangleBorder(), + backgroundColor: context.color.surfaceContainer, + collapsedShape: const RoundedRectangleBorder(), + tilePadding: const EdgeInsets.symmetric(horizontal: 17), + title: const Text('Freunde die du teilst'), + subtitle: const Text( 'Du teilst nur Freunde, die diese Funktion ebenfalls aktiviert haben und die den von dir festgelegten Schwellenwert erreicht haben.', style: TextStyle(fontSize: 10), ), - children: [], + children: _contactsGettingAnnounced.isEmpty + ? [ + const Padding( + padding: EdgeInsetsGeometry.symmetric(vertical: 12), + child: Text( + 'Bisher teilst du noch niemanden.', + ), + ), + ] + : _contactsGettingAnnounced.map((contact) { + return Text(getContactDisplayName(contact)); + }).toList(), ), ListTile( - title: Text('Einstellungen ändern'), - // onTap: () {}, + title: const Text('Einstellungen ändern'), + onTap: () async { + await context.navPush(const UserDiscoverySettingsView()); + await _initAsync(); + }, + ), + const Divider(), + const ListTile( + title: Text('Mehr erfahren'), + subtitle: Text( + 'In unserem FAQ erklären wir dir wie das Feature "Freunde finden" funktioniert.', + ), + // onTap: _disableUserDiscovery, ), const Divider(), ListTile( - title: Text('Deaktivieren'), - onTap: () {}, + title: const Text('Deaktivieren'), + onTap: _disableUserDiscovery, ), + if (_version != null) + ListTile( + title: Text( + 'Your version: ${_version!.announcement}.${_version!.promotion}', + style: const TextStyle(color: Colors.grey, fontSize: 13), + ), + ), ], ), ); diff --git a/lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart b/lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart new file mode 100644 index 00000000..e7a8e643 --- /dev/null +++ b/lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart @@ -0,0 +1,137 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/services/user_discovery.service.dart'; +import 'package:twonly/src/themes/light.dart'; +import 'package:twonly/src/utils/storage.dart'; + +class UserDiscoverySettingsView extends StatefulWidget { + const UserDiscoverySettingsView({super.key}); + + @override + State createState() => + _UserDiscoverySettingsViewState(); +} + +class _UserDiscoverySettingsViewState extends State { + int _minimumRequiredImagesExchanged = 0; + int _userDiscoveryThreshold = 0; + + @override + void initState() { + _minimumRequiredImagesExchanged = gUser.minimumRequiredImagesExchanged; + _userDiscoveryThreshold = gUser.userDiscoveryThreshold; + super.initState(); + } + + Future _saveChanges() async { + final requiresNewInitialization = + gUser.userDiscoveryThreshold != _userDiscoveryThreshold; + + await updateUserdata((u) { + u + ..minimumRequiredImagesExchanged = _minimumRequiredImagesExchanged + ..userDiscoveryThreshold = _userDiscoveryThreshold; + return u; + }); + + if (requiresNewInitialization) { + await UserDiscoveryService.initializeOrUpdate( + threshold: gUser.userDiscoveryThreshold, + minimumRequiredImagesExchanged: gUser.minimumRequiredImagesExchanged, + ); + } + if (mounted) Navigator.pop(context); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Freunde finden'), + ), + body: Padding( + padding: const EdgeInsets.only(top: 10), + child: ListView( + children: [ + ListTile( + title: const Text('Anzahl an geteilten Bildern'), + subtitle: const Text( + 'Wähle die Mindestanzahl an Bildern, die du mit einer Person ausgetauscht haben musst, bevor du ihr deine Freunde sicher teilst.', + ), + trailing: SizedBox( + width: 60, + child: CupertinoPicker( + magnification: 1.22, + squeeze: 1.2, + useMagnifier: true, + itemExtent: 32, + scrollController: FixedExtentScrollController( + initialItem: _minimumRequiredImagesExchanged, + ), + onSelectedItemChanged: (selectedItem) { + _minimumRequiredImagesExchanged = selectedItem; + setState(() {}); + }, + children: List.generate( + 9, + (index) => Center(child: Text('$index')), + ), + ), + ), + ), + ListTile( + title: const Text('Anzahl an gemeinsame Freunde'), + subtitle: const Text( + 'Wähle aus, wie viele gemeinsame Freunde eine Person haben muss, damit du ihr vorgeschlagen wirst.', + ), + trailing: SizedBox( + width: 60, + child: CupertinoPicker( + magnification: 1.22, + squeeze: 1.2, + useMagnifier: true, + itemExtent: 32, + scrollController: FixedExtentScrollController( + initialItem: _userDiscoveryThreshold - 2, + ), + onSelectedItemChanged: (selectedItem) { + _userDiscoveryThreshold = selectedItem + 2; + setState(() {}); + }, + children: List.generate( + 9, + (index) => Center(child: Text('${index + 2}')), + ), + ), + ), + ), + const SizedBox( + height: 30, + ), + if (_minimumRequiredImagesExchanged != + gUser.minimumRequiredImagesExchanged || + _userDiscoveryThreshold != gUser.userDiscoveryThreshold) + Padding( + padding: const EdgeInsets.all(17), + child: FilledButton( + onPressed: _saveChanges, + style: primaryColorButtonStyle.merge( + FilledButton.styleFrom( + padding: EdgeInsets.symmetric( + horizontal: 32, + vertical: 24, + ), + ), + ), + child: const Text('Änderungen übernehmen'), + ), + ), + ], + ), + ), + ); + } +} diff --git a/scripts/generate_proto.sh b/scripts/generate_proto.sh index 40880f92..e6c8ca1a 100755 --- a/scripts/generate_proto.sh +++ b/scripts/generate_proto.sh @@ -17,6 +17,9 @@ protoc --proto_path="$CLIENT_DIR" --dart_out="$GENERATED_DIR" "groups.proto" protoc --proto_path="$CLIENT_DIR" --dart_out="$GENERATED_DIR" "qr.proto" protoc --proto_path="$CLIENT_DIR" --dart_out="$GENERATED_DIR" "data.proto" +mkdir "$GENERATED_DIR/user_discovery/" &>/dev/null +protoc --proto_path="./rust_dependencies/protocols/src/user_discovery/" --dart_out="$GENERATED_DIR/user_discovery/" "types.proto" + protoc --proto_path="$CLIENT_DIR" --dart_out="$GENERATED_DIR" "push_notification.proto" protoc --proto_path="$CLIENT_DIR" --swift_out="./ios/NotificationService/" "push_notification.proto" diff --git a/test/drift/twonly_db/generated/schema.dart b/test/drift/twonly_db/generated/schema.dart index 49f49d7b..ba56c197 100644 --- a/test/drift/twonly_db/generated/schema.dart +++ b/test/drift/twonly_db/generated/schema.dart @@ -16,6 +16,7 @@ import 'schema_v9.dart' as v9; import 'schema_v10.dart' as v10; import 'schema_v11.dart' as v11; import 'schema_v12.dart' as v12; +import 'schema_v13.dart' as v13; class GeneratedHelper implements SchemaInstantiationHelper { @override @@ -45,10 +46,12 @@ class GeneratedHelper implements SchemaInstantiationHelper { return v11.DatabaseAtV11(db); case 12: return v12.DatabaseAtV12(db); + case 13: + return v13.DatabaseAtV13(db); default: throw MissingSchemaException(version, versions); } } - static const versions = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + static const versions = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]; } diff --git a/test/drift/twonly_db/generated/schema_v13.dart b/test/drift/twonly_db/generated/schema_v13.dart new file mode 100644 index 00000000..4f14bd6f --- /dev/null +++ b/test/drift/twonly_db/generated/schema_v13.dart @@ -0,0 +1,9439 @@ +// dart format width=80 +import 'dart:typed_data' as i2; +// GENERATED BY drift_dev, DO NOT MODIFY. +// ignore_for_file: type=lint,unused_import +// +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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn username = GeneratedColumn( + 'username', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn displayName = GeneratedColumn( + 'display_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn nickName = GeneratedColumn( + 'nick_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn avatarSvgCompressed = + GeneratedColumn( + 'avatar_svg_compressed', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn senderProfileCounter = GeneratedColumn( + 'sender_profile_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn accepted = GeneratedColumn( + 'accepted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (accepted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deletedByUser = GeneratedColumn( + 'deleted_by_user', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (deleted_by_user IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn requested = GeneratedColumn( + 'requested', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (requested IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn blocked = GeneratedColumn( + 'blocked', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (blocked IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn verified = GeneratedColumn( + 'verified', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (verified IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn accountDeleted = GeneratedColumn( + 'account_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (account_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn userDiscoveryVersion = + GeneratedColumn( + 'user_discovery_version', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mediaSendCounter = GeneratedColumn( + 'media_send_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn mediaReceivedCounter = GeneratedColumn( + 'media_received_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [ + userId, + username, + displayName, + nickName, + avatarSvgCompressed, + senderProfileCounter, + accepted, + deletedByUser, + requested, + blocked, + verified, + accountDeleted, + createdAt, + userDiscoveryVersion, + mediaSendCounter, + mediaReceivedCounter, + ]; + @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'], + ), + avatarSvgCompressed: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}avatar_svg_compressed'], + ), + senderProfileCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_profile_counter'], + )!, + accepted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}accepted'], + )!, + deletedByUser: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}deleted_by_user'], + )!, + requested: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}requested'], + )!, + blocked: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}blocked'], + )!, + verified: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}verified'], + )!, + accountDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}account_deleted'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + userDiscoveryVersion: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}user_discovery_version'], + ), + mediaSendCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_send_counter'], + )!, + mediaReceivedCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_received_counter'], + )!, + ); + } + + @override + Contacts createAlias(String alias) { + return Contacts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(user_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ContactsData extends DataClass implements Insertable { + final int userId; + final String username; + final String? displayName; + final String? nickName; + final i2.Uint8List? avatarSvgCompressed; + final int senderProfileCounter; + final int accepted; + final int deletedByUser; + final int requested; + final int blocked; + final int verified; + final int accountDeleted; + final int createdAt; + final i2.Uint8List? userDiscoveryVersion; + final int mediaSendCounter; + final int mediaReceivedCounter; + const ContactsData({ + required this.userId, + required this.username, + this.displayName, + this.nickName, + this.avatarSvgCompressed, + required this.senderProfileCounter, + required this.accepted, + required this.deletedByUser, + required this.requested, + required this.blocked, + required this.verified, + required this.accountDeleted, + required this.createdAt, + this.userDiscoveryVersion, + required this.mediaSendCounter, + required this.mediaReceivedCounter, + }); + @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 || avatarSvgCompressed != null) { + map['avatar_svg_compressed'] = Variable( + avatarSvgCompressed, + ); + } + map['sender_profile_counter'] = Variable(senderProfileCounter); + map['accepted'] = Variable(accepted); + map['deleted_by_user'] = Variable(deletedByUser); + map['requested'] = Variable(requested); + map['blocked'] = Variable(blocked); + map['verified'] = Variable(verified); + map['account_deleted'] = Variable(accountDeleted); + map['created_at'] = Variable(createdAt); + if (!nullToAbsent || userDiscoveryVersion != null) { + map['user_discovery_version'] = Variable( + userDiscoveryVersion, + ); + } + map['media_send_counter'] = Variable(mediaSendCounter); + map['media_received_counter'] = Variable(mediaReceivedCounter); + 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), + avatarSvgCompressed: avatarSvgCompressed == null && nullToAbsent + ? const Value.absent() + : Value(avatarSvgCompressed), + senderProfileCounter: Value(senderProfileCounter), + accepted: Value(accepted), + deletedByUser: Value(deletedByUser), + requested: Value(requested), + blocked: Value(blocked), + verified: Value(verified), + accountDeleted: Value(accountDeleted), + createdAt: Value(createdAt), + userDiscoveryVersion: userDiscoveryVersion == null && nullToAbsent + ? const Value.absent() + : Value(userDiscoveryVersion), + mediaSendCounter: Value(mediaSendCounter), + mediaReceivedCounter: Value(mediaReceivedCounter), + ); + } + + 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']), + avatarSvgCompressed: serializer.fromJson( + json['avatarSvgCompressed'], + ), + senderProfileCounter: serializer.fromJson( + json['senderProfileCounter'], + ), + accepted: serializer.fromJson(json['accepted']), + deletedByUser: serializer.fromJson(json['deletedByUser']), + requested: serializer.fromJson(json['requested']), + blocked: serializer.fromJson(json['blocked']), + verified: serializer.fromJson(json['verified']), + accountDeleted: serializer.fromJson(json['accountDeleted']), + createdAt: serializer.fromJson(json['createdAt']), + userDiscoveryVersion: serializer.fromJson( + json['userDiscoveryVersion'], + ), + mediaSendCounter: serializer.fromJson(json['mediaSendCounter']), + mediaReceivedCounter: serializer.fromJson( + json['mediaReceivedCounter'], + ), + ); + } + @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), + 'avatarSvgCompressed': serializer.toJson( + avatarSvgCompressed, + ), + 'senderProfileCounter': serializer.toJson(senderProfileCounter), + 'accepted': serializer.toJson(accepted), + 'deletedByUser': serializer.toJson(deletedByUser), + 'requested': serializer.toJson(requested), + 'blocked': serializer.toJson(blocked), + 'verified': serializer.toJson(verified), + 'accountDeleted': serializer.toJson(accountDeleted), + 'createdAt': serializer.toJson(createdAt), + 'userDiscoveryVersion': serializer.toJson( + userDiscoveryVersion, + ), + 'mediaSendCounter': serializer.toJson(mediaSendCounter), + 'mediaReceivedCounter': serializer.toJson(mediaReceivedCounter), + }; + } + + ContactsData copyWith({ + int? userId, + String? username, + Value displayName = const Value.absent(), + Value nickName = const Value.absent(), + Value avatarSvgCompressed = const Value.absent(), + int? senderProfileCounter, + int? accepted, + int? deletedByUser, + int? requested, + int? blocked, + int? verified, + int? accountDeleted, + int? createdAt, + Value userDiscoveryVersion = const Value.absent(), + int? mediaSendCounter, + int? mediaReceivedCounter, + }) => ContactsData( + userId: userId ?? this.userId, + username: username ?? this.username, + displayName: displayName.present ? displayName.value : this.displayName, + nickName: nickName.present ? nickName.value : this.nickName, + avatarSvgCompressed: avatarSvgCompressed.present + ? avatarSvgCompressed.value + : this.avatarSvgCompressed, + senderProfileCounter: senderProfileCounter ?? this.senderProfileCounter, + accepted: accepted ?? this.accepted, + deletedByUser: deletedByUser ?? this.deletedByUser, + requested: requested ?? this.requested, + blocked: blocked ?? this.blocked, + verified: verified ?? this.verified, + accountDeleted: accountDeleted ?? this.accountDeleted, + createdAt: createdAt ?? this.createdAt, + userDiscoveryVersion: userDiscoveryVersion.present + ? userDiscoveryVersion.value + : this.userDiscoveryVersion, + mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter, + mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter, + ); + 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, + avatarSvgCompressed: data.avatarSvgCompressed.present + ? data.avatarSvgCompressed.value + : this.avatarSvgCompressed, + senderProfileCounter: data.senderProfileCounter.present + ? data.senderProfileCounter.value + : this.senderProfileCounter, + accepted: data.accepted.present ? data.accepted.value : this.accepted, + deletedByUser: data.deletedByUser.present + ? data.deletedByUser.value + : this.deletedByUser, + 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, + accountDeleted: data.accountDeleted.present + ? data.accountDeleted.value + : this.accountDeleted, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + userDiscoveryVersion: data.userDiscoveryVersion.present + ? data.userDiscoveryVersion.value + : this.userDiscoveryVersion, + mediaSendCounter: data.mediaSendCounter.present + ? data.mediaSendCounter.value + : this.mediaSendCounter, + mediaReceivedCounter: data.mediaReceivedCounter.present + ? data.mediaReceivedCounter.value + : this.mediaReceivedCounter, + ); + } + + @override + String toString() { + return (StringBuffer('ContactsData(') + ..write('userId: $userId, ') + ..write('username: $username, ') + ..write('displayName: $displayName, ') + ..write('nickName: $nickName, ') + ..write('avatarSvgCompressed: $avatarSvgCompressed, ') + ..write('senderProfileCounter: $senderProfileCounter, ') + ..write('accepted: $accepted, ') + ..write('deletedByUser: $deletedByUser, ') + ..write('requested: $requested, ') + ..write('blocked: $blocked, ') + ..write('verified: $verified, ') + ..write('accountDeleted: $accountDeleted, ') + ..write('createdAt: $createdAt, ') + ..write('userDiscoveryVersion: $userDiscoveryVersion, ') + ..write('mediaSendCounter: $mediaSendCounter, ') + ..write('mediaReceivedCounter: $mediaReceivedCounter') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + userId, + username, + displayName, + nickName, + $driftBlobEquality.hash(avatarSvgCompressed), + senderProfileCounter, + accepted, + deletedByUser, + requested, + blocked, + verified, + accountDeleted, + createdAt, + $driftBlobEquality.hash(userDiscoveryVersion), + mediaSendCounter, + mediaReceivedCounter, + ); + @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 && + $driftBlobEquality.equals( + other.avatarSvgCompressed, + this.avatarSvgCompressed, + ) && + other.senderProfileCounter == this.senderProfileCounter && + other.accepted == this.accepted && + other.deletedByUser == this.deletedByUser && + other.requested == this.requested && + other.blocked == this.blocked && + other.verified == this.verified && + other.accountDeleted == this.accountDeleted && + other.createdAt == this.createdAt && + $driftBlobEquality.equals( + other.userDiscoveryVersion, + this.userDiscoveryVersion, + ) && + other.mediaSendCounter == this.mediaSendCounter && + other.mediaReceivedCounter == this.mediaReceivedCounter); +} + +class ContactsCompanion extends UpdateCompanion { + final Value userId; + final Value username; + final Value displayName; + final Value nickName; + final Value avatarSvgCompressed; + final Value senderProfileCounter; + final Value accepted; + final Value deletedByUser; + final Value requested; + final Value blocked; + final Value verified; + final Value accountDeleted; + final Value createdAt; + final Value userDiscoveryVersion; + final Value mediaSendCounter; + final Value mediaReceivedCounter; + const ContactsCompanion({ + this.userId = const Value.absent(), + this.username = const Value.absent(), + this.displayName = const Value.absent(), + this.nickName = const Value.absent(), + this.avatarSvgCompressed = const Value.absent(), + this.senderProfileCounter = const Value.absent(), + this.accepted = const Value.absent(), + this.deletedByUser = const Value.absent(), + this.requested = const Value.absent(), + this.blocked = const Value.absent(), + this.verified = const Value.absent(), + this.accountDeleted = const Value.absent(), + this.createdAt = const Value.absent(), + this.userDiscoveryVersion = const Value.absent(), + this.mediaSendCounter = const Value.absent(), + this.mediaReceivedCounter = const Value.absent(), + }); + ContactsCompanion.insert({ + this.userId = const Value.absent(), + required String username, + this.displayName = const Value.absent(), + this.nickName = const Value.absent(), + this.avatarSvgCompressed = const Value.absent(), + this.senderProfileCounter = const Value.absent(), + this.accepted = const Value.absent(), + this.deletedByUser = const Value.absent(), + this.requested = const Value.absent(), + this.blocked = const Value.absent(), + this.verified = const Value.absent(), + this.accountDeleted = const Value.absent(), + this.createdAt = const Value.absent(), + this.userDiscoveryVersion = const Value.absent(), + this.mediaSendCounter = const Value.absent(), + this.mediaReceivedCounter = const Value.absent(), + }) : username = Value(username); + static Insertable custom({ + Expression? userId, + Expression? username, + Expression? displayName, + Expression? nickName, + Expression? avatarSvgCompressed, + Expression? senderProfileCounter, + Expression? accepted, + Expression? deletedByUser, + Expression? requested, + Expression? blocked, + Expression? verified, + Expression? accountDeleted, + Expression? createdAt, + Expression? userDiscoveryVersion, + Expression? mediaSendCounter, + Expression? mediaReceivedCounter, + }) { + 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 (avatarSvgCompressed != null) + 'avatar_svg_compressed': avatarSvgCompressed, + if (senderProfileCounter != null) + 'sender_profile_counter': senderProfileCounter, + if (accepted != null) 'accepted': accepted, + if (deletedByUser != null) 'deleted_by_user': deletedByUser, + if (requested != null) 'requested': requested, + if (blocked != null) 'blocked': blocked, + if (verified != null) 'verified': verified, + if (accountDeleted != null) 'account_deleted': accountDeleted, + if (createdAt != null) 'created_at': createdAt, + if (userDiscoveryVersion != null) + 'user_discovery_version': userDiscoveryVersion, + if (mediaSendCounter != null) 'media_send_counter': mediaSendCounter, + if (mediaReceivedCounter != null) + 'media_received_counter': mediaReceivedCounter, + }); + } + + ContactsCompanion copyWith({ + Value? userId, + Value? username, + Value? displayName, + Value? nickName, + Value? avatarSvgCompressed, + Value? senderProfileCounter, + Value? accepted, + Value? deletedByUser, + Value? requested, + Value? blocked, + Value? verified, + Value? accountDeleted, + Value? createdAt, + Value? userDiscoveryVersion, + Value? mediaSendCounter, + Value? mediaReceivedCounter, + }) { + return ContactsCompanion( + userId: userId ?? this.userId, + username: username ?? this.username, + displayName: displayName ?? this.displayName, + nickName: nickName ?? this.nickName, + avatarSvgCompressed: avatarSvgCompressed ?? this.avatarSvgCompressed, + senderProfileCounter: senderProfileCounter ?? this.senderProfileCounter, + accepted: accepted ?? this.accepted, + deletedByUser: deletedByUser ?? this.deletedByUser, + requested: requested ?? this.requested, + blocked: blocked ?? this.blocked, + verified: verified ?? this.verified, + accountDeleted: accountDeleted ?? this.accountDeleted, + createdAt: createdAt ?? this.createdAt, + userDiscoveryVersion: userDiscoveryVersion ?? this.userDiscoveryVersion, + mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter, + mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter, + ); + } + + @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 (avatarSvgCompressed.present) { + map['avatar_svg_compressed'] = Variable( + avatarSvgCompressed.value, + ); + } + if (senderProfileCounter.present) { + map['sender_profile_counter'] = Variable(senderProfileCounter.value); + } + if (accepted.present) { + map['accepted'] = Variable(accepted.value); + } + if (deletedByUser.present) { + map['deleted_by_user'] = Variable(deletedByUser.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 (accountDeleted.present) { + map['account_deleted'] = Variable(accountDeleted.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (userDiscoveryVersion.present) { + map['user_discovery_version'] = Variable( + userDiscoveryVersion.value, + ); + } + if (mediaSendCounter.present) { + map['media_send_counter'] = Variable(mediaSendCounter.value); + } + if (mediaReceivedCounter.present) { + map['media_received_counter'] = Variable(mediaReceivedCounter.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ContactsCompanion(') + ..write('userId: $userId, ') + ..write('username: $username, ') + ..write('displayName: $displayName, ') + ..write('nickName: $nickName, ') + ..write('avatarSvgCompressed: $avatarSvgCompressed, ') + ..write('senderProfileCounter: $senderProfileCounter, ') + ..write('accepted: $accepted, ') + ..write('deletedByUser: $deletedByUser, ') + ..write('requested: $requested, ') + ..write('blocked: $blocked, ') + ..write('verified: $verified, ') + ..write('accountDeleted: $accountDeleted, ') + ..write('createdAt: $createdAt, ') + ..write('userDiscoveryVersion: $userDiscoveryVersion, ') + ..write('mediaSendCounter: $mediaSendCounter, ') + ..write('mediaReceivedCounter: $mediaReceivedCounter') + ..write(')')) + .toString(); + } +} + +class Groups extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Groups(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isGroupAdmin = GeneratedColumn( + 'is_group_admin', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_group_admin IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn isDirectChat = GeneratedColumn( + 'is_direct_chat', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_direct_chat IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn pinned = GeneratedColumn( + 'pinned', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (pinned IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn archived = GeneratedColumn( + 'archived', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (archived IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn joinedGroup = GeneratedColumn( + 'joined_group', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (joined_group IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn leftGroup = GeneratedColumn( + 'left_group', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (left_group IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deletedContent = GeneratedColumn( + 'deleted_content', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (deleted_content IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stateVersionId = GeneratedColumn( + 'state_version_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stateEncryptionKey = + GeneratedColumn( + 'state_encryption_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn myGroupPrivateKey = + GeneratedColumn( + 'my_group_private_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn groupName = GeneratedColumn( + 'group_name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn draftMessage = GeneratedColumn( + 'draft_message', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn totalMediaCounter = GeneratedColumn( + 'total_media_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn alsoBestFriend = GeneratedColumn( + 'also_best_friend', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (also_best_friend IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deleteMessagesAfterMilliseconds = + GeneratedColumn( + 'delete_messages_after_milliseconds', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 86400000', + defaultValue: const CustomExpression('86400000'), + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn lastMessageSend = GeneratedColumn( + 'last_message_send', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessageReceived = GeneratedColumn( + 'last_message_received', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastFlameCounterChange = GeneratedColumn( + 'last_flame_counter_change', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastFlameSync = GeneratedColumn( + 'last_flame_sync', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn flameCounter = GeneratedColumn( + 'flame_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn maxFlameCounter = GeneratedColumn( + 'max_flame_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn maxFlameCounterFrom = GeneratedColumn( + 'max_flame_counter_from', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessageExchange = GeneratedColumn( + 'last_message_exchange', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupId, + isGroupAdmin, + isDirectChat, + pinned, + archived, + joinedGroup, + leftGroup, + deletedContent, + stateVersionId, + stateEncryptionKey, + myGroupPrivateKey, + groupName, + draftMessage, + totalMediaCounter, + alsoBestFriend, + deleteMessagesAfterMilliseconds, + createdAt, + lastMessageSend, + lastMessageReceived, + lastFlameCounterChange, + lastFlameSync, + flameCounter, + maxFlameCounter, + maxFlameCounterFrom, + lastMessageExchange, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'groups'; + @override + Set get $primaryKey => {groupId}; + @override + GroupsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupsData( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + isGroupAdmin: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_group_admin'], + )!, + isDirectChat: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_direct_chat'], + )!, + pinned: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}pinned'], + )!, + archived: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}archived'], + )!, + joinedGroup: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}joined_group'], + )!, + leftGroup: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}left_group'], + )!, + deletedContent: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}deleted_content'], + )!, + stateVersionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}state_version_id'], + )!, + stateEncryptionKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}state_encryption_key'], + ), + myGroupPrivateKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}my_group_private_key'], + ), + groupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_name'], + )!, + draftMessage: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}draft_message'], + ), + totalMediaCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}total_media_counter'], + )!, + alsoBestFriend: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}also_best_friend'], + )!, + deleteMessagesAfterMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}delete_messages_after_milliseconds'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + lastMessageSend: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_send'], + ), + lastMessageReceived: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_received'], + ), + lastFlameCounterChange: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_flame_counter_change'], + ), + lastFlameSync: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_flame_sync'], + ), + flameCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}flame_counter'], + )!, + maxFlameCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}max_flame_counter'], + )!, + maxFlameCounterFrom: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}max_flame_counter_from'], + ), + lastMessageExchange: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_exchange'], + )!, + ); + } + + @override + Groups createAlias(String alias) { + return Groups(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(group_id)']; + @override + bool get dontWriteConstraints => true; +} + +class GroupsData extends DataClass implements Insertable { + final String groupId; + final int isGroupAdmin; + final int isDirectChat; + final int pinned; + final int archived; + final int joinedGroup; + final int leftGroup; + final int deletedContent; + final int stateVersionId; + final i2.Uint8List? stateEncryptionKey; + final i2.Uint8List? myGroupPrivateKey; + final String groupName; + final String? draftMessage; + final int totalMediaCounter; + final int alsoBestFriend; + final int deleteMessagesAfterMilliseconds; + final int createdAt; + final int? lastMessageSend; + final int? lastMessageReceived; + final int? lastFlameCounterChange; + final int? lastFlameSync; + final int flameCounter; + final int maxFlameCounter; + final int? maxFlameCounterFrom; + final int lastMessageExchange; + const GroupsData({ + required this.groupId, + required this.isGroupAdmin, + required this.isDirectChat, + required this.pinned, + required this.archived, + required this.joinedGroup, + required this.leftGroup, + required this.deletedContent, + required this.stateVersionId, + this.stateEncryptionKey, + this.myGroupPrivateKey, + required this.groupName, + this.draftMessage, + required this.totalMediaCounter, + required this.alsoBestFriend, + required this.deleteMessagesAfterMilliseconds, + required this.createdAt, + this.lastMessageSend, + this.lastMessageReceived, + this.lastFlameCounterChange, + this.lastFlameSync, + required this.flameCounter, + required this.maxFlameCounter, + this.maxFlameCounterFrom, + required this.lastMessageExchange, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['is_group_admin'] = Variable(isGroupAdmin); + map['is_direct_chat'] = Variable(isDirectChat); + map['pinned'] = Variable(pinned); + map['archived'] = Variable(archived); + map['joined_group'] = Variable(joinedGroup); + map['left_group'] = Variable(leftGroup); + map['deleted_content'] = Variable(deletedContent); + map['state_version_id'] = Variable(stateVersionId); + if (!nullToAbsent || stateEncryptionKey != null) { + map['state_encryption_key'] = Variable(stateEncryptionKey); + } + if (!nullToAbsent || myGroupPrivateKey != null) { + map['my_group_private_key'] = Variable(myGroupPrivateKey); + } + map['group_name'] = Variable(groupName); + if (!nullToAbsent || draftMessage != null) { + map['draft_message'] = Variable(draftMessage); + } + map['total_media_counter'] = Variable(totalMediaCounter); + map['also_best_friend'] = Variable(alsoBestFriend); + map['delete_messages_after_milliseconds'] = Variable( + deleteMessagesAfterMilliseconds, + ); + map['created_at'] = Variable(createdAt); + 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['flame_counter'] = Variable(flameCounter); + map['max_flame_counter'] = Variable(maxFlameCounter); + if (!nullToAbsent || maxFlameCounterFrom != null) { + map['max_flame_counter_from'] = Variable(maxFlameCounterFrom); + } + map['last_message_exchange'] = Variable(lastMessageExchange); + return map; + } + + GroupsCompanion toCompanion(bool nullToAbsent) { + return GroupsCompanion( + groupId: Value(groupId), + isGroupAdmin: Value(isGroupAdmin), + isDirectChat: Value(isDirectChat), + pinned: Value(pinned), + archived: Value(archived), + joinedGroup: Value(joinedGroup), + leftGroup: Value(leftGroup), + deletedContent: Value(deletedContent), + stateVersionId: Value(stateVersionId), + stateEncryptionKey: stateEncryptionKey == null && nullToAbsent + ? const Value.absent() + : Value(stateEncryptionKey), + myGroupPrivateKey: myGroupPrivateKey == null && nullToAbsent + ? const Value.absent() + : Value(myGroupPrivateKey), + groupName: Value(groupName), + draftMessage: draftMessage == null && nullToAbsent + ? const Value.absent() + : Value(draftMessage), + totalMediaCounter: Value(totalMediaCounter), + alsoBestFriend: Value(alsoBestFriend), + deleteMessagesAfterMilliseconds: Value(deleteMessagesAfterMilliseconds), + createdAt: Value(createdAt), + 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), + flameCounter: Value(flameCounter), + maxFlameCounter: Value(maxFlameCounter), + maxFlameCounterFrom: maxFlameCounterFrom == null && nullToAbsent + ? const Value.absent() + : Value(maxFlameCounterFrom), + lastMessageExchange: Value(lastMessageExchange), + ); + } + + factory GroupsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupsData( + groupId: serializer.fromJson(json['groupId']), + isGroupAdmin: serializer.fromJson(json['isGroupAdmin']), + isDirectChat: serializer.fromJson(json['isDirectChat']), + pinned: serializer.fromJson(json['pinned']), + archived: serializer.fromJson(json['archived']), + joinedGroup: serializer.fromJson(json['joinedGroup']), + leftGroup: serializer.fromJson(json['leftGroup']), + deletedContent: serializer.fromJson(json['deletedContent']), + stateVersionId: serializer.fromJson(json['stateVersionId']), + stateEncryptionKey: serializer.fromJson( + json['stateEncryptionKey'], + ), + myGroupPrivateKey: serializer.fromJson( + json['myGroupPrivateKey'], + ), + groupName: serializer.fromJson(json['groupName']), + draftMessage: serializer.fromJson(json['draftMessage']), + totalMediaCounter: serializer.fromJson(json['totalMediaCounter']), + alsoBestFriend: serializer.fromJson(json['alsoBestFriend']), + deleteMessagesAfterMilliseconds: serializer.fromJson( + json['deleteMessagesAfterMilliseconds'], + ), + createdAt: serializer.fromJson(json['createdAt']), + lastMessageSend: serializer.fromJson(json['lastMessageSend']), + lastMessageReceived: serializer.fromJson( + json['lastMessageReceived'], + ), + lastFlameCounterChange: serializer.fromJson( + json['lastFlameCounterChange'], + ), + lastFlameSync: serializer.fromJson(json['lastFlameSync']), + flameCounter: serializer.fromJson(json['flameCounter']), + maxFlameCounter: serializer.fromJson(json['maxFlameCounter']), + maxFlameCounterFrom: serializer.fromJson( + json['maxFlameCounterFrom'], + ), + lastMessageExchange: serializer.fromJson( + json['lastMessageExchange'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'isGroupAdmin': serializer.toJson(isGroupAdmin), + 'isDirectChat': serializer.toJson(isDirectChat), + 'pinned': serializer.toJson(pinned), + 'archived': serializer.toJson(archived), + 'joinedGroup': serializer.toJson(joinedGroup), + 'leftGroup': serializer.toJson(leftGroup), + 'deletedContent': serializer.toJson(deletedContent), + 'stateVersionId': serializer.toJson(stateVersionId), + 'stateEncryptionKey': serializer.toJson( + stateEncryptionKey, + ), + 'myGroupPrivateKey': serializer.toJson(myGroupPrivateKey), + 'groupName': serializer.toJson(groupName), + 'draftMessage': serializer.toJson(draftMessage), + 'totalMediaCounter': serializer.toJson(totalMediaCounter), + 'alsoBestFriend': serializer.toJson(alsoBestFriend), + 'deleteMessagesAfterMilliseconds': serializer.toJson( + deleteMessagesAfterMilliseconds, + ), + 'createdAt': serializer.toJson(createdAt), + 'lastMessageSend': serializer.toJson(lastMessageSend), + 'lastMessageReceived': serializer.toJson(lastMessageReceived), + 'lastFlameCounterChange': serializer.toJson(lastFlameCounterChange), + 'lastFlameSync': serializer.toJson(lastFlameSync), + 'flameCounter': serializer.toJson(flameCounter), + 'maxFlameCounter': serializer.toJson(maxFlameCounter), + 'maxFlameCounterFrom': serializer.toJson(maxFlameCounterFrom), + 'lastMessageExchange': serializer.toJson(lastMessageExchange), + }; + } + + GroupsData copyWith({ + String? groupId, + int? isGroupAdmin, + int? isDirectChat, + int? pinned, + int? archived, + int? joinedGroup, + int? leftGroup, + int? deletedContent, + int? stateVersionId, + Value stateEncryptionKey = const Value.absent(), + Value myGroupPrivateKey = const Value.absent(), + String? groupName, + Value draftMessage = const Value.absent(), + int? totalMediaCounter, + int? alsoBestFriend, + int? deleteMessagesAfterMilliseconds, + int? createdAt, + Value lastMessageSend = const Value.absent(), + Value lastMessageReceived = const Value.absent(), + Value lastFlameCounterChange = const Value.absent(), + Value lastFlameSync = const Value.absent(), + int? flameCounter, + int? maxFlameCounter, + Value maxFlameCounterFrom = const Value.absent(), + int? lastMessageExchange, + }) => GroupsData( + groupId: groupId ?? this.groupId, + isGroupAdmin: isGroupAdmin ?? this.isGroupAdmin, + isDirectChat: isDirectChat ?? this.isDirectChat, + pinned: pinned ?? this.pinned, + archived: archived ?? this.archived, + joinedGroup: joinedGroup ?? this.joinedGroup, + leftGroup: leftGroup ?? this.leftGroup, + deletedContent: deletedContent ?? this.deletedContent, + stateVersionId: stateVersionId ?? this.stateVersionId, + stateEncryptionKey: stateEncryptionKey.present + ? stateEncryptionKey.value + : this.stateEncryptionKey, + myGroupPrivateKey: myGroupPrivateKey.present + ? myGroupPrivateKey.value + : this.myGroupPrivateKey, + groupName: groupName ?? this.groupName, + draftMessage: draftMessage.present ? draftMessage.value : this.draftMessage, + totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter, + alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + deleteMessagesAfterMilliseconds ?? this.deleteMessagesAfterMilliseconds, + createdAt: createdAt ?? this.createdAt, + 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, + flameCounter: flameCounter ?? this.flameCounter, + maxFlameCounter: maxFlameCounter ?? this.maxFlameCounter, + maxFlameCounterFrom: maxFlameCounterFrom.present + ? maxFlameCounterFrom.value + : this.maxFlameCounterFrom, + lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, + ); + GroupsData copyWithCompanion(GroupsCompanion data) { + return GroupsData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + isGroupAdmin: data.isGroupAdmin.present + ? data.isGroupAdmin.value + : this.isGroupAdmin, + isDirectChat: data.isDirectChat.present + ? data.isDirectChat.value + : this.isDirectChat, + pinned: data.pinned.present ? data.pinned.value : this.pinned, + archived: data.archived.present ? data.archived.value : this.archived, + joinedGroup: data.joinedGroup.present + ? data.joinedGroup.value + : this.joinedGroup, + leftGroup: data.leftGroup.present ? data.leftGroup.value : this.leftGroup, + deletedContent: data.deletedContent.present + ? data.deletedContent.value + : this.deletedContent, + stateVersionId: data.stateVersionId.present + ? data.stateVersionId.value + : this.stateVersionId, + stateEncryptionKey: data.stateEncryptionKey.present + ? data.stateEncryptionKey.value + : this.stateEncryptionKey, + myGroupPrivateKey: data.myGroupPrivateKey.present + ? data.myGroupPrivateKey.value + : this.myGroupPrivateKey, + groupName: data.groupName.present ? data.groupName.value : this.groupName, + draftMessage: data.draftMessage.present + ? data.draftMessage.value + : this.draftMessage, + totalMediaCounter: data.totalMediaCounter.present + ? data.totalMediaCounter.value + : this.totalMediaCounter, + alsoBestFriend: data.alsoBestFriend.present + ? data.alsoBestFriend.value + : this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + data.deleteMessagesAfterMilliseconds.present + ? data.deleteMessagesAfterMilliseconds.value + : this.deleteMessagesAfterMilliseconds, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + 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, + flameCounter: data.flameCounter.present + ? data.flameCounter.value + : this.flameCounter, + maxFlameCounter: data.maxFlameCounter.present + ? data.maxFlameCounter.value + : this.maxFlameCounter, + maxFlameCounterFrom: data.maxFlameCounterFrom.present + ? data.maxFlameCounterFrom.value + : this.maxFlameCounterFrom, + lastMessageExchange: data.lastMessageExchange.present + ? data.lastMessageExchange.value + : this.lastMessageExchange, + ); + } + + @override + String toString() { + return (StringBuffer('GroupsData(') + ..write('groupId: $groupId, ') + ..write('isGroupAdmin: $isGroupAdmin, ') + ..write('isDirectChat: $isDirectChat, ') + ..write('pinned: $pinned, ') + ..write('archived: $archived, ') + ..write('joinedGroup: $joinedGroup, ') + ..write('leftGroup: $leftGroup, ') + ..write('deletedContent: $deletedContent, ') + ..write('stateVersionId: $stateVersionId, ') + ..write('stateEncryptionKey: $stateEncryptionKey, ') + ..write('myGroupPrivateKey: $myGroupPrivateKey, ') + ..write('groupName: $groupName, ') + ..write('draftMessage: $draftMessage, ') + ..write('totalMediaCounter: $totalMediaCounter, ') + ..write('alsoBestFriend: $alsoBestFriend, ') + ..write( + 'deleteMessagesAfterMilliseconds: $deleteMessagesAfterMilliseconds, ', + ) + ..write('createdAt: $createdAt, ') + ..write('lastMessageSend: $lastMessageSend, ') + ..write('lastMessageReceived: $lastMessageReceived, ') + ..write('lastFlameCounterChange: $lastFlameCounterChange, ') + ..write('lastFlameSync: $lastFlameSync, ') + ..write('flameCounter: $flameCounter, ') + ..write('maxFlameCounter: $maxFlameCounter, ') + ..write('maxFlameCounterFrom: $maxFlameCounterFrom, ') + ..write('lastMessageExchange: $lastMessageExchange') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hashAll([ + groupId, + isGroupAdmin, + isDirectChat, + pinned, + archived, + joinedGroup, + leftGroup, + deletedContent, + stateVersionId, + $driftBlobEquality.hash(stateEncryptionKey), + $driftBlobEquality.hash(myGroupPrivateKey), + groupName, + draftMessage, + totalMediaCounter, + alsoBestFriend, + deleteMessagesAfterMilliseconds, + createdAt, + lastMessageSend, + lastMessageReceived, + lastFlameCounterChange, + lastFlameSync, + flameCounter, + maxFlameCounter, + maxFlameCounterFrom, + lastMessageExchange, + ]); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupsData && + other.groupId == this.groupId && + other.isGroupAdmin == this.isGroupAdmin && + other.isDirectChat == this.isDirectChat && + other.pinned == this.pinned && + other.archived == this.archived && + other.joinedGroup == this.joinedGroup && + other.leftGroup == this.leftGroup && + other.deletedContent == this.deletedContent && + other.stateVersionId == this.stateVersionId && + $driftBlobEquality.equals( + other.stateEncryptionKey, + this.stateEncryptionKey, + ) && + $driftBlobEquality.equals( + other.myGroupPrivateKey, + this.myGroupPrivateKey, + ) && + other.groupName == this.groupName && + other.draftMessage == this.draftMessage && + other.totalMediaCounter == this.totalMediaCounter && + other.alsoBestFriend == this.alsoBestFriend && + other.deleteMessagesAfterMilliseconds == + this.deleteMessagesAfterMilliseconds && + other.createdAt == this.createdAt && + other.lastMessageSend == this.lastMessageSend && + other.lastMessageReceived == this.lastMessageReceived && + other.lastFlameCounterChange == this.lastFlameCounterChange && + other.lastFlameSync == this.lastFlameSync && + other.flameCounter == this.flameCounter && + other.maxFlameCounter == this.maxFlameCounter && + other.maxFlameCounterFrom == this.maxFlameCounterFrom && + other.lastMessageExchange == this.lastMessageExchange); +} + +class GroupsCompanion extends UpdateCompanion { + final Value groupId; + final Value isGroupAdmin; + final Value isDirectChat; + final Value pinned; + final Value archived; + final Value joinedGroup; + final Value leftGroup; + final Value deletedContent; + final Value stateVersionId; + final Value stateEncryptionKey; + final Value myGroupPrivateKey; + final Value groupName; + final Value draftMessage; + final Value totalMediaCounter; + final Value alsoBestFriend; + final Value deleteMessagesAfterMilliseconds; + final Value createdAt; + final Value lastMessageSend; + final Value lastMessageReceived; + final Value lastFlameCounterChange; + final Value lastFlameSync; + final Value flameCounter; + final Value maxFlameCounter; + final Value maxFlameCounterFrom; + final Value lastMessageExchange; + final Value rowid; + const GroupsCompanion({ + this.groupId = const Value.absent(), + this.isGroupAdmin = const Value.absent(), + this.isDirectChat = const Value.absent(), + this.pinned = const Value.absent(), + this.archived = const Value.absent(), + this.joinedGroup = const Value.absent(), + this.leftGroup = const Value.absent(), + this.deletedContent = const Value.absent(), + this.stateVersionId = const Value.absent(), + this.stateEncryptionKey = const Value.absent(), + this.myGroupPrivateKey = const Value.absent(), + this.groupName = const Value.absent(), + this.draftMessage = const Value.absent(), + this.totalMediaCounter = const Value.absent(), + this.alsoBestFriend = const Value.absent(), + this.deleteMessagesAfterMilliseconds = const Value.absent(), + this.createdAt = const Value.absent(), + this.lastMessageSend = const Value.absent(), + this.lastMessageReceived = const Value.absent(), + this.lastFlameCounterChange = const Value.absent(), + this.lastFlameSync = const Value.absent(), + this.flameCounter = const Value.absent(), + this.maxFlameCounter = const Value.absent(), + this.maxFlameCounterFrom = const Value.absent(), + this.lastMessageExchange = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupsCompanion.insert({ + required String groupId, + this.isGroupAdmin = const Value.absent(), + this.isDirectChat = const Value.absent(), + this.pinned = const Value.absent(), + this.archived = const Value.absent(), + this.joinedGroup = const Value.absent(), + this.leftGroup = const Value.absent(), + this.deletedContent = const Value.absent(), + this.stateVersionId = const Value.absent(), + this.stateEncryptionKey = const Value.absent(), + this.myGroupPrivateKey = const Value.absent(), + required String groupName, + this.draftMessage = const Value.absent(), + this.totalMediaCounter = const Value.absent(), + this.alsoBestFriend = const Value.absent(), + this.deleteMessagesAfterMilliseconds = const Value.absent(), + this.createdAt = const Value.absent(), + this.lastMessageSend = const Value.absent(), + this.lastMessageReceived = const Value.absent(), + this.lastFlameCounterChange = const Value.absent(), + this.lastFlameSync = const Value.absent(), + this.flameCounter = const Value.absent(), + this.maxFlameCounter = const Value.absent(), + this.maxFlameCounterFrom = const Value.absent(), + this.lastMessageExchange = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + groupName = Value(groupName); + static Insertable custom({ + Expression? groupId, + Expression? isGroupAdmin, + Expression? isDirectChat, + Expression? pinned, + Expression? archived, + Expression? joinedGroup, + Expression? leftGroup, + Expression? deletedContent, + Expression? stateVersionId, + Expression? stateEncryptionKey, + Expression? myGroupPrivateKey, + Expression? groupName, + Expression? draftMessage, + Expression? totalMediaCounter, + Expression? alsoBestFriend, + Expression? deleteMessagesAfterMilliseconds, + Expression? createdAt, + Expression? lastMessageSend, + Expression? lastMessageReceived, + Expression? lastFlameCounterChange, + Expression? lastFlameSync, + Expression? flameCounter, + Expression? maxFlameCounter, + Expression? maxFlameCounterFrom, + Expression? lastMessageExchange, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (isGroupAdmin != null) 'is_group_admin': isGroupAdmin, + if (isDirectChat != null) 'is_direct_chat': isDirectChat, + if (pinned != null) 'pinned': pinned, + if (archived != null) 'archived': archived, + if (joinedGroup != null) 'joined_group': joinedGroup, + if (leftGroup != null) 'left_group': leftGroup, + if (deletedContent != null) 'deleted_content': deletedContent, + if (stateVersionId != null) 'state_version_id': stateVersionId, + if (stateEncryptionKey != null) + 'state_encryption_key': stateEncryptionKey, + if (myGroupPrivateKey != null) 'my_group_private_key': myGroupPrivateKey, + if (groupName != null) 'group_name': groupName, + if (draftMessage != null) 'draft_message': draftMessage, + if (totalMediaCounter != null) 'total_media_counter': totalMediaCounter, + if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend, + if (deleteMessagesAfterMilliseconds != null) + 'delete_messages_after_milliseconds': deleteMessagesAfterMilliseconds, + if (createdAt != null) 'created_at': createdAt, + 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 (flameCounter != null) 'flame_counter': flameCounter, + if (maxFlameCounter != null) 'max_flame_counter': maxFlameCounter, + if (maxFlameCounterFrom != null) + 'max_flame_counter_from': maxFlameCounterFrom, + if (lastMessageExchange != null) + 'last_message_exchange': lastMessageExchange, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupsCompanion copyWith({ + Value? groupId, + Value? isGroupAdmin, + Value? isDirectChat, + Value? pinned, + Value? archived, + Value? joinedGroup, + Value? leftGroup, + Value? deletedContent, + Value? stateVersionId, + Value? stateEncryptionKey, + Value? myGroupPrivateKey, + Value? groupName, + Value? draftMessage, + Value? totalMediaCounter, + Value? alsoBestFriend, + Value? deleteMessagesAfterMilliseconds, + Value? createdAt, + Value? lastMessageSend, + Value? lastMessageReceived, + Value? lastFlameCounterChange, + Value? lastFlameSync, + Value? flameCounter, + Value? maxFlameCounter, + Value? maxFlameCounterFrom, + Value? lastMessageExchange, + Value? rowid, + }) { + return GroupsCompanion( + groupId: groupId ?? this.groupId, + isGroupAdmin: isGroupAdmin ?? this.isGroupAdmin, + isDirectChat: isDirectChat ?? this.isDirectChat, + pinned: pinned ?? this.pinned, + archived: archived ?? this.archived, + joinedGroup: joinedGroup ?? this.joinedGroup, + leftGroup: leftGroup ?? this.leftGroup, + deletedContent: deletedContent ?? this.deletedContent, + stateVersionId: stateVersionId ?? this.stateVersionId, + stateEncryptionKey: stateEncryptionKey ?? this.stateEncryptionKey, + myGroupPrivateKey: myGroupPrivateKey ?? this.myGroupPrivateKey, + groupName: groupName ?? this.groupName, + draftMessage: draftMessage ?? this.draftMessage, + totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter, + alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + deleteMessagesAfterMilliseconds ?? + this.deleteMessagesAfterMilliseconds, + createdAt: createdAt ?? this.createdAt, + lastMessageSend: lastMessageSend ?? this.lastMessageSend, + lastMessageReceived: lastMessageReceived ?? this.lastMessageReceived, + lastFlameCounterChange: + lastFlameCounterChange ?? this.lastFlameCounterChange, + lastFlameSync: lastFlameSync ?? this.lastFlameSync, + flameCounter: flameCounter ?? this.flameCounter, + maxFlameCounter: maxFlameCounter ?? this.maxFlameCounter, + maxFlameCounterFrom: maxFlameCounterFrom ?? this.maxFlameCounterFrom, + lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (isGroupAdmin.present) { + map['is_group_admin'] = Variable(isGroupAdmin.value); + } + if (isDirectChat.present) { + map['is_direct_chat'] = Variable(isDirectChat.value); + } + if (pinned.present) { + map['pinned'] = Variable(pinned.value); + } + if (archived.present) { + map['archived'] = Variable(archived.value); + } + if (joinedGroup.present) { + map['joined_group'] = Variable(joinedGroup.value); + } + if (leftGroup.present) { + map['left_group'] = Variable(leftGroup.value); + } + if (deletedContent.present) { + map['deleted_content'] = Variable(deletedContent.value); + } + if (stateVersionId.present) { + map['state_version_id'] = Variable(stateVersionId.value); + } + if (stateEncryptionKey.present) { + map['state_encryption_key'] = Variable( + stateEncryptionKey.value, + ); + } + if (myGroupPrivateKey.present) { + map['my_group_private_key'] = Variable( + myGroupPrivateKey.value, + ); + } + if (groupName.present) { + map['group_name'] = Variable(groupName.value); + } + if (draftMessage.present) { + map['draft_message'] = Variable(draftMessage.value); + } + if (totalMediaCounter.present) { + map['total_media_counter'] = Variable(totalMediaCounter.value); + } + if (alsoBestFriend.present) { + map['also_best_friend'] = Variable(alsoBestFriend.value); + } + if (deleteMessagesAfterMilliseconds.present) { + map['delete_messages_after_milliseconds'] = Variable( + deleteMessagesAfterMilliseconds.value, + ); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.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 (flameCounter.present) { + map['flame_counter'] = Variable(flameCounter.value); + } + if (maxFlameCounter.present) { + map['max_flame_counter'] = Variable(maxFlameCounter.value); + } + if (maxFlameCounterFrom.present) { + map['max_flame_counter_from'] = Variable(maxFlameCounterFrom.value); + } + if (lastMessageExchange.present) { + map['last_message_exchange'] = Variable(lastMessageExchange.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GroupsCompanion(') + ..write('groupId: $groupId, ') + ..write('isGroupAdmin: $isGroupAdmin, ') + ..write('isDirectChat: $isDirectChat, ') + ..write('pinned: $pinned, ') + ..write('archived: $archived, ') + ..write('joinedGroup: $joinedGroup, ') + ..write('leftGroup: $leftGroup, ') + ..write('deletedContent: $deletedContent, ') + ..write('stateVersionId: $stateVersionId, ') + ..write('stateEncryptionKey: $stateEncryptionKey, ') + ..write('myGroupPrivateKey: $myGroupPrivateKey, ') + ..write('groupName: $groupName, ') + ..write('draftMessage: $draftMessage, ') + ..write('totalMediaCounter: $totalMediaCounter, ') + ..write('alsoBestFriend: $alsoBestFriend, ') + ..write( + 'deleteMessagesAfterMilliseconds: $deleteMessagesAfterMilliseconds, ', + ) + ..write('createdAt: $createdAt, ') + ..write('lastMessageSend: $lastMessageSend, ') + ..write('lastMessageReceived: $lastMessageReceived, ') + ..write('lastFlameCounterChange: $lastFlameCounterChange, ') + ..write('lastFlameSync: $lastFlameSync, ') + ..write('flameCounter: $flameCounter, ') + ..write('maxFlameCounter: $maxFlameCounter, ') + ..write('maxFlameCounterFrom: $maxFlameCounterFrom, ') + ..write('lastMessageExchange: $lastMessageExchange, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class MediaFiles extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MediaFiles(this.attachedDatabase, [this._alias]); + late final GeneratedColumn mediaId = GeneratedColumn( + 'media_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn uploadState = GeneratedColumn( + 'upload_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn downloadState = GeneratedColumn( + 'download_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn requiresAuthentication = GeneratedColumn( + 'requires_authentication', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (requires_authentication IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stored = GeneratedColumn( + 'stored', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK ("stored" IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn isDraftMedia = GeneratedColumn( + 'is_draft_media', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_draft_media IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn preProgressingProcess = GeneratedColumn( + 'pre_progressing_process', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn reuploadRequestedBy = + GeneratedColumn( + 'reupload_requested_by', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn displayLimitInMilliseconds = + GeneratedColumn( + 'display_limit_in_milliseconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn removeAudio = GeneratedColumn( + 'remove_audio', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL CHECK (remove_audio IN (0, 1))', + ); + late final GeneratedColumn downloadToken = + GeneratedColumn( + 'download_token', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionKey = + GeneratedColumn( + 'encryption_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionMac = + GeneratedColumn( + 'encryption_mac', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionNonce = + GeneratedColumn( + 'encryption_nonce', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn storedFileHash = + GeneratedColumn( + 'stored_file_hash', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + mediaId, + type, + uploadState, + downloadState, + requiresAuthentication, + stored, + isDraftMedia, + preProgressingProcess, + reuploadRequestedBy, + displayLimitInMilliseconds, + removeAudio, + downloadToken, + encryptionKey, + encryptionMac, + encryptionNonce, + storedFileHash, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'media_files'; + @override + Set get $primaryKey => {mediaId}; + @override + MediaFilesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MediaFilesData( + mediaId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}media_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + uploadState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}upload_state'], + ), + downloadState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}download_state'], + ), + requiresAuthentication: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}requires_authentication'], + )!, + stored: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}stored'], + )!, + isDraftMedia: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_draft_media'], + )!, + preProgressingProcess: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}pre_progressing_process'], + ), + reuploadRequestedBy: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}reupload_requested_by'], + ), + displayLimitInMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}display_limit_in_milliseconds'], + ), + removeAudio: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}remove_audio'], + ), + downloadToken: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}download_token'], + ), + encryptionKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_key'], + ), + encryptionMac: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_mac'], + ), + encryptionNonce: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_nonce'], + ), + storedFileHash: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}stored_file_hash'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + MediaFiles createAlias(String alias) { + return MediaFiles(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(media_id)']; + @override + bool get dontWriteConstraints => true; +} + +class MediaFilesData extends DataClass implements Insertable { + final String mediaId; + final String type; + final String? uploadState; + final String? downloadState; + final int requiresAuthentication; + final int stored; + final int isDraftMedia; + final int? preProgressingProcess; + final String? reuploadRequestedBy; + final int? displayLimitInMilliseconds; + final int? removeAudio; + final i2.Uint8List? downloadToken; + final i2.Uint8List? encryptionKey; + final i2.Uint8List? encryptionMac; + final i2.Uint8List? encryptionNonce; + final i2.Uint8List? storedFileHash; + final int createdAt; + const MediaFilesData({ + required this.mediaId, + required this.type, + this.uploadState, + this.downloadState, + required this.requiresAuthentication, + required this.stored, + required this.isDraftMedia, + this.preProgressingProcess, + this.reuploadRequestedBy, + this.displayLimitInMilliseconds, + this.removeAudio, + this.downloadToken, + this.encryptionKey, + this.encryptionMac, + this.encryptionNonce, + this.storedFileHash, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['media_id'] = Variable(mediaId); + map['type'] = Variable(type); + if (!nullToAbsent || uploadState != null) { + map['upload_state'] = Variable(uploadState); + } + if (!nullToAbsent || downloadState != null) { + map['download_state'] = Variable(downloadState); + } + map['requires_authentication'] = Variable(requiresAuthentication); + map['stored'] = Variable(stored); + map['is_draft_media'] = Variable(isDraftMedia); + if (!nullToAbsent || preProgressingProcess != null) { + map['pre_progressing_process'] = Variable(preProgressingProcess); + } + if (!nullToAbsent || reuploadRequestedBy != null) { + map['reupload_requested_by'] = Variable(reuploadRequestedBy); + } + if (!nullToAbsent || displayLimitInMilliseconds != null) { + map['display_limit_in_milliseconds'] = Variable( + displayLimitInMilliseconds, + ); + } + if (!nullToAbsent || removeAudio != null) { + map['remove_audio'] = Variable(removeAudio); + } + if (!nullToAbsent || downloadToken != null) { + map['download_token'] = Variable(downloadToken); + } + if (!nullToAbsent || encryptionKey != null) { + map['encryption_key'] = Variable(encryptionKey); + } + if (!nullToAbsent || encryptionMac != null) { + map['encryption_mac'] = Variable(encryptionMac); + } + if (!nullToAbsent || encryptionNonce != null) { + map['encryption_nonce'] = Variable(encryptionNonce); + } + if (!nullToAbsent || storedFileHash != null) { + map['stored_file_hash'] = Variable(storedFileHash); + } + map['created_at'] = Variable(createdAt); + return map; + } + + MediaFilesCompanion toCompanion(bool nullToAbsent) { + return MediaFilesCompanion( + mediaId: Value(mediaId), + type: Value(type), + uploadState: uploadState == null && nullToAbsent + ? const Value.absent() + : Value(uploadState), + downloadState: downloadState == null && nullToAbsent + ? const Value.absent() + : Value(downloadState), + requiresAuthentication: Value(requiresAuthentication), + stored: Value(stored), + isDraftMedia: Value(isDraftMedia), + preProgressingProcess: preProgressingProcess == null && nullToAbsent + ? const Value.absent() + : Value(preProgressingProcess), + reuploadRequestedBy: reuploadRequestedBy == null && nullToAbsent + ? const Value.absent() + : Value(reuploadRequestedBy), + displayLimitInMilliseconds: + displayLimitInMilliseconds == null && nullToAbsent + ? const Value.absent() + : Value(displayLimitInMilliseconds), + removeAudio: removeAudio == null && nullToAbsent + ? const Value.absent() + : Value(removeAudio), + downloadToken: downloadToken == null && nullToAbsent + ? const Value.absent() + : Value(downloadToken), + encryptionKey: encryptionKey == null && nullToAbsent + ? const Value.absent() + : Value(encryptionKey), + encryptionMac: encryptionMac == null && nullToAbsent + ? const Value.absent() + : Value(encryptionMac), + encryptionNonce: encryptionNonce == null && nullToAbsent + ? const Value.absent() + : Value(encryptionNonce), + storedFileHash: storedFileHash == null && nullToAbsent + ? const Value.absent() + : Value(storedFileHash), + createdAt: Value(createdAt), + ); + } + + factory MediaFilesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MediaFilesData( + mediaId: serializer.fromJson(json['mediaId']), + type: serializer.fromJson(json['type']), + uploadState: serializer.fromJson(json['uploadState']), + downloadState: serializer.fromJson(json['downloadState']), + requiresAuthentication: serializer.fromJson( + json['requiresAuthentication'], + ), + stored: serializer.fromJson(json['stored']), + isDraftMedia: serializer.fromJson(json['isDraftMedia']), + preProgressingProcess: serializer.fromJson( + json['preProgressingProcess'], + ), + reuploadRequestedBy: serializer.fromJson( + json['reuploadRequestedBy'], + ), + displayLimitInMilliseconds: serializer.fromJson( + json['displayLimitInMilliseconds'], + ), + removeAudio: serializer.fromJson(json['removeAudio']), + downloadToken: serializer.fromJson(json['downloadToken']), + encryptionKey: serializer.fromJson(json['encryptionKey']), + encryptionMac: serializer.fromJson(json['encryptionMac']), + encryptionNonce: serializer.fromJson( + json['encryptionNonce'], + ), + storedFileHash: serializer.fromJson( + json['storedFileHash'], + ), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'mediaId': serializer.toJson(mediaId), + 'type': serializer.toJson(type), + 'uploadState': serializer.toJson(uploadState), + 'downloadState': serializer.toJson(downloadState), + 'requiresAuthentication': serializer.toJson(requiresAuthentication), + 'stored': serializer.toJson(stored), + 'isDraftMedia': serializer.toJson(isDraftMedia), + 'preProgressingProcess': serializer.toJson(preProgressingProcess), + 'reuploadRequestedBy': serializer.toJson(reuploadRequestedBy), + 'displayLimitInMilliseconds': serializer.toJson( + displayLimitInMilliseconds, + ), + 'removeAudio': serializer.toJson(removeAudio), + 'downloadToken': serializer.toJson(downloadToken), + 'encryptionKey': serializer.toJson(encryptionKey), + 'encryptionMac': serializer.toJson(encryptionMac), + 'encryptionNonce': serializer.toJson(encryptionNonce), + 'storedFileHash': serializer.toJson(storedFileHash), + 'createdAt': serializer.toJson(createdAt), + }; + } + + MediaFilesData copyWith({ + String? mediaId, + String? type, + Value uploadState = const Value.absent(), + Value downloadState = const Value.absent(), + int? requiresAuthentication, + int? stored, + int? isDraftMedia, + Value preProgressingProcess = const Value.absent(), + Value reuploadRequestedBy = const Value.absent(), + Value displayLimitInMilliseconds = const Value.absent(), + Value removeAudio = const Value.absent(), + Value downloadToken = const Value.absent(), + Value encryptionKey = const Value.absent(), + Value encryptionMac = const Value.absent(), + Value encryptionNonce = const Value.absent(), + Value storedFileHash = const Value.absent(), + int? createdAt, + }) => MediaFilesData( + mediaId: mediaId ?? this.mediaId, + type: type ?? this.type, + uploadState: uploadState.present ? uploadState.value : this.uploadState, + downloadState: downloadState.present + ? downloadState.value + : this.downloadState, + requiresAuthentication: + requiresAuthentication ?? this.requiresAuthentication, + stored: stored ?? this.stored, + isDraftMedia: isDraftMedia ?? this.isDraftMedia, + preProgressingProcess: preProgressingProcess.present + ? preProgressingProcess.value + : this.preProgressingProcess, + reuploadRequestedBy: reuploadRequestedBy.present + ? reuploadRequestedBy.value + : this.reuploadRequestedBy, + displayLimitInMilliseconds: displayLimitInMilliseconds.present + ? displayLimitInMilliseconds.value + : this.displayLimitInMilliseconds, + removeAudio: removeAudio.present ? removeAudio.value : this.removeAudio, + downloadToken: downloadToken.present + ? downloadToken.value + : this.downloadToken, + encryptionKey: encryptionKey.present + ? encryptionKey.value + : this.encryptionKey, + encryptionMac: encryptionMac.present + ? encryptionMac.value + : this.encryptionMac, + encryptionNonce: encryptionNonce.present + ? encryptionNonce.value + : this.encryptionNonce, + storedFileHash: storedFileHash.present + ? storedFileHash.value + : this.storedFileHash, + createdAt: createdAt ?? this.createdAt, + ); + MediaFilesData copyWithCompanion(MediaFilesCompanion data) { + return MediaFilesData( + mediaId: data.mediaId.present ? data.mediaId.value : this.mediaId, + type: data.type.present ? data.type.value : this.type, + uploadState: data.uploadState.present + ? data.uploadState.value + : this.uploadState, + downloadState: data.downloadState.present + ? data.downloadState.value + : this.downloadState, + requiresAuthentication: data.requiresAuthentication.present + ? data.requiresAuthentication.value + : this.requiresAuthentication, + stored: data.stored.present ? data.stored.value : this.stored, + isDraftMedia: data.isDraftMedia.present + ? data.isDraftMedia.value + : this.isDraftMedia, + preProgressingProcess: data.preProgressingProcess.present + ? data.preProgressingProcess.value + : this.preProgressingProcess, + reuploadRequestedBy: data.reuploadRequestedBy.present + ? data.reuploadRequestedBy.value + : this.reuploadRequestedBy, + displayLimitInMilliseconds: data.displayLimitInMilliseconds.present + ? data.displayLimitInMilliseconds.value + : this.displayLimitInMilliseconds, + removeAudio: data.removeAudio.present + ? data.removeAudio.value + : this.removeAudio, + downloadToken: data.downloadToken.present + ? data.downloadToken.value + : this.downloadToken, + encryptionKey: data.encryptionKey.present + ? data.encryptionKey.value + : this.encryptionKey, + encryptionMac: data.encryptionMac.present + ? data.encryptionMac.value + : this.encryptionMac, + encryptionNonce: data.encryptionNonce.present + ? data.encryptionNonce.value + : this.encryptionNonce, + storedFileHash: data.storedFileHash.present + ? data.storedFileHash.value + : this.storedFileHash, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('MediaFilesData(') + ..write('mediaId: $mediaId, ') + ..write('type: $type, ') + ..write('uploadState: $uploadState, ') + ..write('downloadState: $downloadState, ') + ..write('requiresAuthentication: $requiresAuthentication, ') + ..write('stored: $stored, ') + ..write('isDraftMedia: $isDraftMedia, ') + ..write('preProgressingProcess: $preProgressingProcess, ') + ..write('reuploadRequestedBy: $reuploadRequestedBy, ') + ..write('displayLimitInMilliseconds: $displayLimitInMilliseconds, ') + ..write('removeAudio: $removeAudio, ') + ..write('downloadToken: $downloadToken, ') + ..write('encryptionKey: $encryptionKey, ') + ..write('encryptionMac: $encryptionMac, ') + ..write('encryptionNonce: $encryptionNonce, ') + ..write('storedFileHash: $storedFileHash, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + mediaId, + type, + uploadState, + downloadState, + requiresAuthentication, + stored, + isDraftMedia, + preProgressingProcess, + reuploadRequestedBy, + displayLimitInMilliseconds, + removeAudio, + $driftBlobEquality.hash(downloadToken), + $driftBlobEquality.hash(encryptionKey), + $driftBlobEquality.hash(encryptionMac), + $driftBlobEquality.hash(encryptionNonce), + $driftBlobEquality.hash(storedFileHash), + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MediaFilesData && + other.mediaId == this.mediaId && + other.type == this.type && + other.uploadState == this.uploadState && + other.downloadState == this.downloadState && + other.requiresAuthentication == this.requiresAuthentication && + other.stored == this.stored && + other.isDraftMedia == this.isDraftMedia && + other.preProgressingProcess == this.preProgressingProcess && + other.reuploadRequestedBy == this.reuploadRequestedBy && + other.displayLimitInMilliseconds == this.displayLimitInMilliseconds && + other.removeAudio == this.removeAudio && + $driftBlobEquality.equals(other.downloadToken, this.downloadToken) && + $driftBlobEquality.equals(other.encryptionKey, this.encryptionKey) && + $driftBlobEquality.equals(other.encryptionMac, this.encryptionMac) && + $driftBlobEquality.equals( + other.encryptionNonce, + this.encryptionNonce, + ) && + $driftBlobEquality.equals( + other.storedFileHash, + this.storedFileHash, + ) && + other.createdAt == this.createdAt); +} + +class MediaFilesCompanion extends UpdateCompanion { + final Value mediaId; + final Value type; + final Value uploadState; + final Value downloadState; + final Value requiresAuthentication; + final Value stored; + final Value isDraftMedia; + final Value preProgressingProcess; + final Value reuploadRequestedBy; + final Value displayLimitInMilliseconds; + final Value removeAudio; + final Value downloadToken; + final Value encryptionKey; + final Value encryptionMac; + final Value encryptionNonce; + final Value storedFileHash; + final Value createdAt; + final Value rowid; + const MediaFilesCompanion({ + this.mediaId = const Value.absent(), + this.type = const Value.absent(), + this.uploadState = const Value.absent(), + this.downloadState = const Value.absent(), + this.requiresAuthentication = const Value.absent(), + this.stored = const Value.absent(), + this.isDraftMedia = const Value.absent(), + this.preProgressingProcess = const Value.absent(), + this.reuploadRequestedBy = const Value.absent(), + this.displayLimitInMilliseconds = const Value.absent(), + this.removeAudio = const Value.absent(), + this.downloadToken = const Value.absent(), + this.encryptionKey = const Value.absent(), + this.encryptionMac = const Value.absent(), + this.encryptionNonce = const Value.absent(), + this.storedFileHash = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + MediaFilesCompanion.insert({ + required String mediaId, + required String type, + this.uploadState = const Value.absent(), + this.downloadState = const Value.absent(), + this.requiresAuthentication = const Value.absent(), + this.stored = const Value.absent(), + this.isDraftMedia = const Value.absent(), + this.preProgressingProcess = const Value.absent(), + this.reuploadRequestedBy = const Value.absent(), + this.displayLimitInMilliseconds = const Value.absent(), + this.removeAudio = const Value.absent(), + this.downloadToken = const Value.absent(), + this.encryptionKey = const Value.absent(), + this.encryptionMac = const Value.absent(), + this.encryptionNonce = const Value.absent(), + this.storedFileHash = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : mediaId = Value(mediaId), + type = Value(type); + static Insertable custom({ + Expression? mediaId, + Expression? type, + Expression? uploadState, + Expression? downloadState, + Expression? requiresAuthentication, + Expression? stored, + Expression? isDraftMedia, + Expression? preProgressingProcess, + Expression? reuploadRequestedBy, + Expression? displayLimitInMilliseconds, + Expression? removeAudio, + Expression? downloadToken, + Expression? encryptionKey, + Expression? encryptionMac, + Expression? encryptionNonce, + Expression? storedFileHash, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (mediaId != null) 'media_id': mediaId, + if (type != null) 'type': type, + if (uploadState != null) 'upload_state': uploadState, + if (downloadState != null) 'download_state': downloadState, + if (requiresAuthentication != null) + 'requires_authentication': requiresAuthentication, + if (stored != null) 'stored': stored, + if (isDraftMedia != null) 'is_draft_media': isDraftMedia, + if (preProgressingProcess != null) + 'pre_progressing_process': preProgressingProcess, + if (reuploadRequestedBy != null) + 'reupload_requested_by': reuploadRequestedBy, + if (displayLimitInMilliseconds != null) + 'display_limit_in_milliseconds': displayLimitInMilliseconds, + if (removeAudio != null) 'remove_audio': removeAudio, + if (downloadToken != null) 'download_token': downloadToken, + if (encryptionKey != null) 'encryption_key': encryptionKey, + if (encryptionMac != null) 'encryption_mac': encryptionMac, + if (encryptionNonce != null) 'encryption_nonce': encryptionNonce, + if (storedFileHash != null) 'stored_file_hash': storedFileHash, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + MediaFilesCompanion copyWith({ + Value? mediaId, + Value? type, + Value? uploadState, + Value? downloadState, + Value? requiresAuthentication, + Value? stored, + Value? isDraftMedia, + Value? preProgressingProcess, + Value? reuploadRequestedBy, + Value? displayLimitInMilliseconds, + Value? removeAudio, + Value? downloadToken, + Value? encryptionKey, + Value? encryptionMac, + Value? encryptionNonce, + Value? storedFileHash, + Value? createdAt, + Value? rowid, + }) { + return MediaFilesCompanion( + mediaId: mediaId ?? this.mediaId, + type: type ?? this.type, + uploadState: uploadState ?? this.uploadState, + downloadState: downloadState ?? this.downloadState, + requiresAuthentication: + requiresAuthentication ?? this.requiresAuthentication, + stored: stored ?? this.stored, + isDraftMedia: isDraftMedia ?? this.isDraftMedia, + preProgressingProcess: + preProgressingProcess ?? this.preProgressingProcess, + reuploadRequestedBy: reuploadRequestedBy ?? this.reuploadRequestedBy, + displayLimitInMilliseconds: + displayLimitInMilliseconds ?? this.displayLimitInMilliseconds, + removeAudio: removeAudio ?? this.removeAudio, + downloadToken: downloadToken ?? this.downloadToken, + encryptionKey: encryptionKey ?? this.encryptionKey, + encryptionMac: encryptionMac ?? this.encryptionMac, + encryptionNonce: encryptionNonce ?? this.encryptionNonce, + storedFileHash: storedFileHash ?? this.storedFileHash, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (mediaId.present) { + map['media_id'] = Variable(mediaId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (uploadState.present) { + map['upload_state'] = Variable(uploadState.value); + } + if (downloadState.present) { + map['download_state'] = Variable(downloadState.value); + } + if (requiresAuthentication.present) { + map['requires_authentication'] = Variable( + requiresAuthentication.value, + ); + } + if (stored.present) { + map['stored'] = Variable(stored.value); + } + if (isDraftMedia.present) { + map['is_draft_media'] = Variable(isDraftMedia.value); + } + if (preProgressingProcess.present) { + map['pre_progressing_process'] = Variable( + preProgressingProcess.value, + ); + } + if (reuploadRequestedBy.present) { + map['reupload_requested_by'] = Variable( + reuploadRequestedBy.value, + ); + } + if (displayLimitInMilliseconds.present) { + map['display_limit_in_milliseconds'] = Variable( + displayLimitInMilliseconds.value, + ); + } + if (removeAudio.present) { + map['remove_audio'] = Variable(removeAudio.value); + } + if (downloadToken.present) { + map['download_token'] = Variable(downloadToken.value); + } + if (encryptionKey.present) { + map['encryption_key'] = Variable(encryptionKey.value); + } + if (encryptionMac.present) { + map['encryption_mac'] = Variable(encryptionMac.value); + } + if (encryptionNonce.present) { + map['encryption_nonce'] = Variable(encryptionNonce.value); + } + if (storedFileHash.present) { + map['stored_file_hash'] = Variable(storedFileHash.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('MediaFilesCompanion(') + ..write('mediaId: $mediaId, ') + ..write('type: $type, ') + ..write('uploadState: $uploadState, ') + ..write('downloadState: $downloadState, ') + ..write('requiresAuthentication: $requiresAuthentication, ') + ..write('stored: $stored, ') + ..write('isDraftMedia: $isDraftMedia, ') + ..write('preProgressingProcess: $preProgressingProcess, ') + ..write('reuploadRequestedBy: $reuploadRequestedBy, ') + ..write('displayLimitInMilliseconds: $displayLimitInMilliseconds, ') + ..write('removeAudio: $removeAudio, ') + ..write('downloadToken: $downloadToken, ') + ..write('encryptionKey: $encryptionKey, ') + ..write('encryptionMac: $encryptionMac, ') + ..write('encryptionNonce: $encryptionNonce, ') + ..write('storedFileHash: $storedFileHash, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class Messages extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Messages(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderId = GeneratedColumn( + 'sender_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn content = GeneratedColumn( + 'content', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mediaId = GeneratedColumn( + 'media_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: + 'NULL REFERENCES media_files(media_id)ON DELETE SET NULL', + ); + late final GeneratedColumn additionalMessageData = + GeneratedColumn( + 'additional_message_data', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mediaStored = GeneratedColumn( + 'media_stored', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (media_stored IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn mediaReopened = GeneratedColumn( + 'media_reopened', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (media_reopened IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn downloadToken = + GeneratedColumn( + 'download_token', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quotesMessageId = GeneratedColumn( + 'quotes_message_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn isDeletedFromSender = GeneratedColumn( + 'is_deleted_from_sender', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (is_deleted_from_sender IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn openedAt = GeneratedColumn( + 'opened_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn openedByAll = GeneratedColumn( + 'opened_by_all', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn modifiedAt = GeneratedColumn( + 'modified_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByUser = GeneratedColumn( + 'ack_by_user', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByServer = GeneratedColumn( + 'ack_by_server', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + groupId, + messageId, + senderId, + type, + content, + mediaId, + additionalMessageData, + mediaStored, + mediaReopened, + downloadToken, + quotesMessageId, + isDeletedFromSender, + openedAt, + openedByAll, + createdAt, + modifiedAt, + ackByUser, + ackByServer, + ]; + @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( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + senderId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_id'], + ), + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + content: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}content'], + ), + mediaId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}media_id'], + ), + additionalMessageData: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}additional_message_data'], + ), + mediaStored: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_stored'], + )!, + mediaReopened: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_reopened'], + )!, + downloadToken: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}download_token'], + ), + quotesMessageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}quotes_message_id'], + ), + isDeletedFromSender: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_deleted_from_sender'], + )!, + openedAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}opened_at'], + ), + openedByAll: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}opened_by_all'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + modifiedAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}modified_at'], + ), + ackByUser: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_user'], + ), + ackByServer: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_server'], + ), + ); + } + + @override + Messages createAlias(String alias) { + return Messages(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(message_id)']; + @override + bool get dontWriteConstraints => true; +} + +class MessagesData extends DataClass implements Insertable { + final String groupId; + final String messageId; + final int? senderId; + final String type; + final String? content; + final String? mediaId; + final i2.Uint8List? additionalMessageData; + final int mediaStored; + final int mediaReopened; + final i2.Uint8List? downloadToken; + final String? quotesMessageId; + final int isDeletedFromSender; + final int? openedAt; + final int? openedByAll; + final int createdAt; + final int? modifiedAt; + final int? ackByUser; + final int? ackByServer; + const MessagesData({ + required this.groupId, + required this.messageId, + this.senderId, + required this.type, + this.content, + this.mediaId, + this.additionalMessageData, + required this.mediaStored, + required this.mediaReopened, + this.downloadToken, + this.quotesMessageId, + required this.isDeletedFromSender, + this.openedAt, + this.openedByAll, + required this.createdAt, + this.modifiedAt, + this.ackByUser, + this.ackByServer, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['message_id'] = Variable(messageId); + if (!nullToAbsent || senderId != null) { + map['sender_id'] = Variable(senderId); + } + map['type'] = Variable(type); + if (!nullToAbsent || content != null) { + map['content'] = Variable(content); + } + if (!nullToAbsent || mediaId != null) { + map['media_id'] = Variable(mediaId); + } + if (!nullToAbsent || additionalMessageData != null) { + map['additional_message_data'] = Variable( + additionalMessageData, + ); + } + map['media_stored'] = Variable(mediaStored); + map['media_reopened'] = Variable(mediaReopened); + if (!nullToAbsent || downloadToken != null) { + map['download_token'] = Variable(downloadToken); + } + if (!nullToAbsent || quotesMessageId != null) { + map['quotes_message_id'] = Variable(quotesMessageId); + } + map['is_deleted_from_sender'] = Variable(isDeletedFromSender); + if (!nullToAbsent || openedAt != null) { + map['opened_at'] = Variable(openedAt); + } + if (!nullToAbsent || openedByAll != null) { + map['opened_by_all'] = Variable(openedByAll); + } + map['created_at'] = Variable(createdAt); + if (!nullToAbsent || modifiedAt != null) { + map['modified_at'] = Variable(modifiedAt); + } + if (!nullToAbsent || ackByUser != null) { + map['ack_by_user'] = Variable(ackByUser); + } + if (!nullToAbsent || ackByServer != null) { + map['ack_by_server'] = Variable(ackByServer); + } + return map; + } + + MessagesCompanion toCompanion(bool nullToAbsent) { + return MessagesCompanion( + groupId: Value(groupId), + messageId: Value(messageId), + senderId: senderId == null && nullToAbsent + ? const Value.absent() + : Value(senderId), + type: Value(type), + content: content == null && nullToAbsent + ? const Value.absent() + : Value(content), + mediaId: mediaId == null && nullToAbsent + ? const Value.absent() + : Value(mediaId), + additionalMessageData: additionalMessageData == null && nullToAbsent + ? const Value.absent() + : Value(additionalMessageData), + mediaStored: Value(mediaStored), + mediaReopened: Value(mediaReopened), + downloadToken: downloadToken == null && nullToAbsent + ? const Value.absent() + : Value(downloadToken), + quotesMessageId: quotesMessageId == null && nullToAbsent + ? const Value.absent() + : Value(quotesMessageId), + isDeletedFromSender: Value(isDeletedFromSender), + openedAt: openedAt == null && nullToAbsent + ? const Value.absent() + : Value(openedAt), + openedByAll: openedByAll == null && nullToAbsent + ? const Value.absent() + : Value(openedByAll), + createdAt: Value(createdAt), + modifiedAt: modifiedAt == null && nullToAbsent + ? const Value.absent() + : Value(modifiedAt), + ackByUser: ackByUser == null && nullToAbsent + ? const Value.absent() + : Value(ackByUser), + ackByServer: ackByServer == null && nullToAbsent + ? const Value.absent() + : Value(ackByServer), + ); + } + + factory MessagesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessagesData( + groupId: serializer.fromJson(json['groupId']), + messageId: serializer.fromJson(json['messageId']), + senderId: serializer.fromJson(json['senderId']), + type: serializer.fromJson(json['type']), + content: serializer.fromJson(json['content']), + mediaId: serializer.fromJson(json['mediaId']), + additionalMessageData: serializer.fromJson( + json['additionalMessageData'], + ), + mediaStored: serializer.fromJson(json['mediaStored']), + mediaReopened: serializer.fromJson(json['mediaReopened']), + downloadToken: serializer.fromJson(json['downloadToken']), + quotesMessageId: serializer.fromJson(json['quotesMessageId']), + isDeletedFromSender: serializer.fromJson( + json['isDeletedFromSender'], + ), + openedAt: serializer.fromJson(json['openedAt']), + openedByAll: serializer.fromJson(json['openedByAll']), + createdAt: serializer.fromJson(json['createdAt']), + modifiedAt: serializer.fromJson(json['modifiedAt']), + ackByUser: serializer.fromJson(json['ackByUser']), + ackByServer: serializer.fromJson(json['ackByServer']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'messageId': serializer.toJson(messageId), + 'senderId': serializer.toJson(senderId), + 'type': serializer.toJson(type), + 'content': serializer.toJson(content), + 'mediaId': serializer.toJson(mediaId), + 'additionalMessageData': serializer.toJson( + additionalMessageData, + ), + 'mediaStored': serializer.toJson(mediaStored), + 'mediaReopened': serializer.toJson(mediaReopened), + 'downloadToken': serializer.toJson(downloadToken), + 'quotesMessageId': serializer.toJson(quotesMessageId), + 'isDeletedFromSender': serializer.toJson(isDeletedFromSender), + 'openedAt': serializer.toJson(openedAt), + 'openedByAll': serializer.toJson(openedByAll), + 'createdAt': serializer.toJson(createdAt), + 'modifiedAt': serializer.toJson(modifiedAt), + 'ackByUser': serializer.toJson(ackByUser), + 'ackByServer': serializer.toJson(ackByServer), + }; + } + + MessagesData copyWith({ + String? groupId, + String? messageId, + Value senderId = const Value.absent(), + String? type, + Value content = const Value.absent(), + Value mediaId = const Value.absent(), + Value additionalMessageData = const Value.absent(), + int? mediaStored, + int? mediaReopened, + Value downloadToken = const Value.absent(), + Value quotesMessageId = const Value.absent(), + int? isDeletedFromSender, + Value openedAt = const Value.absent(), + Value openedByAll = const Value.absent(), + int? createdAt, + Value modifiedAt = const Value.absent(), + Value ackByUser = const Value.absent(), + Value ackByServer = const Value.absent(), + }) => MessagesData( + groupId: groupId ?? this.groupId, + messageId: messageId ?? this.messageId, + senderId: senderId.present ? senderId.value : this.senderId, + type: type ?? this.type, + content: content.present ? content.value : this.content, + mediaId: mediaId.present ? mediaId.value : this.mediaId, + additionalMessageData: additionalMessageData.present + ? additionalMessageData.value + : this.additionalMessageData, + mediaStored: mediaStored ?? this.mediaStored, + mediaReopened: mediaReopened ?? this.mediaReopened, + downloadToken: downloadToken.present + ? downloadToken.value + : this.downloadToken, + quotesMessageId: quotesMessageId.present + ? quotesMessageId.value + : this.quotesMessageId, + isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, + openedAt: openedAt.present ? openedAt.value : this.openedAt, + openedByAll: openedByAll.present ? openedByAll.value : this.openedByAll, + createdAt: createdAt ?? this.createdAt, + modifiedAt: modifiedAt.present ? modifiedAt.value : this.modifiedAt, + ackByUser: ackByUser.present ? ackByUser.value : this.ackByUser, + ackByServer: ackByServer.present ? ackByServer.value : this.ackByServer, + ); + MessagesData copyWithCompanion(MessagesCompanion data) { + return MessagesData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + senderId: data.senderId.present ? data.senderId.value : this.senderId, + type: data.type.present ? data.type.value : this.type, + content: data.content.present ? data.content.value : this.content, + mediaId: data.mediaId.present ? data.mediaId.value : this.mediaId, + additionalMessageData: data.additionalMessageData.present + ? data.additionalMessageData.value + : this.additionalMessageData, + mediaStored: data.mediaStored.present + ? data.mediaStored.value + : this.mediaStored, + mediaReopened: data.mediaReopened.present + ? data.mediaReopened.value + : this.mediaReopened, + downloadToken: data.downloadToken.present + ? data.downloadToken.value + : this.downloadToken, + quotesMessageId: data.quotesMessageId.present + ? data.quotesMessageId.value + : this.quotesMessageId, + isDeletedFromSender: data.isDeletedFromSender.present + ? data.isDeletedFromSender.value + : this.isDeletedFromSender, + openedAt: data.openedAt.present ? data.openedAt.value : this.openedAt, + openedByAll: data.openedByAll.present + ? data.openedByAll.value + : this.openedByAll, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + modifiedAt: data.modifiedAt.present + ? data.modifiedAt.value + : this.modifiedAt, + ackByUser: data.ackByUser.present ? data.ackByUser.value : this.ackByUser, + ackByServer: data.ackByServer.present + ? data.ackByServer.value + : this.ackByServer, + ); + } + + @override + String toString() { + return (StringBuffer('MessagesData(') + ..write('groupId: $groupId, ') + ..write('messageId: $messageId, ') + ..write('senderId: $senderId, ') + ..write('type: $type, ') + ..write('content: $content, ') + ..write('mediaId: $mediaId, ') + ..write('additionalMessageData: $additionalMessageData, ') + ..write('mediaStored: $mediaStored, ') + ..write('mediaReopened: $mediaReopened, ') + ..write('downloadToken: $downloadToken, ') + ..write('quotesMessageId: $quotesMessageId, ') + ..write('isDeletedFromSender: $isDeletedFromSender, ') + ..write('openedAt: $openedAt, ') + ..write('openedByAll: $openedByAll, ') + ..write('createdAt: $createdAt, ') + ..write('modifiedAt: $modifiedAt, ') + ..write('ackByUser: $ackByUser, ') + ..write('ackByServer: $ackByServer') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupId, + messageId, + senderId, + type, + content, + mediaId, + $driftBlobEquality.hash(additionalMessageData), + mediaStored, + mediaReopened, + $driftBlobEquality.hash(downloadToken), + quotesMessageId, + isDeletedFromSender, + openedAt, + openedByAll, + createdAt, + modifiedAt, + ackByUser, + ackByServer, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessagesData && + other.groupId == this.groupId && + other.messageId == this.messageId && + other.senderId == this.senderId && + other.type == this.type && + other.content == this.content && + other.mediaId == this.mediaId && + $driftBlobEquality.equals( + other.additionalMessageData, + this.additionalMessageData, + ) && + other.mediaStored == this.mediaStored && + other.mediaReopened == this.mediaReopened && + $driftBlobEquality.equals(other.downloadToken, this.downloadToken) && + other.quotesMessageId == this.quotesMessageId && + other.isDeletedFromSender == this.isDeletedFromSender && + other.openedAt == this.openedAt && + other.openedByAll == this.openedByAll && + other.createdAt == this.createdAt && + other.modifiedAt == this.modifiedAt && + other.ackByUser == this.ackByUser && + other.ackByServer == this.ackByServer); +} + +class MessagesCompanion extends UpdateCompanion { + final Value groupId; + final Value messageId; + final Value senderId; + final Value type; + final Value content; + final Value mediaId; + final Value additionalMessageData; + final Value mediaStored; + final Value mediaReopened; + final Value downloadToken; + final Value quotesMessageId; + final Value isDeletedFromSender; + final Value openedAt; + final Value openedByAll; + final Value createdAt; + final Value modifiedAt; + final Value ackByUser; + final Value ackByServer; + final Value rowid; + const MessagesCompanion({ + this.groupId = const Value.absent(), + this.messageId = const Value.absent(), + this.senderId = const Value.absent(), + this.type = const Value.absent(), + this.content = const Value.absent(), + this.mediaId = const Value.absent(), + this.additionalMessageData = const Value.absent(), + this.mediaStored = const Value.absent(), + this.mediaReopened = const Value.absent(), + this.downloadToken = const Value.absent(), + this.quotesMessageId = const Value.absent(), + this.isDeletedFromSender = const Value.absent(), + this.openedAt = const Value.absent(), + this.openedByAll = const Value.absent(), + this.createdAt = const Value.absent(), + this.modifiedAt = const Value.absent(), + this.ackByUser = const Value.absent(), + this.ackByServer = const Value.absent(), + this.rowid = const Value.absent(), + }); + MessagesCompanion.insert({ + required String groupId, + required String messageId, + this.senderId = const Value.absent(), + required String type, + this.content = const Value.absent(), + this.mediaId = const Value.absent(), + this.additionalMessageData = const Value.absent(), + this.mediaStored = const Value.absent(), + this.mediaReopened = const Value.absent(), + this.downloadToken = const Value.absent(), + this.quotesMessageId = const Value.absent(), + this.isDeletedFromSender = const Value.absent(), + this.openedAt = const Value.absent(), + this.openedByAll = const Value.absent(), + this.createdAt = const Value.absent(), + this.modifiedAt = const Value.absent(), + this.ackByUser = const Value.absent(), + this.ackByServer = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + messageId = Value(messageId), + type = Value(type); + static Insertable custom({ + Expression? groupId, + Expression? messageId, + Expression? senderId, + Expression? type, + Expression? content, + Expression? mediaId, + Expression? additionalMessageData, + Expression? mediaStored, + Expression? mediaReopened, + Expression? downloadToken, + Expression? quotesMessageId, + Expression? isDeletedFromSender, + Expression? openedAt, + Expression? openedByAll, + Expression? createdAt, + Expression? modifiedAt, + Expression? ackByUser, + Expression? ackByServer, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (messageId != null) 'message_id': messageId, + if (senderId != null) 'sender_id': senderId, + if (type != null) 'type': type, + if (content != null) 'content': content, + if (mediaId != null) 'media_id': mediaId, + if (additionalMessageData != null) + 'additional_message_data': additionalMessageData, + if (mediaStored != null) 'media_stored': mediaStored, + if (mediaReopened != null) 'media_reopened': mediaReopened, + if (downloadToken != null) 'download_token': downloadToken, + if (quotesMessageId != null) 'quotes_message_id': quotesMessageId, + if (isDeletedFromSender != null) + 'is_deleted_from_sender': isDeletedFromSender, + if (openedAt != null) 'opened_at': openedAt, + if (openedByAll != null) 'opened_by_all': openedByAll, + if (createdAt != null) 'created_at': createdAt, + if (modifiedAt != null) 'modified_at': modifiedAt, + if (ackByUser != null) 'ack_by_user': ackByUser, + if (ackByServer != null) 'ack_by_server': ackByServer, + if (rowid != null) 'rowid': rowid, + }); + } + + MessagesCompanion copyWith({ + Value? groupId, + Value? messageId, + Value? senderId, + Value? type, + Value? content, + Value? mediaId, + Value? additionalMessageData, + Value? mediaStored, + Value? mediaReopened, + Value? downloadToken, + Value? quotesMessageId, + Value? isDeletedFromSender, + Value? openedAt, + Value? openedByAll, + Value? createdAt, + Value? modifiedAt, + Value? ackByUser, + Value? ackByServer, + Value? rowid, + }) { + return MessagesCompanion( + groupId: groupId ?? this.groupId, + messageId: messageId ?? this.messageId, + senderId: senderId ?? this.senderId, + type: type ?? this.type, + content: content ?? this.content, + mediaId: mediaId ?? this.mediaId, + additionalMessageData: + additionalMessageData ?? this.additionalMessageData, + mediaStored: mediaStored ?? this.mediaStored, + mediaReopened: mediaReopened ?? this.mediaReopened, + downloadToken: downloadToken ?? this.downloadToken, + quotesMessageId: quotesMessageId ?? this.quotesMessageId, + isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, + openedAt: openedAt ?? this.openedAt, + openedByAll: openedByAll ?? this.openedByAll, + createdAt: createdAt ?? this.createdAt, + modifiedAt: modifiedAt ?? this.modifiedAt, + ackByUser: ackByUser ?? this.ackByUser, + ackByServer: ackByServer ?? this.ackByServer, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (senderId.present) { + map['sender_id'] = Variable(senderId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (mediaId.present) { + map['media_id'] = Variable(mediaId.value); + } + if (additionalMessageData.present) { + map['additional_message_data'] = Variable( + additionalMessageData.value, + ); + } + if (mediaStored.present) { + map['media_stored'] = Variable(mediaStored.value); + } + if (mediaReopened.present) { + map['media_reopened'] = Variable(mediaReopened.value); + } + if (downloadToken.present) { + map['download_token'] = Variable(downloadToken.value); + } + if (quotesMessageId.present) { + map['quotes_message_id'] = Variable(quotesMessageId.value); + } + if (isDeletedFromSender.present) { + map['is_deleted_from_sender'] = Variable(isDeletedFromSender.value); + } + if (openedAt.present) { + map['opened_at'] = Variable(openedAt.value); + } + if (openedByAll.present) { + map['opened_by_all'] = Variable(openedByAll.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (modifiedAt.present) { + map['modified_at'] = Variable(modifiedAt.value); + } + if (ackByUser.present) { + map['ack_by_user'] = Variable(ackByUser.value); + } + if (ackByServer.present) { + map['ack_by_server'] = Variable(ackByServer.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessagesCompanion(') + ..write('groupId: $groupId, ') + ..write('messageId: $messageId, ') + ..write('senderId: $senderId, ') + ..write('type: $type, ') + ..write('content: $content, ') + ..write('mediaId: $mediaId, ') + ..write('additionalMessageData: $additionalMessageData, ') + ..write('mediaStored: $mediaStored, ') + ..write('mediaReopened: $mediaReopened, ') + ..write('downloadToken: $downloadToken, ') + ..write('quotesMessageId: $quotesMessageId, ') + ..write('isDeletedFromSender: $isDeletedFromSender, ') + ..write('openedAt: $openedAt, ') + ..write('openedByAll: $openedByAll, ') + ..write('createdAt: $createdAt, ') + ..write('modifiedAt: $modifiedAt, ') + ..write('ackByUser: $ackByUser, ') + ..write('ackByServer: $ackByServer, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class MessageHistories extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MessageHistories(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn content = GeneratedColumn( + 'content', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + id, + messageId, + contactId, + content, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'message_histories'; + @override + Set get $primaryKey => {id}; + @override + MessageHistoriesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MessageHistoriesData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + content: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}content'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + MessageHistories createAlias(String alias) { + return MessageHistories(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class MessageHistoriesData extends DataClass + implements Insertable { + final int id; + final String messageId; + final int? contactId; + final String? content; + final int createdAt; + const MessageHistoriesData({ + required this.id, + required this.messageId, + this.contactId, + this.content, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['message_id'] = Variable(messageId); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + if (!nullToAbsent || content != null) { + map['content'] = Variable(content); + } + map['created_at'] = Variable(createdAt); + return map; + } + + MessageHistoriesCompanion toCompanion(bool nullToAbsent) { + return MessageHistoriesCompanion( + id: Value(id), + messageId: Value(messageId), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + content: content == null && nullToAbsent + ? const Value.absent() + : Value(content), + createdAt: Value(createdAt), + ); + } + + factory MessageHistoriesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessageHistoriesData( + id: serializer.fromJson(json['id']), + messageId: serializer.fromJson(json['messageId']), + contactId: serializer.fromJson(json['contactId']), + content: serializer.fromJson(json['content']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'messageId': serializer.toJson(messageId), + 'contactId': serializer.toJson(contactId), + 'content': serializer.toJson(content), + 'createdAt': serializer.toJson(createdAt), + }; + } + + MessageHistoriesData copyWith({ + int? id, + String? messageId, + Value contactId = const Value.absent(), + Value content = const Value.absent(), + int? createdAt, + }) => MessageHistoriesData( + id: id ?? this.id, + messageId: messageId ?? this.messageId, + contactId: contactId.present ? contactId.value : this.contactId, + content: content.present ? content.value : this.content, + createdAt: createdAt ?? this.createdAt, + ); + MessageHistoriesData copyWithCompanion(MessageHistoriesCompanion data) { + return MessageHistoriesData( + id: data.id.present ? data.id.value : this.id, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + content: data.content.present ? data.content.value : this.content, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('MessageHistoriesData(') + ..write('id: $id, ') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('content: $content, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, messageId, contactId, content, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessageHistoriesData && + other.id == this.id && + other.messageId == this.messageId && + other.contactId == this.contactId && + other.content == this.content && + other.createdAt == this.createdAt); +} + +class MessageHistoriesCompanion extends UpdateCompanion { + final Value id; + final Value messageId; + final Value contactId; + final Value content; + final Value createdAt; + const MessageHistoriesCompanion({ + this.id = const Value.absent(), + this.messageId = const Value.absent(), + this.contactId = const Value.absent(), + this.content = const Value.absent(), + this.createdAt = const Value.absent(), + }); + MessageHistoriesCompanion.insert({ + this.id = const Value.absent(), + required String messageId, + this.contactId = const Value.absent(), + this.content = const Value.absent(), + this.createdAt = const Value.absent(), + }) : messageId = Value(messageId); + static Insertable custom({ + Expression? id, + Expression? messageId, + Expression? contactId, + Expression? content, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (messageId != null) 'message_id': messageId, + if (contactId != null) 'contact_id': contactId, + if (content != null) 'content': content, + if (createdAt != null) 'created_at': createdAt, + }); + } + + MessageHistoriesCompanion copyWith({ + Value? id, + Value? messageId, + Value? contactId, + Value? content, + Value? createdAt, + }) { + return MessageHistoriesCompanion( + id: id ?? this.id, + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + content: content ?? this.content, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessageHistoriesCompanion(') + ..write('id: $id, ') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('content: $content, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class Reactions extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Reactions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn emoji = GeneratedColumn( + 'emoji', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderId = GeneratedColumn( + 'sender_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [messageId, emoji, senderId, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'reactions'; + @override + Set get $primaryKey => {messageId, senderId, emoji}; + @override + ReactionsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReactionsData( + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + emoji: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}emoji'], + )!, + senderId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_id'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + Reactions createAlias(String alias) { + return Reactions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(message_id, sender_id, emoji)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class ReactionsData extends DataClass implements Insertable { + final String messageId; + final String emoji; + final int? senderId; + final int createdAt; + const ReactionsData({ + required this.messageId, + required this.emoji, + this.senderId, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['message_id'] = Variable(messageId); + map['emoji'] = Variable(emoji); + if (!nullToAbsent || senderId != null) { + map['sender_id'] = Variable(senderId); + } + map['created_at'] = Variable(createdAt); + return map; + } + + ReactionsCompanion toCompanion(bool nullToAbsent) { + return ReactionsCompanion( + messageId: Value(messageId), + emoji: Value(emoji), + senderId: senderId == null && nullToAbsent + ? const Value.absent() + : Value(senderId), + createdAt: Value(createdAt), + ); + } + + factory ReactionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReactionsData( + messageId: serializer.fromJson(json['messageId']), + emoji: serializer.fromJson(json['emoji']), + senderId: serializer.fromJson(json['senderId']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'messageId': serializer.toJson(messageId), + 'emoji': serializer.toJson(emoji), + 'senderId': serializer.toJson(senderId), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReactionsData copyWith({ + String? messageId, + String? emoji, + Value senderId = const Value.absent(), + int? createdAt, + }) => ReactionsData( + messageId: messageId ?? this.messageId, + emoji: emoji ?? this.emoji, + senderId: senderId.present ? senderId.value : this.senderId, + createdAt: createdAt ?? this.createdAt, + ); + ReactionsData copyWithCompanion(ReactionsCompanion data) { + return ReactionsData( + messageId: data.messageId.present ? data.messageId.value : this.messageId, + emoji: data.emoji.present ? data.emoji.value : this.emoji, + senderId: data.senderId.present ? data.senderId.value : this.senderId, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReactionsData(') + ..write('messageId: $messageId, ') + ..write('emoji: $emoji, ') + ..write('senderId: $senderId, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(messageId, emoji, senderId, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReactionsData && + other.messageId == this.messageId && + other.emoji == this.emoji && + other.senderId == this.senderId && + other.createdAt == this.createdAt); +} + +class ReactionsCompanion extends UpdateCompanion { + final Value messageId; + final Value emoji; + final Value senderId; + final Value createdAt; + final Value rowid; + const ReactionsCompanion({ + this.messageId = const Value.absent(), + this.emoji = const Value.absent(), + this.senderId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReactionsCompanion.insert({ + required String messageId, + required String emoji, + this.senderId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : messageId = Value(messageId), + emoji = Value(emoji); + static Insertable custom({ + Expression? messageId, + Expression? emoji, + Expression? senderId, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (messageId != null) 'message_id': messageId, + if (emoji != null) 'emoji': emoji, + if (senderId != null) 'sender_id': senderId, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReactionsCompanion copyWith({ + Value? messageId, + Value? emoji, + Value? senderId, + Value? createdAt, + Value? rowid, + }) { + return ReactionsCompanion( + messageId: messageId ?? this.messageId, + emoji: emoji ?? this.emoji, + senderId: senderId ?? this.senderId, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (emoji.present) { + map['emoji'] = Variable(emoji.value); + } + if (senderId.present) { + map['sender_id'] = Variable(senderId.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('ReactionsCompanion(') + ..write('messageId: $messageId, ') + ..write('emoji: $emoji, ') + ..write('senderId: $senderId, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class GroupMembers extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + GroupMembers(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn memberState = GeneratedColumn( + 'member_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn groupPublicKey = + GeneratedColumn( + 'group_public_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastChatOpened = GeneratedColumn( + 'last_chat_opened', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastTypeIndicator = GeneratedColumn( + 'last_type_indicator', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessage = GeneratedColumn( + 'last_message', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupId, + contactId, + memberState, + groupPublicKey, + lastChatOpened, + lastTypeIndicator, + lastMessage, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'group_members'; + @override + Set get $primaryKey => {groupId, contactId}; + @override + GroupMembersData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupMembersData( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + memberState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}member_state'], + ), + groupPublicKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}group_public_key'], + ), + lastChatOpened: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_chat_opened'], + ), + lastTypeIndicator: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_type_indicator'], + ), + lastMessage: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + GroupMembers createAlias(String alias) { + return GroupMembers(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(group_id, contact_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class GroupMembersData extends DataClass + implements Insertable { + final String groupId; + final int contactId; + final String? memberState; + final i2.Uint8List? groupPublicKey; + final int? lastChatOpened; + final int? lastTypeIndicator; + final int? lastMessage; + final int createdAt; + const GroupMembersData({ + required this.groupId, + required this.contactId, + this.memberState, + this.groupPublicKey, + this.lastChatOpened, + this.lastTypeIndicator, + this.lastMessage, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['contact_id'] = Variable(contactId); + if (!nullToAbsent || memberState != null) { + map['member_state'] = Variable(memberState); + } + if (!nullToAbsent || groupPublicKey != null) { + map['group_public_key'] = Variable(groupPublicKey); + } + if (!nullToAbsent || lastChatOpened != null) { + map['last_chat_opened'] = Variable(lastChatOpened); + } + if (!nullToAbsent || lastTypeIndicator != null) { + map['last_type_indicator'] = Variable(lastTypeIndicator); + } + if (!nullToAbsent || lastMessage != null) { + map['last_message'] = Variable(lastMessage); + } + map['created_at'] = Variable(createdAt); + return map; + } + + GroupMembersCompanion toCompanion(bool nullToAbsent) { + return GroupMembersCompanion( + groupId: Value(groupId), + contactId: Value(contactId), + memberState: memberState == null && nullToAbsent + ? const Value.absent() + : Value(memberState), + groupPublicKey: groupPublicKey == null && nullToAbsent + ? const Value.absent() + : Value(groupPublicKey), + lastChatOpened: lastChatOpened == null && nullToAbsent + ? const Value.absent() + : Value(lastChatOpened), + lastTypeIndicator: lastTypeIndicator == null && nullToAbsent + ? const Value.absent() + : Value(lastTypeIndicator), + lastMessage: lastMessage == null && nullToAbsent + ? const Value.absent() + : Value(lastMessage), + createdAt: Value(createdAt), + ); + } + + factory GroupMembersData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupMembersData( + groupId: serializer.fromJson(json['groupId']), + contactId: serializer.fromJson(json['contactId']), + memberState: serializer.fromJson(json['memberState']), + groupPublicKey: serializer.fromJson( + json['groupPublicKey'], + ), + lastChatOpened: serializer.fromJson(json['lastChatOpened']), + lastTypeIndicator: serializer.fromJson(json['lastTypeIndicator']), + lastMessage: serializer.fromJson(json['lastMessage']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'contactId': serializer.toJson(contactId), + 'memberState': serializer.toJson(memberState), + 'groupPublicKey': serializer.toJson(groupPublicKey), + 'lastChatOpened': serializer.toJson(lastChatOpened), + 'lastTypeIndicator': serializer.toJson(lastTypeIndicator), + 'lastMessage': serializer.toJson(lastMessage), + 'createdAt': serializer.toJson(createdAt), + }; + } + + GroupMembersData copyWith({ + String? groupId, + int? contactId, + Value memberState = const Value.absent(), + Value groupPublicKey = const Value.absent(), + Value lastChatOpened = const Value.absent(), + Value lastTypeIndicator = const Value.absent(), + Value lastMessage = const Value.absent(), + int? createdAt, + }) => GroupMembersData( + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + memberState: memberState.present ? memberState.value : this.memberState, + groupPublicKey: groupPublicKey.present + ? groupPublicKey.value + : this.groupPublicKey, + lastChatOpened: lastChatOpened.present + ? lastChatOpened.value + : this.lastChatOpened, + lastTypeIndicator: lastTypeIndicator.present + ? lastTypeIndicator.value + : this.lastTypeIndicator, + lastMessage: lastMessage.present ? lastMessage.value : this.lastMessage, + createdAt: createdAt ?? this.createdAt, + ); + GroupMembersData copyWithCompanion(GroupMembersCompanion data) { + return GroupMembersData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + memberState: data.memberState.present + ? data.memberState.value + : this.memberState, + groupPublicKey: data.groupPublicKey.present + ? data.groupPublicKey.value + : this.groupPublicKey, + lastChatOpened: data.lastChatOpened.present + ? data.lastChatOpened.value + : this.lastChatOpened, + lastTypeIndicator: data.lastTypeIndicator.present + ? data.lastTypeIndicator.value + : this.lastTypeIndicator, + lastMessage: data.lastMessage.present + ? data.lastMessage.value + : this.lastMessage, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('GroupMembersData(') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('memberState: $memberState, ') + ..write('groupPublicKey: $groupPublicKey, ') + ..write('lastChatOpened: $lastChatOpened, ') + ..write('lastTypeIndicator: $lastTypeIndicator, ') + ..write('lastMessage: $lastMessage, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupId, + contactId, + memberState, + $driftBlobEquality.hash(groupPublicKey), + lastChatOpened, + lastTypeIndicator, + lastMessage, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupMembersData && + other.groupId == this.groupId && + other.contactId == this.contactId && + other.memberState == this.memberState && + $driftBlobEquality.equals( + other.groupPublicKey, + this.groupPublicKey, + ) && + other.lastChatOpened == this.lastChatOpened && + other.lastTypeIndicator == this.lastTypeIndicator && + other.lastMessage == this.lastMessage && + other.createdAt == this.createdAt); +} + +class GroupMembersCompanion extends UpdateCompanion { + final Value groupId; + final Value contactId; + final Value memberState; + final Value groupPublicKey; + final Value lastChatOpened; + final Value lastTypeIndicator; + final Value lastMessage; + final Value createdAt; + final Value rowid; + const GroupMembersCompanion({ + this.groupId = const Value.absent(), + this.contactId = const Value.absent(), + this.memberState = const Value.absent(), + this.groupPublicKey = const Value.absent(), + this.lastChatOpened = const Value.absent(), + this.lastTypeIndicator = const Value.absent(), + this.lastMessage = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupMembersCompanion.insert({ + required String groupId, + required int contactId, + this.memberState = const Value.absent(), + this.groupPublicKey = const Value.absent(), + this.lastChatOpened = const Value.absent(), + this.lastTypeIndicator = const Value.absent(), + this.lastMessage = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + contactId = Value(contactId); + static Insertable custom({ + Expression? groupId, + Expression? contactId, + Expression? memberState, + Expression? groupPublicKey, + Expression? lastChatOpened, + Expression? lastTypeIndicator, + Expression? lastMessage, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (contactId != null) 'contact_id': contactId, + if (memberState != null) 'member_state': memberState, + if (groupPublicKey != null) 'group_public_key': groupPublicKey, + if (lastChatOpened != null) 'last_chat_opened': lastChatOpened, + if (lastTypeIndicator != null) 'last_type_indicator': lastTypeIndicator, + if (lastMessage != null) 'last_message': lastMessage, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupMembersCompanion copyWith({ + Value? groupId, + Value? contactId, + Value? memberState, + Value? groupPublicKey, + Value? lastChatOpened, + Value? lastTypeIndicator, + Value? lastMessage, + Value? createdAt, + Value? rowid, + }) { + return GroupMembersCompanion( + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + memberState: memberState ?? this.memberState, + groupPublicKey: groupPublicKey ?? this.groupPublicKey, + lastChatOpened: lastChatOpened ?? this.lastChatOpened, + lastTypeIndicator: lastTypeIndicator ?? this.lastTypeIndicator, + lastMessage: lastMessage ?? this.lastMessage, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (memberState.present) { + map['member_state'] = Variable(memberState.value); + } + if (groupPublicKey.present) { + map['group_public_key'] = Variable(groupPublicKey.value); + } + if (lastChatOpened.present) { + map['last_chat_opened'] = Variable(lastChatOpened.value); + } + if (lastTypeIndicator.present) { + map['last_type_indicator'] = Variable(lastTypeIndicator.value); + } + if (lastMessage.present) { + map['last_message'] = Variable(lastMessage.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('GroupMembersCompanion(') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('memberState: $memberState, ') + ..write('groupPublicKey: $groupPublicKey, ') + ..write('lastChatOpened: $lastChatOpened, ') + ..write('lastTypeIndicator: $lastTypeIndicator, ') + ..write('lastMessage: $lastMessage, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class Receipts extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Receipts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn receiptId = GeneratedColumn( + 'receipt_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn message = + GeneratedColumn( + 'message', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactWillSendsReceipt = + GeneratedColumn( + 'contact_will_sends_receipt', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 1 CHECK (contact_will_sends_receipt IN (0, 1))', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn + willBeRetriedByMediaUpload = GeneratedColumn( + 'will_be_retried_by_media_upload', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (will_be_retried_by_media_upload IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn markForRetry = GeneratedColumn( + 'mark_for_retry', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn markForRetryAfterAccepted = + GeneratedColumn( + 'mark_for_retry_after_accepted', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByServerAt = GeneratedColumn( + 'ack_by_server_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn retryCount = GeneratedColumn( + 'retry_count', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn lastRetry = GeneratedColumn( + 'last_retry', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + receiptId, + contactId, + messageId, + message, + contactWillSendsReceipt, + willBeRetriedByMediaUpload, + markForRetry, + markForRetryAfterAccepted, + ackByServerAt, + retryCount, + lastRetry, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'receipts'; + @override + Set get $primaryKey => {receiptId}; + @override + ReceiptsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReceiptsData( + receiptId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}receipt_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + ), + message: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}message'], + )!, + contactWillSendsReceipt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_will_sends_receipt'], + )!, + willBeRetriedByMediaUpload: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}will_be_retried_by_media_upload'], + )!, + markForRetry: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}mark_for_retry'], + ), + markForRetryAfterAccepted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}mark_for_retry_after_accepted'], + ), + ackByServerAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_server_at'], + ), + retryCount: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}retry_count'], + )!, + lastRetry: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_retry'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + Receipts createAlias(String alias) { + return Receipts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(receipt_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ReceiptsData extends DataClass implements Insertable { + final String receiptId; + final int contactId; + final String? messageId; + final i2.Uint8List message; + final int contactWillSendsReceipt; + final int willBeRetriedByMediaUpload; + final int? markForRetry; + final int? markForRetryAfterAccepted; + final int? ackByServerAt; + final int retryCount; + final int? lastRetry; + final int createdAt; + const ReceiptsData({ + required this.receiptId, + required this.contactId, + this.messageId, + required this.message, + required this.contactWillSendsReceipt, + required this.willBeRetriedByMediaUpload, + this.markForRetry, + this.markForRetryAfterAccepted, + this.ackByServerAt, + required this.retryCount, + this.lastRetry, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['receipt_id'] = Variable(receiptId); + map['contact_id'] = Variable(contactId); + if (!nullToAbsent || messageId != null) { + map['message_id'] = Variable(messageId); + } + map['message'] = Variable(message); + map['contact_will_sends_receipt'] = Variable(contactWillSendsReceipt); + map['will_be_retried_by_media_upload'] = Variable( + willBeRetriedByMediaUpload, + ); + if (!nullToAbsent || markForRetry != null) { + map['mark_for_retry'] = Variable(markForRetry); + } + if (!nullToAbsent || markForRetryAfterAccepted != null) { + map['mark_for_retry_after_accepted'] = Variable( + markForRetryAfterAccepted, + ); + } + if (!nullToAbsent || ackByServerAt != null) { + map['ack_by_server_at'] = Variable(ackByServerAt); + } + map['retry_count'] = Variable(retryCount); + if (!nullToAbsent || lastRetry != null) { + map['last_retry'] = Variable(lastRetry); + } + map['created_at'] = Variable(createdAt); + return map; + } + + ReceiptsCompanion toCompanion(bool nullToAbsent) { + return ReceiptsCompanion( + receiptId: Value(receiptId), + contactId: Value(contactId), + messageId: messageId == null && nullToAbsent + ? const Value.absent() + : Value(messageId), + message: Value(message), + contactWillSendsReceipt: Value(contactWillSendsReceipt), + willBeRetriedByMediaUpload: Value(willBeRetriedByMediaUpload), + markForRetry: markForRetry == null && nullToAbsent + ? const Value.absent() + : Value(markForRetry), + markForRetryAfterAccepted: + markForRetryAfterAccepted == null && nullToAbsent + ? const Value.absent() + : Value(markForRetryAfterAccepted), + ackByServerAt: ackByServerAt == null && nullToAbsent + ? const Value.absent() + : Value(ackByServerAt), + retryCount: Value(retryCount), + lastRetry: lastRetry == null && nullToAbsent + ? const Value.absent() + : Value(lastRetry), + createdAt: Value(createdAt), + ); + } + + factory ReceiptsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReceiptsData( + receiptId: serializer.fromJson(json['receiptId']), + contactId: serializer.fromJson(json['contactId']), + messageId: serializer.fromJson(json['messageId']), + message: serializer.fromJson(json['message']), + contactWillSendsReceipt: serializer.fromJson( + json['contactWillSendsReceipt'], + ), + willBeRetriedByMediaUpload: serializer.fromJson( + json['willBeRetriedByMediaUpload'], + ), + markForRetry: serializer.fromJson(json['markForRetry']), + markForRetryAfterAccepted: serializer.fromJson( + json['markForRetryAfterAccepted'], + ), + ackByServerAt: serializer.fromJson(json['ackByServerAt']), + retryCount: serializer.fromJson(json['retryCount']), + lastRetry: serializer.fromJson(json['lastRetry']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'receiptId': serializer.toJson(receiptId), + 'contactId': serializer.toJson(contactId), + 'messageId': serializer.toJson(messageId), + 'message': serializer.toJson(message), + 'contactWillSendsReceipt': serializer.toJson( + contactWillSendsReceipt, + ), + 'willBeRetriedByMediaUpload': serializer.toJson( + willBeRetriedByMediaUpload, + ), + 'markForRetry': serializer.toJson(markForRetry), + 'markForRetryAfterAccepted': serializer.toJson( + markForRetryAfterAccepted, + ), + 'ackByServerAt': serializer.toJson(ackByServerAt), + 'retryCount': serializer.toJson(retryCount), + 'lastRetry': serializer.toJson(lastRetry), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReceiptsData copyWith({ + String? receiptId, + int? contactId, + Value messageId = const Value.absent(), + i2.Uint8List? message, + int? contactWillSendsReceipt, + int? willBeRetriedByMediaUpload, + Value markForRetry = const Value.absent(), + Value markForRetryAfterAccepted = const Value.absent(), + Value ackByServerAt = const Value.absent(), + int? retryCount, + Value lastRetry = const Value.absent(), + int? createdAt, + }) => ReceiptsData( + receiptId: receiptId ?? this.receiptId, + contactId: contactId ?? this.contactId, + messageId: messageId.present ? messageId.value : this.messageId, + message: message ?? this.message, + contactWillSendsReceipt: + contactWillSendsReceipt ?? this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: + willBeRetriedByMediaUpload ?? this.willBeRetriedByMediaUpload, + markForRetry: markForRetry.present ? markForRetry.value : this.markForRetry, + markForRetryAfterAccepted: markForRetryAfterAccepted.present + ? markForRetryAfterAccepted.value + : this.markForRetryAfterAccepted, + ackByServerAt: ackByServerAt.present + ? ackByServerAt.value + : this.ackByServerAt, + retryCount: retryCount ?? this.retryCount, + lastRetry: lastRetry.present ? lastRetry.value : this.lastRetry, + createdAt: createdAt ?? this.createdAt, + ); + ReceiptsData copyWithCompanion(ReceiptsCompanion data) { + return ReceiptsData( + receiptId: data.receiptId.present ? data.receiptId.value : this.receiptId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + message: data.message.present ? data.message.value : this.message, + contactWillSendsReceipt: data.contactWillSendsReceipt.present + ? data.contactWillSendsReceipt.value + : this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: data.willBeRetriedByMediaUpload.present + ? data.willBeRetriedByMediaUpload.value + : this.willBeRetriedByMediaUpload, + markForRetry: data.markForRetry.present + ? data.markForRetry.value + : this.markForRetry, + markForRetryAfterAccepted: data.markForRetryAfterAccepted.present + ? data.markForRetryAfterAccepted.value + : this.markForRetryAfterAccepted, + ackByServerAt: data.ackByServerAt.present + ? data.ackByServerAt.value + : this.ackByServerAt, + retryCount: data.retryCount.present + ? data.retryCount.value + : this.retryCount, + lastRetry: data.lastRetry.present ? data.lastRetry.value : this.lastRetry, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReceiptsData(') + ..write('receiptId: $receiptId, ') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('message: $message, ') + ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') + ..write('willBeRetriedByMediaUpload: $willBeRetriedByMediaUpload, ') + ..write('markForRetry: $markForRetry, ') + ..write('markForRetryAfterAccepted: $markForRetryAfterAccepted, ') + ..write('ackByServerAt: $ackByServerAt, ') + ..write('retryCount: $retryCount, ') + ..write('lastRetry: $lastRetry, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + receiptId, + contactId, + messageId, + $driftBlobEquality.hash(message), + contactWillSendsReceipt, + willBeRetriedByMediaUpload, + markForRetry, + markForRetryAfterAccepted, + ackByServerAt, + retryCount, + lastRetry, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReceiptsData && + other.receiptId == this.receiptId && + other.contactId == this.contactId && + other.messageId == this.messageId && + $driftBlobEquality.equals(other.message, this.message) && + other.contactWillSendsReceipt == this.contactWillSendsReceipt && + other.willBeRetriedByMediaUpload == this.willBeRetriedByMediaUpload && + other.markForRetry == this.markForRetry && + other.markForRetryAfterAccepted == this.markForRetryAfterAccepted && + other.ackByServerAt == this.ackByServerAt && + other.retryCount == this.retryCount && + other.lastRetry == this.lastRetry && + other.createdAt == this.createdAt); +} + +class ReceiptsCompanion extends UpdateCompanion { + final Value receiptId; + final Value contactId; + final Value messageId; + final Value message; + final Value contactWillSendsReceipt; + final Value willBeRetriedByMediaUpload; + final Value markForRetry; + final Value markForRetryAfterAccepted; + final Value ackByServerAt; + final Value retryCount; + final Value lastRetry; + final Value createdAt; + final Value rowid; + const ReceiptsCompanion({ + this.receiptId = const Value.absent(), + this.contactId = const Value.absent(), + this.messageId = const Value.absent(), + this.message = const Value.absent(), + this.contactWillSendsReceipt = const Value.absent(), + this.willBeRetriedByMediaUpload = const Value.absent(), + this.markForRetry = const Value.absent(), + this.markForRetryAfterAccepted = const Value.absent(), + this.ackByServerAt = const Value.absent(), + this.retryCount = const Value.absent(), + this.lastRetry = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReceiptsCompanion.insert({ + required String receiptId, + required int contactId, + this.messageId = const Value.absent(), + required i2.Uint8List message, + this.contactWillSendsReceipt = const Value.absent(), + this.willBeRetriedByMediaUpload = const Value.absent(), + this.markForRetry = const Value.absent(), + this.markForRetryAfterAccepted = const Value.absent(), + this.ackByServerAt = const Value.absent(), + this.retryCount = const Value.absent(), + this.lastRetry = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : receiptId = Value(receiptId), + contactId = Value(contactId), + message = Value(message); + static Insertable custom({ + Expression? receiptId, + Expression? contactId, + Expression? messageId, + Expression? message, + Expression? contactWillSendsReceipt, + Expression? willBeRetriedByMediaUpload, + Expression? markForRetry, + Expression? markForRetryAfterAccepted, + Expression? ackByServerAt, + Expression? retryCount, + Expression? lastRetry, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (receiptId != null) 'receipt_id': receiptId, + if (contactId != null) 'contact_id': contactId, + if (messageId != null) 'message_id': messageId, + if (message != null) 'message': message, + if (contactWillSendsReceipt != null) + 'contact_will_sends_receipt': contactWillSendsReceipt, + if (willBeRetriedByMediaUpload != null) + 'will_be_retried_by_media_upload': willBeRetriedByMediaUpload, + if (markForRetry != null) 'mark_for_retry': markForRetry, + if (markForRetryAfterAccepted != null) + 'mark_for_retry_after_accepted': markForRetryAfterAccepted, + if (ackByServerAt != null) 'ack_by_server_at': ackByServerAt, + if (retryCount != null) 'retry_count': retryCount, + if (lastRetry != null) 'last_retry': lastRetry, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReceiptsCompanion copyWith({ + Value? receiptId, + Value? contactId, + Value? messageId, + Value? message, + Value? contactWillSendsReceipt, + Value? willBeRetriedByMediaUpload, + Value? markForRetry, + Value? markForRetryAfterAccepted, + Value? ackByServerAt, + Value? retryCount, + Value? lastRetry, + Value? createdAt, + Value? rowid, + }) { + return ReceiptsCompanion( + receiptId: receiptId ?? this.receiptId, + contactId: contactId ?? this.contactId, + messageId: messageId ?? this.messageId, + message: message ?? this.message, + contactWillSendsReceipt: + contactWillSendsReceipt ?? this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: + willBeRetriedByMediaUpload ?? this.willBeRetriedByMediaUpload, + markForRetry: markForRetry ?? this.markForRetry, + markForRetryAfterAccepted: + markForRetryAfterAccepted ?? this.markForRetryAfterAccepted, + ackByServerAt: ackByServerAt ?? this.ackByServerAt, + retryCount: retryCount ?? this.retryCount, + lastRetry: lastRetry ?? this.lastRetry, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (receiptId.present) { + map['receipt_id'] = Variable(receiptId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (message.present) { + map['message'] = Variable(message.value); + } + if (contactWillSendsReceipt.present) { + map['contact_will_sends_receipt'] = Variable( + contactWillSendsReceipt.value, + ); + } + if (willBeRetriedByMediaUpload.present) { + map['will_be_retried_by_media_upload'] = Variable( + willBeRetriedByMediaUpload.value, + ); + } + if (markForRetry.present) { + map['mark_for_retry'] = Variable(markForRetry.value); + } + if (markForRetryAfterAccepted.present) { + map['mark_for_retry_after_accepted'] = Variable( + markForRetryAfterAccepted.value, + ); + } + if (ackByServerAt.present) { + map['ack_by_server_at'] = Variable(ackByServerAt.value); + } + if (retryCount.present) { + map['retry_count'] = Variable(retryCount.value); + } + if (lastRetry.present) { + map['last_retry'] = Variable(lastRetry.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('ReceiptsCompanion(') + ..write('receiptId: $receiptId, ') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('message: $message, ') + ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') + ..write('willBeRetriedByMediaUpload: $willBeRetriedByMediaUpload, ') + ..write('markForRetry: $markForRetry, ') + ..write('markForRetryAfterAccepted: $markForRetryAfterAccepted, ') + ..write('ackByServerAt: $ackByServerAt, ') + ..write('retryCount: $retryCount, ') + ..write('lastRetry: $lastRetry, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class ReceivedReceipts extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + ReceivedReceipts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn receiptId = GeneratedColumn( + 'receipt_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [receiptId, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'received_receipts'; + @override + Set get $primaryKey => {receiptId}; + @override + ReceivedReceiptsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReceivedReceiptsData( + receiptId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}receipt_id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + ReceivedReceipts createAlias(String alias) { + return ReceivedReceipts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(receipt_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ReceivedReceiptsData extends DataClass + implements Insertable { + final String receiptId; + final int createdAt; + const ReceivedReceiptsData({ + required this.receiptId, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['receipt_id'] = Variable(receiptId); + map['created_at'] = Variable(createdAt); + return map; + } + + ReceivedReceiptsCompanion toCompanion(bool nullToAbsent) { + return ReceivedReceiptsCompanion( + receiptId: Value(receiptId), + createdAt: Value(createdAt), + ); + } + + factory ReceivedReceiptsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReceivedReceiptsData( + receiptId: serializer.fromJson(json['receiptId']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'receiptId': serializer.toJson(receiptId), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReceivedReceiptsData copyWith({String? receiptId, int? createdAt}) => + ReceivedReceiptsData( + receiptId: receiptId ?? this.receiptId, + createdAt: createdAt ?? this.createdAt, + ); + ReceivedReceiptsData copyWithCompanion(ReceivedReceiptsCompanion data) { + return ReceivedReceiptsData( + receiptId: data.receiptId.present ? data.receiptId.value : this.receiptId, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReceivedReceiptsData(') + ..write('receiptId: $receiptId, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(receiptId, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReceivedReceiptsData && + other.receiptId == this.receiptId && + other.createdAt == this.createdAt); +} + +class ReceivedReceiptsCompanion extends UpdateCompanion { + final Value receiptId; + final Value createdAt; + final Value rowid; + const ReceivedReceiptsCompanion({ + this.receiptId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReceivedReceiptsCompanion.insert({ + required String receiptId, + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : receiptId = Value(receiptId); + static Insertable custom({ + Expression? receiptId, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (receiptId != null) 'receipt_id': receiptId, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReceivedReceiptsCompanion copyWith({ + Value? receiptId, + Value? createdAt, + Value? rowid, + }) { + return ReceivedReceiptsCompanion( + receiptId: receiptId ?? this.receiptId, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (receiptId.present) { + map['receipt_id'] = Variable(receiptId.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('ReceivedReceiptsCompanion(') + ..write('receiptId: $receiptId, ') + ..write('createdAt: $createdAt, ') + ..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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn identityKey = + GeneratedColumn( + 'identity_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalIdentityKeyStores createAlias(String alias) { + return SignalIdentityKeyStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(device_id, name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalIdentityKeyStoresData extends DataClass + implements Insertable { + final int deviceId; + final String name; + final i2.Uint8List identityKey; + final int 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, + i2.Uint8List? identityKey, + int? 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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn preKey = + GeneratedColumn( + 'pre_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalPreKeyStores createAlias(String alias) { + return SignalPreKeyStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(pre_key_id)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalPreKeyStoresData extends DataClass + implements Insertable { + final int preKeyId; + final i2.Uint8List preKey; + final int 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, + i2.Uint8List? preKey, + int? 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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderKey = + GeneratedColumn( + 'sender_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + @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); + } + + @override + List get customConstraints => const ['PRIMARY KEY(sender_key_name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalSenderKeyStoresData extends DataClass + implements Insertable { + final String senderKeyName; + final i2.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, + i2.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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn sessionRecord = + GeneratedColumn( + 'session_record', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalSessionStores createAlias(String alias) { + return SignalSessionStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(device_id, name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalSessionStoresData extends DataClass + implements Insertable { + final int deviceId; + final String name; + final i2.Uint8List sessionRecord; + final int 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, + i2.Uint8List? sessionRecord, + int? 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 i2.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 MessageActions extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MessageActions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn actionAt = GeneratedColumn( + 'action_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [messageId, contactId, type, actionAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'message_actions'; + @override + Set get $primaryKey => {messageId, contactId, type}; + @override + MessageActionsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MessageActionsData( + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + actionAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}action_at'], + )!, + ); + } + + @override + MessageActions createAlias(String alias) { + return MessageActions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(message_id, contact_id, type)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class MessageActionsData extends DataClass + implements Insertable { + final String messageId; + final int contactId; + final String type; + final int actionAt; + const MessageActionsData({ + required this.messageId, + required this.contactId, + required this.type, + required this.actionAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['message_id'] = Variable(messageId); + map['contact_id'] = Variable(contactId); + map['type'] = Variable(type); + map['action_at'] = Variable(actionAt); + return map; + } + + MessageActionsCompanion toCompanion(bool nullToAbsent) { + return MessageActionsCompanion( + messageId: Value(messageId), + contactId: Value(contactId), + type: Value(type), + actionAt: Value(actionAt), + ); + } + + factory MessageActionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessageActionsData( + messageId: serializer.fromJson(json['messageId']), + contactId: serializer.fromJson(json['contactId']), + type: serializer.fromJson(json['type']), + actionAt: serializer.fromJson(json['actionAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'messageId': serializer.toJson(messageId), + 'contactId': serializer.toJson(contactId), + 'type': serializer.toJson(type), + 'actionAt': serializer.toJson(actionAt), + }; + } + + MessageActionsData copyWith({ + String? messageId, + int? contactId, + String? type, + int? actionAt, + }) => MessageActionsData( + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + ); + MessageActionsData copyWithCompanion(MessageActionsCompanion data) { + return MessageActionsData( + messageId: data.messageId.present ? data.messageId.value : this.messageId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + type: data.type.present ? data.type.value : this.type, + actionAt: data.actionAt.present ? data.actionAt.value : this.actionAt, + ); + } + + @override + String toString() { + return (StringBuffer('MessageActionsData(') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('actionAt: $actionAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(messageId, contactId, type, actionAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessageActionsData && + other.messageId == this.messageId && + other.contactId == this.contactId && + other.type == this.type && + other.actionAt == this.actionAt); +} + +class MessageActionsCompanion extends UpdateCompanion { + final Value messageId; + final Value contactId; + final Value type; + final Value actionAt; + final Value rowid; + const MessageActionsCompanion({ + this.messageId = const Value.absent(), + this.contactId = const Value.absent(), + this.type = const Value.absent(), + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + MessageActionsCompanion.insert({ + required String messageId, + required int contactId, + required String type, + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : messageId = Value(messageId), + contactId = Value(contactId), + type = Value(type); + static Insertable custom({ + Expression? messageId, + Expression? contactId, + Expression? type, + Expression? actionAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (messageId != null) 'message_id': messageId, + if (contactId != null) 'contact_id': contactId, + if (type != null) 'type': type, + if (actionAt != null) 'action_at': actionAt, + if (rowid != null) 'rowid': rowid, + }); + } + + MessageActionsCompanion copyWith({ + Value? messageId, + Value? contactId, + Value? type, + Value? actionAt, + Value? rowid, + }) { + return MessageActionsCompanion( + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (actionAt.present) { + map['action_at'] = Variable(actionAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessageActionsCompanion(') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('actionAt: $actionAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class GroupHistories extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + GroupHistories(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupHistoryId = GeneratedColumn( + 'group_history_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn affectedContactId = GeneratedColumn( + 'affected_contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn oldGroupName = GeneratedColumn( + 'old_group_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn newGroupName = GeneratedColumn( + 'new_group_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn newDeleteMessagesAfterMilliseconds = + GeneratedColumn( + 'new_delete_messages_after_milliseconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn actionAt = GeneratedColumn( + 'action_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupHistoryId, + groupId, + contactId, + affectedContactId, + oldGroupName, + newGroupName, + newDeleteMessagesAfterMilliseconds, + type, + actionAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'group_histories'; + @override + Set get $primaryKey => {groupHistoryId}; + @override + GroupHistoriesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupHistoriesData( + groupHistoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_history_id'], + )!, + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + affectedContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}affected_contact_id'], + ), + oldGroupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}old_group_name'], + ), + newGroupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}new_group_name'], + ), + newDeleteMessagesAfterMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}new_delete_messages_after_milliseconds'], + ), + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + actionAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}action_at'], + )!, + ); + } + + @override + GroupHistories createAlias(String alias) { + return GroupHistories(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(group_history_id)']; + @override + bool get dontWriteConstraints => true; +} + +class GroupHistoriesData extends DataClass + implements Insertable { + final String groupHistoryId; + final String groupId; + final int? contactId; + final int? affectedContactId; + final String? oldGroupName; + final String? newGroupName; + final int? newDeleteMessagesAfterMilliseconds; + final String type; + final int actionAt; + const GroupHistoriesData({ + required this.groupHistoryId, + required this.groupId, + this.contactId, + this.affectedContactId, + this.oldGroupName, + this.newGroupName, + this.newDeleteMessagesAfterMilliseconds, + required this.type, + required this.actionAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_history_id'] = Variable(groupHistoryId); + map['group_id'] = Variable(groupId); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + if (!nullToAbsent || affectedContactId != null) { + map['affected_contact_id'] = Variable(affectedContactId); + } + if (!nullToAbsent || oldGroupName != null) { + map['old_group_name'] = Variable(oldGroupName); + } + if (!nullToAbsent || newGroupName != null) { + map['new_group_name'] = Variable(newGroupName); + } + if (!nullToAbsent || newDeleteMessagesAfterMilliseconds != null) { + map['new_delete_messages_after_milliseconds'] = Variable( + newDeleteMessagesAfterMilliseconds, + ); + } + map['type'] = Variable(type); + map['action_at'] = Variable(actionAt); + return map; + } + + GroupHistoriesCompanion toCompanion(bool nullToAbsent) { + return GroupHistoriesCompanion( + groupHistoryId: Value(groupHistoryId), + groupId: Value(groupId), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + affectedContactId: affectedContactId == null && nullToAbsent + ? const Value.absent() + : Value(affectedContactId), + oldGroupName: oldGroupName == null && nullToAbsent + ? const Value.absent() + : Value(oldGroupName), + newGroupName: newGroupName == null && nullToAbsent + ? const Value.absent() + : Value(newGroupName), + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds == null && nullToAbsent + ? const Value.absent() + : Value(newDeleteMessagesAfterMilliseconds), + type: Value(type), + actionAt: Value(actionAt), + ); + } + + factory GroupHistoriesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupHistoriesData( + groupHistoryId: serializer.fromJson(json['groupHistoryId']), + groupId: serializer.fromJson(json['groupId']), + contactId: serializer.fromJson(json['contactId']), + affectedContactId: serializer.fromJson(json['affectedContactId']), + oldGroupName: serializer.fromJson(json['oldGroupName']), + newGroupName: serializer.fromJson(json['newGroupName']), + newDeleteMessagesAfterMilliseconds: serializer.fromJson( + json['newDeleteMessagesAfterMilliseconds'], + ), + type: serializer.fromJson(json['type']), + actionAt: serializer.fromJson(json['actionAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupHistoryId': serializer.toJson(groupHistoryId), + 'groupId': serializer.toJson(groupId), + 'contactId': serializer.toJson(contactId), + 'affectedContactId': serializer.toJson(affectedContactId), + 'oldGroupName': serializer.toJson(oldGroupName), + 'newGroupName': serializer.toJson(newGroupName), + 'newDeleteMessagesAfterMilliseconds': serializer.toJson( + newDeleteMessagesAfterMilliseconds, + ), + 'type': serializer.toJson(type), + 'actionAt': serializer.toJson(actionAt), + }; + } + + GroupHistoriesData copyWith({ + String? groupHistoryId, + String? groupId, + Value contactId = const Value.absent(), + Value affectedContactId = const Value.absent(), + Value oldGroupName = const Value.absent(), + Value newGroupName = const Value.absent(), + Value newDeleteMessagesAfterMilliseconds = const Value.absent(), + String? type, + int? actionAt, + }) => GroupHistoriesData( + groupHistoryId: groupHistoryId ?? this.groupHistoryId, + groupId: groupId ?? this.groupId, + contactId: contactId.present ? contactId.value : this.contactId, + affectedContactId: affectedContactId.present + ? affectedContactId.value + : this.affectedContactId, + oldGroupName: oldGroupName.present ? oldGroupName.value : this.oldGroupName, + newGroupName: newGroupName.present ? newGroupName.value : this.newGroupName, + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds.present + ? newDeleteMessagesAfterMilliseconds.value + : this.newDeleteMessagesAfterMilliseconds, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + ); + GroupHistoriesData copyWithCompanion(GroupHistoriesCompanion data) { + return GroupHistoriesData( + groupHistoryId: data.groupHistoryId.present + ? data.groupHistoryId.value + : this.groupHistoryId, + groupId: data.groupId.present ? data.groupId.value : this.groupId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + affectedContactId: data.affectedContactId.present + ? data.affectedContactId.value + : this.affectedContactId, + oldGroupName: data.oldGroupName.present + ? data.oldGroupName.value + : this.oldGroupName, + newGroupName: data.newGroupName.present + ? data.newGroupName.value + : this.newGroupName, + newDeleteMessagesAfterMilliseconds: + data.newDeleteMessagesAfterMilliseconds.present + ? data.newDeleteMessagesAfterMilliseconds.value + : this.newDeleteMessagesAfterMilliseconds, + type: data.type.present ? data.type.value : this.type, + actionAt: data.actionAt.present ? data.actionAt.value : this.actionAt, + ); + } + + @override + String toString() { + return (StringBuffer('GroupHistoriesData(') + ..write('groupHistoryId: $groupHistoryId, ') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('affectedContactId: $affectedContactId, ') + ..write('oldGroupName: $oldGroupName, ') + ..write('newGroupName: $newGroupName, ') + ..write( + 'newDeleteMessagesAfterMilliseconds: $newDeleteMessagesAfterMilliseconds, ', + ) + ..write('type: $type, ') + ..write('actionAt: $actionAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupHistoryId, + groupId, + contactId, + affectedContactId, + oldGroupName, + newGroupName, + newDeleteMessagesAfterMilliseconds, + type, + actionAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupHistoriesData && + other.groupHistoryId == this.groupHistoryId && + other.groupId == this.groupId && + other.contactId == this.contactId && + other.affectedContactId == this.affectedContactId && + other.oldGroupName == this.oldGroupName && + other.newGroupName == this.newGroupName && + other.newDeleteMessagesAfterMilliseconds == + this.newDeleteMessagesAfterMilliseconds && + other.type == this.type && + other.actionAt == this.actionAt); +} + +class GroupHistoriesCompanion extends UpdateCompanion { + final Value groupHistoryId; + final Value groupId; + final Value contactId; + final Value affectedContactId; + final Value oldGroupName; + final Value newGroupName; + final Value newDeleteMessagesAfterMilliseconds; + final Value type; + final Value actionAt; + final Value rowid; + const GroupHistoriesCompanion({ + this.groupHistoryId = const Value.absent(), + this.groupId = const Value.absent(), + this.contactId = const Value.absent(), + this.affectedContactId = const Value.absent(), + this.oldGroupName = const Value.absent(), + this.newGroupName = const Value.absent(), + this.newDeleteMessagesAfterMilliseconds = const Value.absent(), + this.type = const Value.absent(), + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupHistoriesCompanion.insert({ + required String groupHistoryId, + required String groupId, + this.contactId = const Value.absent(), + this.affectedContactId = const Value.absent(), + this.oldGroupName = const Value.absent(), + this.newGroupName = const Value.absent(), + this.newDeleteMessagesAfterMilliseconds = const Value.absent(), + required String type, + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupHistoryId = Value(groupHistoryId), + groupId = Value(groupId), + type = Value(type); + static Insertable custom({ + Expression? groupHistoryId, + Expression? groupId, + Expression? contactId, + Expression? affectedContactId, + Expression? oldGroupName, + Expression? newGroupName, + Expression? newDeleteMessagesAfterMilliseconds, + Expression? type, + Expression? actionAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupHistoryId != null) 'group_history_id': groupHistoryId, + if (groupId != null) 'group_id': groupId, + if (contactId != null) 'contact_id': contactId, + if (affectedContactId != null) 'affected_contact_id': affectedContactId, + if (oldGroupName != null) 'old_group_name': oldGroupName, + if (newGroupName != null) 'new_group_name': newGroupName, + if (newDeleteMessagesAfterMilliseconds != null) + 'new_delete_messages_after_milliseconds': + newDeleteMessagesAfterMilliseconds, + if (type != null) 'type': type, + if (actionAt != null) 'action_at': actionAt, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupHistoriesCompanion copyWith({ + Value? groupHistoryId, + Value? groupId, + Value? contactId, + Value? affectedContactId, + Value? oldGroupName, + Value? newGroupName, + Value? newDeleteMessagesAfterMilliseconds, + Value? type, + Value? actionAt, + Value? rowid, + }) { + return GroupHistoriesCompanion( + groupHistoryId: groupHistoryId ?? this.groupHistoryId, + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + affectedContactId: affectedContactId ?? this.affectedContactId, + oldGroupName: oldGroupName ?? this.oldGroupName, + newGroupName: newGroupName ?? this.newGroupName, + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds ?? + this.newDeleteMessagesAfterMilliseconds, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupHistoryId.present) { + map['group_history_id'] = Variable(groupHistoryId.value); + } + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (affectedContactId.present) { + map['affected_contact_id'] = Variable(affectedContactId.value); + } + if (oldGroupName.present) { + map['old_group_name'] = Variable(oldGroupName.value); + } + if (newGroupName.present) { + map['new_group_name'] = Variable(newGroupName.value); + } + if (newDeleteMessagesAfterMilliseconds.present) { + map['new_delete_messages_after_milliseconds'] = Variable( + newDeleteMessagesAfterMilliseconds.value, + ); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (actionAt.present) { + map['action_at'] = Variable(actionAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GroupHistoriesCompanion(') + ..write('groupHistoryId: $groupHistoryId, ') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('affectedContactId: $affectedContactId, ') + ..write('oldGroupName: $oldGroupName, ') + ..write('newGroupName: $newGroupName, ') + ..write( + 'newDeleteMessagesAfterMilliseconds: $newDeleteMessagesAfterMilliseconds, ', + ) + ..write('type: $type, ') + ..write('actionAt: $actionAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class KeyVerifications extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + KeyVerifications(this.attachedDatabase, [this._alias]); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [contactId, type, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'key_verifications'; + @override + Set get $primaryKey => {contactId}; + @override + KeyVerificationsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return KeyVerificationsData( + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + KeyVerifications createAlias(String alias) { + return KeyVerifications(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(contact_id)']; + @override + bool get dontWriteConstraints => true; +} + +class KeyVerificationsData extends DataClass + implements Insertable { + final int contactId; + final String type; + final int createdAt; + const KeyVerificationsData({ + required this.contactId, + required this.type, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['contact_id'] = Variable(contactId); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + return map; + } + + KeyVerificationsCompanion toCompanion(bool nullToAbsent) { + return KeyVerificationsCompanion( + contactId: Value(contactId), + type: Value(type), + createdAt: Value(createdAt), + ); + } + + factory KeyVerificationsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return KeyVerificationsData( + contactId: serializer.fromJson(json['contactId']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'contactId': serializer.toJson(contactId), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + }; + } + + KeyVerificationsData copyWith({ + int? contactId, + String? type, + int? createdAt, + }) => KeyVerificationsData( + contactId: contactId ?? this.contactId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + KeyVerificationsData copyWithCompanion(KeyVerificationsCompanion data) { + return KeyVerificationsData( + contactId: data.contactId.present ? data.contactId.value : this.contactId, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('KeyVerificationsData(') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(contactId, type, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is KeyVerificationsData && + other.contactId == this.contactId && + other.type == this.type && + other.createdAt == this.createdAt); +} + +class KeyVerificationsCompanion extends UpdateCompanion { + final Value contactId; + final Value type; + final Value createdAt; + const KeyVerificationsCompanion({ + this.contactId = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + }); + KeyVerificationsCompanion.insert({ + this.contactId = const Value.absent(), + required String type, + this.createdAt = const Value.absent(), + }) : type = Value(type); + static Insertable custom({ + Expression? contactId, + Expression? type, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (contactId != null) 'contact_id': contactId, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + }); + } + + KeyVerificationsCompanion copyWith({ + Value? contactId, + Value? type, + Value? createdAt, + }) { + return KeyVerificationsCompanion( + contactId: contactId ?? this.contactId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('KeyVerificationsCompanion(') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class VerificationTokens extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + VerificationTokens(this.attachedDatabase, [this._alias]); + late final GeneratedColumn tokenId = GeneratedColumn( + 'token_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn token = + GeneratedColumn( + 'token', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [tokenId, token, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'verification_tokens'; + @override + Set get $primaryKey => {tokenId}; + @override + VerificationTokensData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return VerificationTokensData( + tokenId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}token_id'], + )!, + token: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}token'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + VerificationTokens createAlias(String alias) { + return VerificationTokens(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class VerificationTokensData extends DataClass + implements Insertable { + final int tokenId; + final i2.Uint8List token; + final int createdAt; + const VerificationTokensData({ + required this.tokenId, + required this.token, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['token_id'] = Variable(tokenId); + map['token'] = Variable(token); + map['created_at'] = Variable(createdAt); + return map; + } + + VerificationTokensCompanion toCompanion(bool nullToAbsent) { + return VerificationTokensCompanion( + tokenId: Value(tokenId), + token: Value(token), + createdAt: Value(createdAt), + ); + } + + factory VerificationTokensData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return VerificationTokensData( + tokenId: serializer.fromJson(json['tokenId']), + token: serializer.fromJson(json['token']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'tokenId': serializer.toJson(tokenId), + 'token': serializer.toJson(token), + 'createdAt': serializer.toJson(createdAt), + }; + } + + VerificationTokensData copyWith({ + int? tokenId, + i2.Uint8List? token, + int? createdAt, + }) => VerificationTokensData( + tokenId: tokenId ?? this.tokenId, + token: token ?? this.token, + createdAt: createdAt ?? this.createdAt, + ); + VerificationTokensData copyWithCompanion(VerificationTokensCompanion data) { + return VerificationTokensData( + tokenId: data.tokenId.present ? data.tokenId.value : this.tokenId, + token: data.token.present ? data.token.value : this.token, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('VerificationTokensData(') + ..write('tokenId: $tokenId, ') + ..write('token: $token, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(tokenId, $driftBlobEquality.hash(token), createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is VerificationTokensData && + other.tokenId == this.tokenId && + $driftBlobEquality.equals(other.token, this.token) && + other.createdAt == this.createdAt); +} + +class VerificationTokensCompanion + extends UpdateCompanion { + final Value tokenId; + final Value token; + final Value createdAt; + const VerificationTokensCompanion({ + this.tokenId = const Value.absent(), + this.token = const Value.absent(), + this.createdAt = const Value.absent(), + }); + VerificationTokensCompanion.insert({ + this.tokenId = const Value.absent(), + required i2.Uint8List token, + this.createdAt = const Value.absent(), + }) : token = Value(token); + static Insertable custom({ + Expression? tokenId, + Expression? token, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (tokenId != null) 'token_id': tokenId, + if (token != null) 'token': token, + if (createdAt != null) 'created_at': createdAt, + }); + } + + VerificationTokensCompanion copyWith({ + Value? tokenId, + Value? token, + Value? createdAt, + }) { + return VerificationTokensCompanion( + tokenId: tokenId ?? this.tokenId, + token: token ?? this.token, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (tokenId.present) { + map['token_id'] = Variable(tokenId.value); + } + if (token.present) { + map['token'] = Variable(token.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('VerificationTokensCompanion(') + ..write('tokenId: $tokenId, ') + ..write('token: $token, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryAnnouncedUsers extends Table + with + TableInfo< + UserDiscoveryAnnouncedUsers, + UserDiscoveryAnnouncedUsersData + > { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryAnnouncedUsers(this.attachedDatabase, [this._alias]); + late final GeneratedColumn announcedUserId = GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn announcedPublicKey = + GeneratedColumn( + 'announced_public_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicId = GeneratedColumn( + 'public_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL UNIQUE', + ); + @override + List get $columns => [ + announcedUserId, + announcedPublicKey, + publicId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_announced_users'; + @override + Set get $primaryKey => {announcedUserId}; + @override + UserDiscoveryAnnouncedUsersData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryAnnouncedUsersData( + announcedUserId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}announced_user_id'], + )!, + announcedPublicKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}announced_public_key'], + )!, + publicId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_id'], + )!, + ); + } + + @override + UserDiscoveryAnnouncedUsers createAlias(String alias) { + return UserDiscoveryAnnouncedUsers(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(announced_user_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryAnnouncedUsersData extends DataClass + implements Insertable { + final int announcedUserId; + final i2.Uint8List announcedPublicKey; + final int publicId; + const UserDiscoveryAnnouncedUsersData({ + required this.announcedUserId, + required this.announcedPublicKey, + required this.publicId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['announced_user_id'] = Variable(announcedUserId); + map['announced_public_key'] = Variable(announcedPublicKey); + map['public_id'] = Variable(publicId); + return map; + } + + UserDiscoveryAnnouncedUsersCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: Value(announcedUserId), + announcedPublicKey: Value(announcedPublicKey), + publicId: Value(publicId), + ); + } + + factory UserDiscoveryAnnouncedUsersData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryAnnouncedUsersData( + announcedUserId: serializer.fromJson(json['announcedUserId']), + announcedPublicKey: serializer.fromJson( + json['announcedPublicKey'], + ), + publicId: serializer.fromJson(json['publicId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'announcedUserId': serializer.toJson(announcedUserId), + 'announcedPublicKey': serializer.toJson(announcedPublicKey), + 'publicId': serializer.toJson(publicId), + }; + } + + UserDiscoveryAnnouncedUsersData copyWith({ + int? announcedUserId, + i2.Uint8List? announcedPublicKey, + int? publicId, + }) => UserDiscoveryAnnouncedUsersData( + announcedUserId: announcedUserId ?? this.announcedUserId, + announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, + publicId: publicId ?? this.publicId, + ); + UserDiscoveryAnnouncedUsersData copyWithCompanion( + UserDiscoveryAnnouncedUsersCompanion data, + ) { + return UserDiscoveryAnnouncedUsersData( + announcedUserId: data.announcedUserId.present + ? data.announcedUserId.value + : this.announcedUserId, + announcedPublicKey: data.announcedPublicKey.present + ? data.announcedPublicKey.value + : this.announcedPublicKey, + publicId: data.publicId.present ? data.publicId.value : this.publicId, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryAnnouncedUsersData(') + ..write('announcedUserId: $announcedUserId, ') + ..write('announcedPublicKey: $announcedPublicKey, ') + ..write('publicId: $publicId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + announcedUserId, + $driftBlobEquality.hash(announcedPublicKey), + publicId, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryAnnouncedUsersData && + other.announcedUserId == this.announcedUserId && + $driftBlobEquality.equals( + other.announcedPublicKey, + this.announcedPublicKey, + ) && + other.publicId == this.publicId); +} + +class UserDiscoveryAnnouncedUsersCompanion + extends UpdateCompanion { + final Value announcedUserId; + final Value announcedPublicKey; + final Value publicId; + const UserDiscoveryAnnouncedUsersCompanion({ + this.announcedUserId = const Value.absent(), + this.announcedPublicKey = const Value.absent(), + this.publicId = const Value.absent(), + }); + UserDiscoveryAnnouncedUsersCompanion.insert({ + this.announcedUserId = const Value.absent(), + required i2.Uint8List announcedPublicKey, + required int publicId, + }) : announcedPublicKey = Value(announcedPublicKey), + publicId = Value(publicId); + static Insertable custom({ + Expression? announcedUserId, + Expression? announcedPublicKey, + Expression? publicId, + }) { + return RawValuesInsertable({ + if (announcedUserId != null) 'announced_user_id': announcedUserId, + if (announcedPublicKey != null) + 'announced_public_key': announcedPublicKey, + if (publicId != null) 'public_id': publicId, + }); + } + + UserDiscoveryAnnouncedUsersCompanion copyWith({ + Value? announcedUserId, + Value? announcedPublicKey, + Value? publicId, + }) { + return UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: announcedUserId ?? this.announcedUserId, + announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, + publicId: publicId ?? this.publicId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (announcedUserId.present) { + map['announced_user_id'] = Variable(announcedUserId.value); + } + if (announcedPublicKey.present) { + map['announced_public_key'] = Variable( + announcedPublicKey.value, + ); + } + if (publicId.present) { + map['public_id'] = Variable(publicId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryAnnouncedUsersCompanion(') + ..write('announcedUserId: $announcedUserId, ') + ..write('announcedPublicKey: $announcedPublicKey, ') + ..write('publicId: $publicId') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryUserRelations extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryUserRelations(this.attachedDatabase, [this._alias]); + late final GeneratedColumn announcedUserId = GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES user_discovery_announced_users(announced_user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn fromContactId = GeneratedColumn( + 'from_contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn publicKeyVerifiedTimestamp = + GeneratedColumn( + 'public_key_verified_timestamp', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + announcedUserId, + fromContactId, + publicKeyVerifiedTimestamp, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_user_relations'; + @override + Set get $primaryKey => {announcedUserId, fromContactId}; + @override + UserDiscoveryUserRelationsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryUserRelationsData( + announcedUserId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}announced_user_id'], + )!, + fromContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}from_contact_id'], + )!, + publicKeyVerifiedTimestamp: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_key_verified_timestamp'], + ), + ); + } + + @override + UserDiscoveryUserRelations createAlias(String alias) { + return UserDiscoveryUserRelations(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(announced_user_id, from_contact_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryUserRelationsData extends DataClass + implements Insertable { + final int announcedUserId; + final int fromContactId; + final int? publicKeyVerifiedTimestamp; + const UserDiscoveryUserRelationsData({ + required this.announcedUserId, + required this.fromContactId, + this.publicKeyVerifiedTimestamp, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['announced_user_id'] = Variable(announcedUserId); + map['from_contact_id'] = Variable(fromContactId); + if (!nullToAbsent || publicKeyVerifiedTimestamp != null) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp, + ); + } + return map; + } + + UserDiscoveryUserRelationsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryUserRelationsCompanion( + announcedUserId: Value(announcedUserId), + fromContactId: Value(fromContactId), + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp == null && nullToAbsent + ? const Value.absent() + : Value(publicKeyVerifiedTimestamp), + ); + } + + factory UserDiscoveryUserRelationsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryUserRelationsData( + announcedUserId: serializer.fromJson(json['announcedUserId']), + fromContactId: serializer.fromJson(json['fromContactId']), + publicKeyVerifiedTimestamp: serializer.fromJson( + json['publicKeyVerifiedTimestamp'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'announcedUserId': serializer.toJson(announcedUserId), + 'fromContactId': serializer.toJson(fromContactId), + 'publicKeyVerifiedTimestamp': serializer.toJson( + publicKeyVerifiedTimestamp, + ), + }; + } + + UserDiscoveryUserRelationsData copyWith({ + int? announcedUserId, + int? fromContactId, + Value publicKeyVerifiedTimestamp = const Value.absent(), + }) => UserDiscoveryUserRelationsData( + announcedUserId: announcedUserId ?? this.announcedUserId, + fromContactId: fromContactId ?? this.fromContactId, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp.present + ? publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + UserDiscoveryUserRelationsData copyWithCompanion( + UserDiscoveryUserRelationsCompanion data, + ) { + return UserDiscoveryUserRelationsData( + announcedUserId: data.announcedUserId.present + ? data.announcedUserId.value + : this.announcedUserId, + fromContactId: data.fromContactId.present + ? data.fromContactId.value + : this.fromContactId, + publicKeyVerifiedTimestamp: data.publicKeyVerifiedTimestamp.present + ? data.publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryUserRelationsData(') + ..write('announcedUserId: $announcedUserId, ') + ..write('fromContactId: $fromContactId, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(announcedUserId, fromContactId, publicKeyVerifiedTimestamp); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryUserRelationsData && + other.announcedUserId == this.announcedUserId && + other.fromContactId == this.fromContactId && + other.publicKeyVerifiedTimestamp == this.publicKeyVerifiedTimestamp); +} + +class UserDiscoveryUserRelationsCompanion + extends UpdateCompanion { + final Value announcedUserId; + final Value fromContactId; + final Value publicKeyVerifiedTimestamp; + final Value rowid; + const UserDiscoveryUserRelationsCompanion({ + this.announcedUserId = const Value.absent(), + this.fromContactId = const Value.absent(), + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }); + UserDiscoveryUserRelationsCompanion.insert({ + required int announcedUserId, + required int fromContactId, + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }) : announcedUserId = Value(announcedUserId), + fromContactId = Value(fromContactId); + static Insertable custom({ + Expression? announcedUserId, + Expression? fromContactId, + Expression? publicKeyVerifiedTimestamp, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (announcedUserId != null) 'announced_user_id': announcedUserId, + if (fromContactId != null) 'from_contact_id': fromContactId, + if (publicKeyVerifiedTimestamp != null) + 'public_key_verified_timestamp': publicKeyVerifiedTimestamp, + if (rowid != null) 'rowid': rowid, + }); + } + + UserDiscoveryUserRelationsCompanion copyWith({ + Value? announcedUserId, + Value? fromContactId, + Value? publicKeyVerifiedTimestamp, + Value? rowid, + }) { + return UserDiscoveryUserRelationsCompanion( + announcedUserId: announcedUserId ?? this.announcedUserId, + fromContactId: fromContactId ?? this.fromContactId, + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp ?? this.publicKeyVerifiedTimestamp, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (announcedUserId.present) { + map['announced_user_id'] = Variable(announcedUserId.value); + } + if (fromContactId.present) { + map['from_contact_id'] = Variable(fromContactId.value); + } + if (publicKeyVerifiedTimestamp.present) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp.value, + ); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryUserRelationsCompanion(') + ..write('announcedUserId: $announcedUserId, ') + ..write('fromContactId: $fromContactId, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryOtherPromotions extends Table + with + TableInfo< + UserDiscoveryOtherPromotions, + UserDiscoveryOtherPromotionsData + > { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryOtherPromotions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn fromContactId = GeneratedColumn( + 'from_contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn promotionId = GeneratedColumn( + 'promotion_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicId = GeneratedColumn( + 'public_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn threshold = GeneratedColumn( + 'threshold', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn announcementShare = + GeneratedColumn( + 'announcement_share', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicKeyVerifiedTimestamp = + GeneratedColumn( + 'public_key_verified_timestamp', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + fromContactId, + promotionId, + publicId, + threshold, + announcementShare, + publicKeyVerifiedTimestamp, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_other_promotions'; + @override + Set get $primaryKey => {fromContactId, promotionId}; + @override + UserDiscoveryOtherPromotionsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryOtherPromotionsData( + fromContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}from_contact_id'], + )!, + promotionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}promotion_id'], + )!, + publicId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_id'], + )!, + threshold: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}threshold'], + )!, + announcementShare: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}announcement_share'], + )!, + publicKeyVerifiedTimestamp: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_key_verified_timestamp'], + ), + ); + } + + @override + UserDiscoveryOtherPromotions createAlias(String alias) { + return UserDiscoveryOtherPromotions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(from_contact_id, promotion_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryOtherPromotionsData extends DataClass + implements Insertable { + final int fromContactId; + final int promotionId; + final int publicId; + final int threshold; + final i2.Uint8List announcementShare; + final int? publicKeyVerifiedTimestamp; + const UserDiscoveryOtherPromotionsData({ + required this.fromContactId, + required this.promotionId, + required this.publicId, + required this.threshold, + required this.announcementShare, + this.publicKeyVerifiedTimestamp, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['from_contact_id'] = Variable(fromContactId); + map['promotion_id'] = Variable(promotionId); + map['public_id'] = Variable(publicId); + map['threshold'] = Variable(threshold); + map['announcement_share'] = Variable(announcementShare); + if (!nullToAbsent || publicKeyVerifiedTimestamp != null) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp, + ); + } + return map; + } + + UserDiscoveryOtherPromotionsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryOtherPromotionsCompanion( + fromContactId: Value(fromContactId), + promotionId: Value(promotionId), + publicId: Value(publicId), + threshold: Value(threshold), + announcementShare: Value(announcementShare), + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp == null && nullToAbsent + ? const Value.absent() + : Value(publicKeyVerifiedTimestamp), + ); + } + + factory UserDiscoveryOtherPromotionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryOtherPromotionsData( + fromContactId: serializer.fromJson(json['fromContactId']), + promotionId: serializer.fromJson(json['promotionId']), + publicId: serializer.fromJson(json['publicId']), + threshold: serializer.fromJson(json['threshold']), + announcementShare: serializer.fromJson( + json['announcementShare'], + ), + publicKeyVerifiedTimestamp: serializer.fromJson( + json['publicKeyVerifiedTimestamp'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'fromContactId': serializer.toJson(fromContactId), + 'promotionId': serializer.toJson(promotionId), + 'publicId': serializer.toJson(publicId), + 'threshold': serializer.toJson(threshold), + 'announcementShare': serializer.toJson(announcementShare), + 'publicKeyVerifiedTimestamp': serializer.toJson( + publicKeyVerifiedTimestamp, + ), + }; + } + + UserDiscoveryOtherPromotionsData copyWith({ + int? fromContactId, + int? promotionId, + int? publicId, + int? threshold, + i2.Uint8List? announcementShare, + Value publicKeyVerifiedTimestamp = const Value.absent(), + }) => UserDiscoveryOtherPromotionsData( + fromContactId: fromContactId ?? this.fromContactId, + promotionId: promotionId ?? this.promotionId, + publicId: publicId ?? this.publicId, + threshold: threshold ?? this.threshold, + announcementShare: announcementShare ?? this.announcementShare, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp.present + ? publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + UserDiscoveryOtherPromotionsData copyWithCompanion( + UserDiscoveryOtherPromotionsCompanion data, + ) { + return UserDiscoveryOtherPromotionsData( + fromContactId: data.fromContactId.present + ? data.fromContactId.value + : this.fromContactId, + promotionId: data.promotionId.present + ? data.promotionId.value + : this.promotionId, + publicId: data.publicId.present ? data.publicId.value : this.publicId, + threshold: data.threshold.present ? data.threshold.value : this.threshold, + announcementShare: data.announcementShare.present + ? data.announcementShare.value + : this.announcementShare, + publicKeyVerifiedTimestamp: data.publicKeyVerifiedTimestamp.present + ? data.publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOtherPromotionsData(') + ..write('fromContactId: $fromContactId, ') + ..write('promotionId: $promotionId, ') + ..write('publicId: $publicId, ') + ..write('threshold: $threshold, ') + ..write('announcementShare: $announcementShare, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + fromContactId, + promotionId, + publicId, + threshold, + $driftBlobEquality.hash(announcementShare), + publicKeyVerifiedTimestamp, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryOtherPromotionsData && + other.fromContactId == this.fromContactId && + other.promotionId == this.promotionId && + other.publicId == this.publicId && + other.threshold == this.threshold && + $driftBlobEquality.equals( + other.announcementShare, + this.announcementShare, + ) && + other.publicKeyVerifiedTimestamp == this.publicKeyVerifiedTimestamp); +} + +class UserDiscoveryOtherPromotionsCompanion + extends UpdateCompanion { + final Value fromContactId; + final Value promotionId; + final Value publicId; + final Value threshold; + final Value announcementShare; + final Value publicKeyVerifiedTimestamp; + final Value rowid; + const UserDiscoveryOtherPromotionsCompanion({ + this.fromContactId = const Value.absent(), + this.promotionId = const Value.absent(), + this.publicId = const Value.absent(), + this.threshold = const Value.absent(), + this.announcementShare = const Value.absent(), + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }); + UserDiscoveryOtherPromotionsCompanion.insert({ + required int fromContactId, + required int promotionId, + required int publicId, + required int threshold, + required i2.Uint8List announcementShare, + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }) : fromContactId = Value(fromContactId), + promotionId = Value(promotionId), + publicId = Value(publicId), + threshold = Value(threshold), + announcementShare = Value(announcementShare); + static Insertable custom({ + Expression? fromContactId, + Expression? promotionId, + Expression? publicId, + Expression? threshold, + Expression? announcementShare, + Expression? publicKeyVerifiedTimestamp, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (fromContactId != null) 'from_contact_id': fromContactId, + if (promotionId != null) 'promotion_id': promotionId, + if (publicId != null) 'public_id': publicId, + if (threshold != null) 'threshold': threshold, + if (announcementShare != null) 'announcement_share': announcementShare, + if (publicKeyVerifiedTimestamp != null) + 'public_key_verified_timestamp': publicKeyVerifiedTimestamp, + if (rowid != null) 'rowid': rowid, + }); + } + + UserDiscoveryOtherPromotionsCompanion copyWith({ + Value? fromContactId, + Value? promotionId, + Value? publicId, + Value? threshold, + Value? announcementShare, + Value? publicKeyVerifiedTimestamp, + Value? rowid, + }) { + return UserDiscoveryOtherPromotionsCompanion( + fromContactId: fromContactId ?? this.fromContactId, + promotionId: promotionId ?? this.promotionId, + publicId: publicId ?? this.publicId, + threshold: threshold ?? this.threshold, + announcementShare: announcementShare ?? this.announcementShare, + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp ?? this.publicKeyVerifiedTimestamp, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (fromContactId.present) { + map['from_contact_id'] = Variable(fromContactId.value); + } + if (promotionId.present) { + map['promotion_id'] = Variable(promotionId.value); + } + if (publicId.present) { + map['public_id'] = Variable(publicId.value); + } + if (threshold.present) { + map['threshold'] = Variable(threshold.value); + } + if (announcementShare.present) { + map['announcement_share'] = Variable( + announcementShare.value, + ); + } + if (publicKeyVerifiedTimestamp.present) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp.value, + ); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOtherPromotionsCompanion(') + ..write('fromContactId: $fromContactId, ') + ..write('promotionId: $promotionId, ') + ..write('publicId: $publicId, ') + ..write('threshold: $threshold, ') + ..write('announcementShare: $announcementShare, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryOwnPromotions extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryOwnPromotions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn versionId = GeneratedColumn( + 'version_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn promotion = + GeneratedColumn( + 'promotion', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + @override + List get $columns => [versionId, contactId, promotion]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_own_promotions'; + @override + Set get $primaryKey => {versionId}; + @override + UserDiscoveryOwnPromotionsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryOwnPromotionsData( + versionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}version_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + promotion: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}promotion'], + )!, + ); + } + + @override + UserDiscoveryOwnPromotions createAlias(String alias) { + return UserDiscoveryOwnPromotions(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryOwnPromotionsData extends DataClass + implements Insertable { + final int versionId; + final int contactId; + final i2.Uint8List promotion; + const UserDiscoveryOwnPromotionsData({ + required this.versionId, + required this.contactId, + required this.promotion, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['version_id'] = Variable(versionId); + map['contact_id'] = Variable(contactId); + map['promotion'] = Variable(promotion); + return map; + } + + UserDiscoveryOwnPromotionsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryOwnPromotionsCompanion( + versionId: Value(versionId), + contactId: Value(contactId), + promotion: Value(promotion), + ); + } + + factory UserDiscoveryOwnPromotionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryOwnPromotionsData( + versionId: serializer.fromJson(json['versionId']), + contactId: serializer.fromJson(json['contactId']), + promotion: serializer.fromJson(json['promotion']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'versionId': serializer.toJson(versionId), + 'contactId': serializer.toJson(contactId), + 'promotion': serializer.toJson(promotion), + }; + } + + UserDiscoveryOwnPromotionsData copyWith({ + int? versionId, + int? contactId, + i2.Uint8List? promotion, + }) => UserDiscoveryOwnPromotionsData( + versionId: versionId ?? this.versionId, + contactId: contactId ?? this.contactId, + promotion: promotion ?? this.promotion, + ); + UserDiscoveryOwnPromotionsData copyWithCompanion( + UserDiscoveryOwnPromotionsCompanion data, + ) { + return UserDiscoveryOwnPromotionsData( + versionId: data.versionId.present ? data.versionId.value : this.versionId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + promotion: data.promotion.present ? data.promotion.value : this.promotion, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOwnPromotionsData(') + ..write('versionId: $versionId, ') + ..write('contactId: $contactId, ') + ..write('promotion: $promotion') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(versionId, contactId, $driftBlobEquality.hash(promotion)); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryOwnPromotionsData && + other.versionId == this.versionId && + other.contactId == this.contactId && + $driftBlobEquality.equals(other.promotion, this.promotion)); +} + +class UserDiscoveryOwnPromotionsCompanion + extends UpdateCompanion { + final Value versionId; + final Value contactId; + final Value promotion; + const UserDiscoveryOwnPromotionsCompanion({ + this.versionId = const Value.absent(), + this.contactId = const Value.absent(), + this.promotion = const Value.absent(), + }); + UserDiscoveryOwnPromotionsCompanion.insert({ + this.versionId = const Value.absent(), + required int contactId, + required i2.Uint8List promotion, + }) : contactId = Value(contactId), + promotion = Value(promotion); + static Insertable custom({ + Expression? versionId, + Expression? contactId, + Expression? promotion, + }) { + return RawValuesInsertable({ + if (versionId != null) 'version_id': versionId, + if (contactId != null) 'contact_id': contactId, + if (promotion != null) 'promotion': promotion, + }); + } + + UserDiscoveryOwnPromotionsCompanion copyWith({ + Value? versionId, + Value? contactId, + Value? promotion, + }) { + return UserDiscoveryOwnPromotionsCompanion( + versionId: versionId ?? this.versionId, + contactId: contactId ?? this.contactId, + promotion: promotion ?? this.promotion, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (versionId.present) { + map['version_id'] = Variable(versionId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (promotion.present) { + map['promotion'] = Variable(promotion.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOwnPromotionsCompanion(') + ..write('versionId: $versionId, ') + ..write('contactId: $contactId, ') + ..write('promotion: $promotion') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryShares extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryShares(this.attachedDatabase, [this._alias]); + late final GeneratedColumn shareId = GeneratedColumn( + 'share_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn share = + GeneratedColumn( + 'share', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + @override + List get $columns => [shareId, share, contactId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_shares'; + @override + Set get $primaryKey => {shareId}; + @override + UserDiscoverySharesData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoverySharesData( + shareId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}share_id'], + )!, + share: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}share'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + ); + } + + @override + UserDiscoveryShares createAlias(String alias) { + return UserDiscoveryShares(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoverySharesData extends DataClass + implements Insertable { + final int shareId; + final i2.Uint8List share; + final int? contactId; + const UserDiscoverySharesData({ + required this.shareId, + required this.share, + this.contactId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['share_id'] = Variable(shareId); + map['share'] = Variable(share); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + return map; + } + + UserDiscoverySharesCompanion toCompanion(bool nullToAbsent) { + return UserDiscoverySharesCompanion( + shareId: Value(shareId), + share: Value(share), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + ); + } + + factory UserDiscoverySharesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoverySharesData( + shareId: serializer.fromJson(json['shareId']), + share: serializer.fromJson(json['share']), + contactId: serializer.fromJson(json['contactId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'shareId': serializer.toJson(shareId), + 'share': serializer.toJson(share), + 'contactId': serializer.toJson(contactId), + }; + } + + UserDiscoverySharesData copyWith({ + int? shareId, + i2.Uint8List? share, + Value contactId = const Value.absent(), + }) => UserDiscoverySharesData( + shareId: shareId ?? this.shareId, + share: share ?? this.share, + contactId: contactId.present ? contactId.value : this.contactId, + ); + UserDiscoverySharesData copyWithCompanion(UserDiscoverySharesCompanion data) { + return UserDiscoverySharesData( + shareId: data.shareId.present ? data.shareId.value : this.shareId, + share: data.share.present ? data.share.value : this.share, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoverySharesData(') + ..write('shareId: $shareId, ') + ..write('share: $share, ') + ..write('contactId: $contactId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(shareId, $driftBlobEquality.hash(share), contactId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoverySharesData && + other.shareId == this.shareId && + $driftBlobEquality.equals(other.share, this.share) && + other.contactId == this.contactId); +} + +class UserDiscoverySharesCompanion + extends UpdateCompanion { + final Value shareId; + final Value share; + final Value contactId; + const UserDiscoverySharesCompanion({ + this.shareId = const Value.absent(), + this.share = const Value.absent(), + this.contactId = const Value.absent(), + }); + UserDiscoverySharesCompanion.insert({ + this.shareId = const Value.absent(), + required i2.Uint8List share, + this.contactId = const Value.absent(), + }) : share = Value(share); + static Insertable custom({ + Expression? shareId, + Expression? share, + Expression? contactId, + }) { + return RawValuesInsertable({ + if (shareId != null) 'share_id': shareId, + if (share != null) 'share': share, + if (contactId != null) 'contact_id': contactId, + }); + } + + UserDiscoverySharesCompanion copyWith({ + Value? shareId, + Value? share, + Value? contactId, + }) { + return UserDiscoverySharesCompanion( + shareId: shareId ?? this.shareId, + share: share ?? this.share, + contactId: contactId ?? this.contactId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (shareId.present) { + map['share_id'] = Variable(shareId.value); + } + if (share.present) { + map['share'] = Variable(share.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoverySharesCompanion(') + ..write('shareId: $shareId, ') + ..write('share: $share, ') + ..write('contactId: $contactId') + ..write(')')) + .toString(); + } +} + +class DatabaseAtV13 extends GeneratedDatabase { + DatabaseAtV13(QueryExecutor e) : super(e); + late final Contacts contacts = Contacts(this); + late final Groups groups = Groups(this); + late final MediaFiles mediaFiles = MediaFiles(this); + late final Messages messages = Messages(this); + late final MessageHistories messageHistories = MessageHistories(this); + late final Reactions reactions = Reactions(this); + late final GroupMembers groupMembers = GroupMembers(this); + late final Receipts receipts = Receipts(this); + late final ReceivedReceipts receivedReceipts = ReceivedReceipts(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 MessageActions messageActions = MessageActions(this); + late final GroupHistories groupHistories = GroupHistories(this); + late final KeyVerifications keyVerifications = KeyVerifications(this); + late final VerificationTokens verificationTokens = VerificationTokens(this); + late final UserDiscoveryAnnouncedUsers userDiscoveryAnnouncedUsers = + UserDiscoveryAnnouncedUsers(this); + late final UserDiscoveryUserRelations userDiscoveryUserRelations = + UserDiscoveryUserRelations(this); + late final UserDiscoveryOtherPromotions userDiscoveryOtherPromotions = + UserDiscoveryOtherPromotions(this); + late final UserDiscoveryOwnPromotions userDiscoveryOwnPromotions = + UserDiscoveryOwnPromotions(this); + late final UserDiscoveryShares userDiscoveryShares = UserDiscoveryShares( + this, + ); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + contacts, + groups, + mediaFiles, + messages, + messageHistories, + reactions, + groupMembers, + receipts, + receivedReceipts, + signalIdentityKeyStores, + signalPreKeyStores, + signalSenderKeyStores, + signalSessionStores, + messageActions, + groupHistories, + keyVerifications, + verificationTokens, + userDiscoveryAnnouncedUsers, + userDiscoveryUserRelations, + userDiscoveryOtherPromotions, + userDiscoveryOwnPromotions, + userDiscoveryShares, + ]; + @override + StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules([ + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('messages', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'media_files', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('messages', kind: UpdateKind.update)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('reactions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('reactions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_members', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('receipts', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('receipts', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_actions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_actions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('key_verifications', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'user_discovery_announced_users', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_user_relations', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_user_relations', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_other_promotions', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_own_promotions', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('user_discovery_shares', kind: UpdateKind.delete)], + ), + ]); + @override + int get schemaVersion => 13; +} From 65174736034f59be68e5416a3bd540df49e454ec Mon Sep 17 00:00:00 2001 From: otsmr Date: Sun, 19 Apr 2026 23:10:58 +0200 Subject: [PATCH 14/86] updated protobuf --- .../push_notification.pb.swift | 10 +- ios/Podfile.lock | 31 -- lib/src/model/protobuf/client/backup.proto | 10 +- .../protobuf/client/generated/backup.pb.dart | 9 +- .../client/generated/backup.pbjson.dart | 13 +- .../protobuf/client/generated/groups.pb.dart | 14 +- .../client/generated/groups.pbjson.dart | 28 +- .../client/generated/messages.pb.dart | 282 ++++++++--- .../client/generated/messages.pbjson.dart | 466 ++++++++++-------- .../generated/push_notification.pb.dart | 20 +- .../generated/push_notification.pbenum.dart | 92 ++-- .../generated/push_notification.pbjson.dart | 94 ++-- .../protobuf/client/generated/qr.pb.dart | 2 +- .../protobuf/client/generated/qr.pbenum.dart | 6 +- .../protobuf/client/generated/qr.pbjson.dart | 4 +- lib/src/model/protobuf/client/groups.proto | 24 +- lib/src/model/protobuf/client/messages.proto | 347 ++++++------- .../protobuf/client/push_notification.proto | 67 ++- lib/src/model/protobuf/client/qr.proto | 24 +- lib/src/services/api/messages.dart | 2 +- .../background.notifications.dart | 50 +- .../notifications/pushkeys.notifications.dart | 42 +- lib/src/utils/qr.dart | 4 +- lib/src/views/settings/notification.view.dart | 2 +- 24 files changed, 904 insertions(+), 739 deletions(-) diff --git a/ios/NotificationService/push_notification.pb.swift b/ios/NotificationService/push_notification.pb.swift index 303e2fa5..1f8a210d 100644 --- a/ios/NotificationService/push_notification.pb.swift +++ b/ios/NotificationService/push_notification.pb.swift @@ -230,12 +230,12 @@ struct PushKey: Sendable { // MARK: - Code below here is support for the SwiftProtobuf runtime. extension PushKind: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0reaction\0\u{1}response\0\u{1}text\0\u{1}video\0\u{1}twonly\0\u{1}image\0\u{1}contactRequest\0\u{1}acceptRequest\0\u{1}storedMediaFile\0\u{1}testNotification\0\u{1}reopenedMedia\0\u{1}reactionToVideo\0\u{1}reactionToText\0\u{1}reactionToImage\0\u{1}reactionToAudio\0\u{1}addedToGroup\0\u{1}audio\0") + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0REACTION\0\u{1}RESPONSE\0\u{1}TEXT\0\u{1}VIDEO\0\u{1}TWONLY\0\u{1}IMAGE\0\u{1}CONTACT_REQUEST\0\u{1}ACCEPT_REQUEST\0\u{1}STORED_MEDIA_FILE\0\u{1}TEST_NOTIFICATION\0\u{1}REOPENED_MEDIA\0\u{1}REACTION_TO_VIDEO\0\u{1}REACTION_TO_TEXT\0\u{1}REACTION_TO_IMAGE\0\u{1}REACTION_TO_AUDIO\0\u{1}ADDED_TO_GROUP\0\u{1}AUDIO\0") } extension EncryptedPushNotification: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = "EncryptedPushNotification" - static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}keyId\0\u{1}nonce\0\u{1}ciphertext\0\u{1}mac\0") + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}key_id\0\u{1}nonce\0\u{1}ciphertext\0\u{1}mac\0") mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -280,7 +280,7 @@ extension EncryptedPushNotification: SwiftProtobuf.Message, SwiftProtobuf._Messa extension PushNotification: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = "PushNotification" - static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}kind\0\u{1}messageId\0\u{1}additionalContent\0") + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}kind\0\u{3}message_id\0\u{3}additional_content\0") mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -354,7 +354,7 @@ extension PushUsers: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation extension PushUser: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = "PushUser" - static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}userId\0\u{1}displayName\0\u{1}blocked\0\u{1}lastMessageId\0\u{1}pushKeys\0") + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}user_id\0\u{3}display_name\0\u{1}blocked\0\u{3}last_message_id\0\u{3}push_keys\0") mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -408,7 +408,7 @@ extension PushUser: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB extension PushKey: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = "PushKey" - static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}id\0\u{1}key\0\u{1}createdAtUnixTimestamp\0") + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}id\0\u{1}key\0\u{3}created_at_unix_timestamp\0") mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a09dc56e..a37444d4 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -308,31 +308,6 @@ PODS: - sqflite_darwin (0.0.4): - Flutter - FlutterMacOS - - sqlite3 (3.52.0): - - sqlite3/common (= 3.52.0) - - sqlite3/common (3.52.0) - - sqlite3/dbstatvtab (3.52.0): - - sqlite3/common - - sqlite3/fts5 (3.52.0): - - sqlite3/common - - sqlite3/math (3.52.0): - - sqlite3/common - - sqlite3/perf-threadsafe (3.52.0): - - sqlite3/common - - sqlite3/rtree (3.52.0): - - sqlite3/common - - sqlite3/session (3.52.0): - - sqlite3/common - - sqlite3_flutter_libs (0.0.1): - - Flutter - - FlutterMacOS - - sqlite3 (~> 3.52.0) - - sqlite3/dbstatvtab - - sqlite3/fts5 - - sqlite3/math - - sqlite3/perf-threadsafe - - sqlite3/rtree - - sqlite3/session - SwiftProtobuf (1.36.1) - SwiftyGif (5.4.5) - url_launcher_ios (0.0.1): @@ -386,7 +361,6 @@ DEPENDENCIES: - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`) - SwiftProtobuf - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) @@ -421,7 +395,6 @@ SPEC REPOS: - SDWebImage - SDWebImageWebPCoder - Sentry - - sqlite3 - SwiftProtobuf - SwiftyGif @@ -500,8 +473,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" sqflite_darwin: :path: ".symlinks/plugins/sqflite_darwin/darwin" - sqlite3_flutter_libs: - :path: ".symlinks/plugins/sqlite3_flutter_libs/darwin" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" video_player_avfoundation: @@ -574,8 +545,6 @@ SPEC CHECKSUMS: share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 - sqlite3: a51c07cf16e023d6c48abd5e5791a61a47354921 - sqlite3_flutter_libs: b3e120efe9a82017e5552a620f696589ed4f62ab SwiftProtobuf: 9e106a71456f4d3f6a3b0c8fd87ef0be085efc38 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b diff --git a/lib/src/model/protobuf/client/backup.proto b/lib/src/model/protobuf/client/backup.proto index 0a09bfd3..e3fa952c 100644 --- a/lib/src/model/protobuf/client/backup.proto +++ b/lib/src/model/protobuf/client/backup.proto @@ -1,12 +1,12 @@ syntax = "proto3"; message TwonlySafeBackupContent { - string secureStorageJson = 1; - bytes twonlyDatabase = 2; + string secure_storage_json = 1; + bytes twonly_database = 2; } message TwonlySafeBackupEncrypted { - bytes mac = 1; - bytes nonce = 2; - bytes cipherText = 3; + bytes mac = 1; + bytes nonce = 2; + bytes cipher_text = 3; } \ No newline at end of file diff --git a/lib/src/model/protobuf/client/generated/backup.pb.dart b/lib/src/model/protobuf/client/generated/backup.pb.dart index 7f8b1140..b623f4ba 100644 --- a/lib/src/model/protobuf/client/generated/backup.pb.dart +++ b/lib/src/model/protobuf/client/generated/backup.pb.dart @@ -39,11 +39,9 @@ class TwonlySafeBackupContent extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( _omitMessageNames ? '' : 'TwonlySafeBackupContent', createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'secureStorageJson', - protoName: 'secureStorageJson') + ..aOS(1, _omitFieldNames ? '' : 'secureStorageJson') ..a<$core.List<$core.int>>( - 2, _omitFieldNames ? '' : 'twonlyDatabase', $pb.PbFieldType.OY, - protoName: 'twonlyDatabase') + 2, _omitFieldNames ? '' : 'twonlyDatabase', $pb.PbFieldType.OY) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -118,8 +116,7 @@ class TwonlySafeBackupEncrypted extends $pb.GeneratedMessage { ..a<$core.List<$core.int>>( 2, _omitFieldNames ? '' : 'nonce', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>( - 3, _omitFieldNames ? '' : 'cipherText', $pb.PbFieldType.OY, - protoName: 'cipherText') + 3, _omitFieldNames ? '' : 'cipherText', $pb.PbFieldType.OY) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') diff --git a/lib/src/model/protobuf/client/generated/backup.pbjson.dart b/lib/src/model/protobuf/client/generated/backup.pbjson.dart index d084021e..e121806b 100644 --- a/lib/src/model/protobuf/client/generated/backup.pbjson.dart +++ b/lib/src/model/protobuf/client/generated/backup.pbjson.dart @@ -19,20 +19,21 @@ const TwonlySafeBackupContent$json = { '1': 'TwonlySafeBackupContent', '2': [ { - '1': 'secureStorageJson', + '1': 'secure_storage_json', '3': 1, '4': 1, '5': 9, '10': 'secureStorageJson' }, - {'1': 'twonlyDatabase', '3': 2, '4': 1, '5': 12, '10': 'twonlyDatabase'}, + {'1': 'twonly_database', '3': 2, '4': 1, '5': 12, '10': 'twonlyDatabase'}, ], }; /// Descriptor for `TwonlySafeBackupContent`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List twonlySafeBackupContentDescriptor = $convert.base64Decode( - 'ChdUd29ubHlTYWZlQmFja3VwQ29udGVudBIsChFzZWN1cmVTdG9yYWdlSnNvbhgBIAEoCVIRc2' - 'VjdXJlU3RvcmFnZUpzb24SJgoOdHdvbmx5RGF0YWJhc2UYAiABKAxSDnR3b25seURhdGFiYXNl'); + 'ChdUd29ubHlTYWZlQmFja3VwQ29udGVudBIuChNzZWN1cmVfc3RvcmFnZV9qc29uGAEgASgJUh' + 'FzZWN1cmVTdG9yYWdlSnNvbhInCg90d29ubHlfZGF0YWJhc2UYAiABKAxSDnR3b25seURhdGFi' + 'YXNl'); @$core.Deprecated('Use twonlySafeBackupEncryptedDescriptor instead') const TwonlySafeBackupEncrypted$json = { @@ -40,7 +41,7 @@ const TwonlySafeBackupEncrypted$json = { '2': [ {'1': 'mac', '3': 1, '4': 1, '5': 12, '10': 'mac'}, {'1': 'nonce', '3': 2, '4': 1, '5': 12, '10': 'nonce'}, - {'1': 'cipherText', '3': 3, '4': 1, '5': 12, '10': 'cipherText'}, + {'1': 'cipher_text', '3': 3, '4': 1, '5': 12, '10': 'cipherText'}, ], }; @@ -48,4 +49,4 @@ const TwonlySafeBackupEncrypted$json = { final $typed_data.Uint8List twonlySafeBackupEncryptedDescriptor = $convert.base64Decode( 'ChlUd29ubHlTYWZlQmFja3VwRW5jcnlwdGVkEhAKA21hYxgBIAEoDFIDbWFjEhQKBW5vbmNlGA' - 'IgASgMUgVub25jZRIeCgpjaXBoZXJUZXh0GAMgASgMUgpjaXBoZXJUZXh0'); + 'IgASgMUgVub25jZRIfCgtjaXBoZXJfdGV4dBgDIAEoDFIKY2lwaGVyVGV4dA=='); diff --git a/lib/src/model/protobuf/client/generated/groups.pb.dart b/lib/src/model/protobuf/client/generated/groups.pb.dart index 96883f47..71fcac5e 100644 --- a/lib/src/model/protobuf/client/generated/groups.pb.dart +++ b/lib/src/model/protobuf/client/generated/groups.pb.dart @@ -53,13 +53,10 @@ class EncryptedGroupState extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'EncryptedGroupState', createEmptyInstance: create) ..p<$fixnum.Int64>( - 1, _omitFieldNames ? '' : 'memberIds', $pb.PbFieldType.K6, - protoName: 'memberIds') - ..p<$fixnum.Int64>(2, _omitFieldNames ? '' : 'adminIds', $pb.PbFieldType.K6, - protoName: 'adminIds') - ..aOS(3, _omitFieldNames ? '' : 'groupName', protoName: 'groupName') - ..aInt64(4, _omitFieldNames ? '' : 'deleteMessagesAfterMilliseconds', - protoName: 'deleteMessagesAfterMilliseconds') + 1, _omitFieldNames ? '' : 'memberIds', $pb.PbFieldType.K6) + ..p<$fixnum.Int64>(2, _omitFieldNames ? '' : 'adminIds', $pb.PbFieldType.K6) + ..aOS(3, _omitFieldNames ? '' : 'groupName') + ..aInt64(4, _omitFieldNames ? '' : 'deleteMessagesAfterMilliseconds') ..a<$core.List<$core.int>>( 5, _omitFieldNames ? '' : 'padding', $pb.PbFieldType.OY) ..hasRequiredFields = false; @@ -212,8 +209,7 @@ class EncryptedGroupStateEnvelop extends $pb.GeneratedMessage { ..a<$core.List<$core.int>>( 1, _omitFieldNames ? '' : 'nonce', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>( - 2, _omitFieldNames ? '' : 'encryptedGroupState', $pb.PbFieldType.OY, - protoName: 'encryptedGroupState') + 2, _omitFieldNames ? '' : 'encryptedGroupState', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>( 3, _omitFieldNames ? '' : 'mac', $pb.PbFieldType.OY) ..hasRequiredFields = false; diff --git a/lib/src/model/protobuf/client/generated/groups.pbjson.dart b/lib/src/model/protobuf/client/generated/groups.pbjson.dart index 7fa61ef1..6d96647c 100644 --- a/lib/src/model/protobuf/client/generated/groups.pbjson.dart +++ b/lib/src/model/protobuf/client/generated/groups.pbjson.dart @@ -18,11 +18,11 @@ import 'dart:typed_data' as $typed_data; const EncryptedGroupState$json = { '1': 'EncryptedGroupState', '2': [ - {'1': 'memberIds', '3': 1, '4': 3, '5': 3, '10': 'memberIds'}, - {'1': 'adminIds', '3': 2, '4': 3, '5': 3, '10': 'adminIds'}, - {'1': 'groupName', '3': 3, '4': 1, '5': 9, '10': 'groupName'}, + {'1': 'member_ids', '3': 1, '4': 3, '5': 3, '10': 'memberIds'}, + {'1': 'admin_ids', '3': 2, '4': 3, '5': 3, '10': 'adminIds'}, + {'1': 'group_name', '3': 3, '4': 1, '5': 9, '10': 'groupName'}, { - '1': 'deleteMessagesAfterMilliseconds', + '1': 'delete_messages_after_milliseconds', '3': 4, '4': 1, '5': 3, @@ -33,17 +33,17 @@ const EncryptedGroupState$json = { {'1': 'padding', '3': 5, '4': 1, '5': 12, '10': 'padding'}, ], '8': [ - {'1': '_deleteMessagesAfterMilliseconds'}, + {'1': '_delete_messages_after_milliseconds'}, ], }; /// Descriptor for `EncryptedGroupState`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List encryptedGroupStateDescriptor = $convert.base64Decode( - 'ChNFbmNyeXB0ZWRHcm91cFN0YXRlEhwKCW1lbWJlcklkcxgBIAMoA1IJbWVtYmVySWRzEhoKCG' - 'FkbWluSWRzGAIgAygDUghhZG1pbklkcxIcCglncm91cE5hbWUYAyABKAlSCWdyb3VwTmFtZRJN' - 'Ch9kZWxldGVNZXNzYWdlc0FmdGVyTWlsbGlzZWNvbmRzGAQgASgDSABSH2RlbGV0ZU1lc3NhZ2' - 'VzQWZ0ZXJNaWxsaXNlY29uZHOIAQESGAoHcGFkZGluZxgFIAEoDFIHcGFkZGluZ0IiCiBfZGVs' - 'ZXRlTWVzc2FnZXNBZnRlck1pbGxpc2Vjb25kcw=='); + 'ChNFbmNyeXB0ZWRHcm91cFN0YXRlEh0KCm1lbWJlcl9pZHMYASADKANSCW1lbWJlcklkcxIbCg' + 'lhZG1pbl9pZHMYAiADKANSCGFkbWluSWRzEh0KCmdyb3VwX25hbWUYAyABKAlSCWdyb3VwTmFt' + 'ZRJQCiJkZWxldGVfbWVzc2FnZXNfYWZ0ZXJfbWlsbGlzZWNvbmRzGAQgASgDSABSH2RlbGV0ZU' + '1lc3NhZ2VzQWZ0ZXJNaWxsaXNlY29uZHOIAQESGAoHcGFkZGluZxgFIAEoDFIHcGFkZGluZ0Il' + 'CiNfZGVsZXRlX21lc3NhZ2VzX2FmdGVyX21pbGxpc2Vjb25kcw=='); @$core.Deprecated('Use encryptedAppendedGroupStateDescriptor instead') const EncryptedAppendedGroupState$json = { @@ -81,7 +81,7 @@ const EncryptedGroupStateEnvelop$json = { '2': [ {'1': 'nonce', '3': 1, '4': 1, '5': 12, '10': 'nonce'}, { - '1': 'encryptedGroupState', + '1': 'encrypted_group_state', '3': 2, '4': 1, '5': 12, @@ -94,6 +94,6 @@ const EncryptedGroupStateEnvelop$json = { /// Descriptor for `EncryptedGroupStateEnvelop`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List encryptedGroupStateEnvelopDescriptor = $convert.base64Decode( - 'ChpFbmNyeXB0ZWRHcm91cFN0YXRlRW52ZWxvcBIUCgVub25jZRgBIAEoDFIFbm9uY2USMAoTZW' - '5jcnlwdGVkR3JvdXBTdGF0ZRgCIAEoDFITZW5jcnlwdGVkR3JvdXBTdGF0ZRIQCgNtYWMYAyAB' - 'KAxSA21hYw=='); + 'ChpFbmNyeXB0ZWRHcm91cFN0YXRlRW52ZWxvcBIUCgVub25jZRgBIAEoDFIFbm9uY2USMgoVZW' + '5jcnlwdGVkX2dyb3VwX3N0YXRlGAIgASgMUhNlbmNyeXB0ZWRHcm91cFN0YXRlEhAKA21hYxgD' + 'IAEoDFIDbWFj'); diff --git a/lib/src/model/protobuf/client/generated/messages.pb.dart b/lib/src/model/protobuf/client/generated/messages.pb.dart index e14d7101..dea973ea 100644 --- a/lib/src/model/protobuf/client/generated/messages.pb.dart +++ b/lib/src/model/protobuf/client/generated/messages.pb.dart @@ -52,12 +52,11 @@ class Message extends $pb.GeneratedMessage { defaultOrMaker: Message_Type.SENDER_DELIVERY_RECEIPT, valueOf: Message_Type.valueOf, enumValues: Message_Type.values) - ..aOS(2, _omitFieldNames ? '' : 'receiptId', protoName: 'receiptId') + ..aOS(2, _omitFieldNames ? '' : 'receiptId') ..a<$core.List<$core.int>>( - 3, _omitFieldNames ? '' : 'encryptedContent', $pb.PbFieldType.OY, - protoName: 'encryptedContent') + 3, _omitFieldNames ? '' : 'encryptedContent', $pb.PbFieldType.OY) ..aOM(4, _omitFieldNames ? '' : 'plaintextContent', - protoName: 'plaintextContent', subBuilder: PlaintextContent.create) + subBuilder: PlaintextContent.create) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -255,11 +254,9 @@ class PlaintextContent extends $pb.GeneratedMessage { createEmptyInstance: create) ..aOM( 1, _omitFieldNames ? '' : 'decryptionErrorMessage', - protoName: 'decryptionErrorMessage', subBuilder: PlaintextContent_DecryptionErrorMessage.create) ..aOM( 2, _omitFieldNames ? '' : 'retryControlError', - protoName: 'retryControlError', subBuilder: PlaintextContent_RetryErrorMessage.create) ..hasRequiredFields = false; @@ -411,11 +408,9 @@ class EncryptedContent_GroupCreate extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'EncryptedContent.GroupCreate', createEmptyInstance: create) ..a<$core.List<$core.int>>( - 3, _omitFieldNames ? '' : 'stateKey', $pb.PbFieldType.OY, - protoName: 'stateKey') + 3, _omitFieldNames ? '' : 'stateKey', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>( - 4, _omitFieldNames ? '' : 'groupPublicKey', $pb.PbFieldType.OY, - protoName: 'groupPublicKey') + 4, _omitFieldNames ? '' : 'groupPublicKey', $pb.PbFieldType.OY) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -485,8 +480,7 @@ class EncryptedContent_GroupJoin extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'EncryptedContent.GroupJoin', createEmptyInstance: create) ..a<$core.List<$core.int>>( - 1, _omitFieldNames ? '' : 'groupPublicKey', $pb.PbFieldType.OY, - protoName: 'groupPublicKey') + 1, _omitFieldNames ? '' : 'groupPublicKey', $pb.PbFieldType.OY) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -598,13 +592,10 @@ class EncryptedContent_GroupUpdate extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( _omitMessageNames ? '' : 'EncryptedContent.GroupUpdate', createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'groupActionType', - protoName: 'groupActionType') - ..aInt64(2, _omitFieldNames ? '' : 'affectedContactId', - protoName: 'affectedContactId') - ..aOS(3, _omitFieldNames ? '' : 'newGroupName', protoName: 'newGroupName') - ..aInt64(4, _omitFieldNames ? '' : 'newDeleteMessagesAfterMilliseconds', - protoName: 'newDeleteMessagesAfterMilliseconds') + ..aOS(1, _omitFieldNames ? '' : 'groupActionType') + ..aInt64(2, _omitFieldNames ? '' : 'affectedContactId') + ..aOS(3, _omitFieldNames ? '' : 'newGroupName') + ..aInt64(4, _omitFieldNames ? '' : 'newDeleteMessagesAfterMilliseconds') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -697,12 +688,10 @@ class EncryptedContent_TextMessage extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( _omitMessageNames ? '' : 'EncryptedContent.TextMessage', createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'senderMessageId', - protoName: 'senderMessageId') + ..aOS(1, _omitFieldNames ? '' : 'senderMessageId') ..aOS(2, _omitFieldNames ? '' : 'text') ..aInt64(3, _omitFieldNames ? '' : 'timestamp') - ..aOS(4, _omitFieldNames ? '' : 'quoteMessageId', - protoName: 'quoteMessageId') + ..aOS(4, _omitFieldNames ? '' : 'quoteMessageId') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -892,8 +881,7 @@ class EncryptedContent_Reaction extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( _omitMessageNames ? '' : 'EncryptedContent.Reaction', createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'targetMessageId', - protoName: 'targetMessageId') + ..aOS(1, _omitFieldNames ? '' : 'targetMessageId') ..aOS(2, _omitFieldNames ? '' : 'emoji') ..aOB(3, _omitFieldNames ? '' : 'remove') ..hasRequiredFields = false; @@ -984,10 +972,8 @@ class EncryptedContent_MessageUpdate extends $pb.GeneratedMessage { defaultOrMaker: EncryptedContent_MessageUpdate_Type.DELETE, valueOf: EncryptedContent_MessageUpdate_Type.valueOf, enumValues: EncryptedContent_MessageUpdate_Type.values) - ..aOS(2, _omitFieldNames ? '' : 'senderMessageId', - protoName: 'senderMessageId') - ..pPS(3, _omitFieldNames ? '' : 'multipleTargetMessageIds', - protoName: 'multipleTargetMessageIds') + ..aOS(2, _omitFieldNames ? '' : 'senderMessageId') + ..pPS(3, _omitFieldNames ? '' : 'multipleTargetMessageIds') ..aOS(4, _omitFieldNames ? '' : 'text') ..aInt64(5, _omitFieldNames ? '' : 'timestamp') ..hasRequiredFields = false; @@ -1101,32 +1087,24 @@ class EncryptedContent_Media extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( _omitMessageNames ? '' : 'EncryptedContent.Media', createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'senderMessageId', - protoName: 'senderMessageId') + ..aOS(1, _omitFieldNames ? '' : 'senderMessageId') ..e( 2, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, defaultOrMaker: EncryptedContent_Media_Type.REUPLOAD, valueOf: EncryptedContent_Media_Type.valueOf, enumValues: EncryptedContent_Media_Type.values) - ..aInt64(3, _omitFieldNames ? '' : 'displayLimitInMilliseconds', - protoName: 'displayLimitInMilliseconds') - ..aOB(4, _omitFieldNames ? '' : 'requiresAuthentication', - protoName: 'requiresAuthentication') + ..aInt64(3, _omitFieldNames ? '' : 'displayLimitInMilliseconds') + ..aOB(4, _omitFieldNames ? '' : 'requiresAuthentication') ..aInt64(5, _omitFieldNames ? '' : 'timestamp') - ..aOS(6, _omitFieldNames ? '' : 'quoteMessageId', - protoName: 'quoteMessageId') + ..aOS(6, _omitFieldNames ? '' : 'quoteMessageId') ..a<$core.List<$core.int>>( - 7, _omitFieldNames ? '' : 'downloadToken', $pb.PbFieldType.OY, - protoName: 'downloadToken') + 7, _omitFieldNames ? '' : 'downloadToken', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>( - 8, _omitFieldNames ? '' : 'encryptionKey', $pb.PbFieldType.OY, - protoName: 'encryptionKey') + 8, _omitFieldNames ? '' : 'encryptionKey', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>( - 9, _omitFieldNames ? '' : 'encryptionMac', $pb.PbFieldType.OY, - protoName: 'encryptionMac') + 9, _omitFieldNames ? '' : 'encryptionMac', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>( - 10, _omitFieldNames ? '' : 'encryptionNonce', $pb.PbFieldType.OY, - protoName: 'encryptionNonce') + 10, _omitFieldNames ? '' : 'encryptionNonce', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>( 11, _omitFieldNames ? '' : 'additionalMessageData', $pb.PbFieldType.OY) ..hasRequiredFields = false; @@ -1283,8 +1261,7 @@ class EncryptedContent_MediaUpdate extends $pb.GeneratedMessage { defaultOrMaker: EncryptedContent_MediaUpdate_Type.REOPENED, valueOf: EncryptedContent_MediaUpdate_Type.valueOf, enumValues: EncryptedContent_MediaUpdate_Type.values) - ..aOS(2, _omitFieldNames ? '' : 'targetMessageId', - protoName: 'targetMessageId') + ..aOS(2, _omitFieldNames ? '' : 'targetMessageId') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -1429,10 +1406,9 @@ class EncryptedContent_ContactUpdate extends $pb.GeneratedMessage { valueOf: EncryptedContent_ContactUpdate_Type.valueOf, enumValues: EncryptedContent_ContactUpdate_Type.values) ..a<$core.List<$core.int>>( - 2, _omitFieldNames ? '' : 'avatarSvgCompressed', $pb.PbFieldType.OY, - protoName: 'avatarSvgCompressed') + 2, _omitFieldNames ? '' : 'avatarSvgCompressed', $pb.PbFieldType.OY) ..aOS(3, _omitFieldNames ? '' : 'username') - ..aOS(4, _omitFieldNames ? '' : 'displayName', protoName: 'displayName') + ..aOS(4, _omitFieldNames ? '' : 'displayName') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -1529,10 +1505,10 @@ class EncryptedContent_PushKeys extends $pb.GeneratedMessage { defaultOrMaker: EncryptedContent_PushKeys_Type.REQUEST, valueOf: EncryptedContent_PushKeys_Type.valueOf, enumValues: EncryptedContent_PushKeys_Type.values) - ..aInt64(2, _omitFieldNames ? '' : 'keyId', protoName: 'keyId') + ..aInt64(2, _omitFieldNames ? '' : 'keyId') ..a<$core.List<$core.int>>( 3, _omitFieldNames ? '' : 'key', $pb.PbFieldType.OY) - ..aInt64(4, _omitFieldNames ? '' : 'createdAt', protoName: 'createdAt') + ..aInt64(4, _omitFieldNames ? '' : 'createdAt') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -1623,12 +1599,10 @@ class EncryptedContent_FlameSync extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( _omitMessageNames ? '' : 'EncryptedContent.FlameSync', createEmptyInstance: create) - ..aInt64(1, _omitFieldNames ? '' : 'flameCounter', - protoName: 'flameCounter') - ..aInt64(2, _omitFieldNames ? '' : 'lastFlameCounterChange', - protoName: 'lastFlameCounterChange') - ..aOB(3, _omitFieldNames ? '' : 'bestFriend', protoName: 'bestFriend') - ..aOB(4, _omitFieldNames ? '' : 'forceUpdate', protoName: 'forceUpdate') + ..aInt64(1, _omitFieldNames ? '' : 'flameCounter') + ..aInt64(2, _omitFieldNames ? '' : 'lastFlameCounterChange') + ..aOB(3, _omitFieldNames ? '' : 'bestFriend') + ..aOB(4, _omitFieldNames ? '' : 'forceUpdate') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -1765,6 +1739,124 @@ class EncryptedContent_TypingIndicator extends $pb.GeneratedMessage { void clearCreatedAt() => $_clearField(2); } +class EncryptedContent_UserDiscoveryRequest extends $pb.GeneratedMessage { + factory EncryptedContent_UserDiscoveryRequest({ + $core.List<$core.int>? currentVersion, + }) { + final result = create(); + if (currentVersion != null) result.currentVersion = currentVersion; + return result; + } + + EncryptedContent_UserDiscoveryRequest._(); + + factory EncryptedContent_UserDiscoveryRequest.fromBuffer( + $core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory EncryptedContent_UserDiscoveryRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'EncryptedContent.UserDiscoveryRequest', + createEmptyInstance: create) + ..a<$core.List<$core.int>>( + 1, _omitFieldNames ? '' : 'currentVersion', $pb.PbFieldType.OY) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + EncryptedContent_UserDiscoveryRequest clone() => + EncryptedContent_UserDiscoveryRequest()..mergeFromMessage(this); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + EncryptedContent_UserDiscoveryRequest copyWith( + void Function(EncryptedContent_UserDiscoveryRequest) updates) => + super.copyWith((message) => + updates(message as EncryptedContent_UserDiscoveryRequest)) + as EncryptedContent_UserDiscoveryRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static EncryptedContent_UserDiscoveryRequest create() => + EncryptedContent_UserDiscoveryRequest._(); + @$core.override + EncryptedContent_UserDiscoveryRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => + $pb.PbList(); + @$core.pragma('dart2js:noInline') + static EncryptedContent_UserDiscoveryRequest getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor< + EncryptedContent_UserDiscoveryRequest>(create); + static EncryptedContent_UserDiscoveryRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.List<$core.int> get currentVersion => $_getN(0); + @$pb.TagNumber(1) + set currentVersion($core.List<$core.int> value) => $_setBytes(0, value); + @$pb.TagNumber(1) + $core.bool hasCurrentVersion() => $_has(0); + @$pb.TagNumber(1) + void clearCurrentVersion() => $_clearField(1); +} + +class EncryptedContent_UserDiscoveryUpdate extends $pb.GeneratedMessage { + factory EncryptedContent_UserDiscoveryUpdate({ + $core.Iterable<$core.List<$core.int>>? messages, + }) { + final result = create(); + if (messages != null) result.messages.addAll(messages); + return result; + } + + EncryptedContent_UserDiscoveryUpdate._(); + + factory EncryptedContent_UserDiscoveryUpdate.fromBuffer( + $core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory EncryptedContent_UserDiscoveryUpdate.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'EncryptedContent.UserDiscoveryUpdate', + createEmptyInstance: create) + ..p<$core.List<$core.int>>( + 1, _omitFieldNames ? '' : 'messages', $pb.PbFieldType.PY) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + EncryptedContent_UserDiscoveryUpdate clone() => + EncryptedContent_UserDiscoveryUpdate()..mergeFromMessage(this); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + EncryptedContent_UserDiscoveryUpdate copyWith( + void Function(EncryptedContent_UserDiscoveryUpdate) updates) => + super.copyWith((message) => + updates(message as EncryptedContent_UserDiscoveryUpdate)) + as EncryptedContent_UserDiscoveryUpdate; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static EncryptedContent_UserDiscoveryUpdate create() => + EncryptedContent_UserDiscoveryUpdate._(); + @$core.override + EncryptedContent_UserDiscoveryUpdate createEmptyInstance() => create(); + static $pb.PbList createRepeated() => + $pb.PbList(); + @$core.pragma('dart2js:noInline') + static EncryptedContent_UserDiscoveryUpdate getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor< + EncryptedContent_UserDiscoveryUpdate>(create); + static EncryptedContent_UserDiscoveryUpdate? _defaultInstance; + + @$pb.TagNumber(1) + $pb.PbList<$core.List<$core.int>> get messages => $_getList(0); +} + class EncryptedContent extends $pb.GeneratedMessage { factory EncryptedContent({ $core.String? groupId, @@ -1786,6 +1878,9 @@ class EncryptedContent extends $pb.GeneratedMessage { EncryptedContent_ErrorMessages? errorMessages, EncryptedContent_AdditionalDataMessage? additionalDataMessage, EncryptedContent_TypingIndicator? typingIndicator, + $core.List<$core.int>? senderUserDiscoveryVersion, + EncryptedContent_UserDiscoveryRequest? userDiscoveryRequest, + EncryptedContent_UserDiscoveryUpdate? userDiscoveryUpdate, }) { final result = create(); if (groupId != null) result.groupId = groupId; @@ -1810,6 +1905,12 @@ class EncryptedContent extends $pb.GeneratedMessage { if (additionalDataMessage != null) result.additionalDataMessage = additionalDataMessage; if (typingIndicator != null) result.typingIndicator = typingIndicator; + if (senderUserDiscoveryVersion != null) + result.senderUserDiscoveryVersion = senderUserDiscoveryVersion; + if (userDiscoveryRequest != null) + result.userDiscoveryRequest = userDiscoveryRequest; + if (userDiscoveryUpdate != null) + result.userDiscoveryUpdate = userDiscoveryUpdate; return result; } @@ -1825,50 +1926,41 @@ class EncryptedContent extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( _omitMessageNames ? '' : 'EncryptedContent', createEmptyInstance: create) - ..aOS(2, _omitFieldNames ? '' : 'groupId', protoName: 'groupId') - ..aOB(3, _omitFieldNames ? '' : 'isDirectChat', protoName: 'isDirectChat') - ..aInt64(4, _omitFieldNames ? '' : 'senderProfileCounter', - protoName: 'senderProfileCounter') + ..aOS(2, _omitFieldNames ? '' : 'groupId') + ..aOB(3, _omitFieldNames ? '' : 'isDirectChat') + ..aInt64(4, _omitFieldNames ? '' : 'senderProfileCounter') ..aOM( 5, _omitFieldNames ? '' : 'messageUpdate', - protoName: 'messageUpdate', subBuilder: EncryptedContent_MessageUpdate.create) ..aOM(6, _omitFieldNames ? '' : 'media', subBuilder: EncryptedContent_Media.create) ..aOM(7, _omitFieldNames ? '' : 'mediaUpdate', - protoName: 'mediaUpdate', subBuilder: EncryptedContent_MediaUpdate.create) ..aOM( 8, _omitFieldNames ? '' : 'contactUpdate', - protoName: 'contactUpdate', subBuilder: EncryptedContent_ContactUpdate.create) ..aOM( 9, _omitFieldNames ? '' : 'contactRequest', - protoName: 'contactRequest', subBuilder: EncryptedContent_ContactRequest.create) ..aOM(10, _omitFieldNames ? '' : 'flameSync', - protoName: 'flameSync', subBuilder: EncryptedContent_FlameSync.create) + subBuilder: EncryptedContent_FlameSync.create) ..aOM(11, _omitFieldNames ? '' : 'pushKeys', - protoName: 'pushKeys', subBuilder: EncryptedContent_PushKeys.create) + subBuilder: EncryptedContent_PushKeys.create) ..aOM(12, _omitFieldNames ? '' : 'reaction', subBuilder: EncryptedContent_Reaction.create) ..aOM( 13, _omitFieldNames ? '' : 'textMessage', - protoName: 'textMessage', subBuilder: EncryptedContent_TextMessage.create) ..aOM( 14, _omitFieldNames ? '' : 'groupCreate', - protoName: 'groupCreate', subBuilder: EncryptedContent_GroupCreate.create) ..aOM(15, _omitFieldNames ? '' : 'groupJoin', - protoName: 'groupJoin', subBuilder: EncryptedContent_GroupJoin.create) + subBuilder: EncryptedContent_GroupJoin.create) ..aOM( 16, _omitFieldNames ? '' : 'groupUpdate', - protoName: 'groupUpdate', subBuilder: EncryptedContent_GroupUpdate.create) ..aOM( 17, _omitFieldNames ? '' : 'resendGroupPublicKey', - protoName: 'resendGroupPublicKey', subBuilder: EncryptedContent_ResendGroupPublicKey.create) ..aOM( 18, _omitFieldNames ? '' : 'errorMessages', @@ -1879,6 +1971,14 @@ class EncryptedContent extends $pb.GeneratedMessage { ..aOM( 20, _omitFieldNames ? '' : 'typingIndicator', subBuilder: EncryptedContent_TypingIndicator.create) + ..a<$core.List<$core.int>>(21, + _omitFieldNames ? '' : 'senderUserDiscoveryVersion', $pb.PbFieldType.OY) + ..aOM( + 22, _omitFieldNames ? '' : 'userDiscoveryRequest', + subBuilder: EncryptedContent_UserDiscoveryRequest.create) + ..aOM( + 23, _omitFieldNames ? '' : 'userDiscoveryUpdate', + subBuilder: EncryptedContent_UserDiscoveryUpdate.create) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -2115,6 +2215,42 @@ class EncryptedContent extends $pb.GeneratedMessage { void clearTypingIndicator() => $_clearField(20); @$pb.TagNumber(20) EncryptedContent_TypingIndicator ensureTypingIndicator() => $_ensure(18); + + @$pb.TagNumber(21) + $core.List<$core.int> get senderUserDiscoveryVersion => $_getN(19); + @$pb.TagNumber(21) + set senderUserDiscoveryVersion($core.List<$core.int> value) => + $_setBytes(19, value); + @$pb.TagNumber(21) + $core.bool hasSenderUserDiscoveryVersion() => $_has(19); + @$pb.TagNumber(21) + void clearSenderUserDiscoveryVersion() => $_clearField(21); + + @$pb.TagNumber(22) + EncryptedContent_UserDiscoveryRequest get userDiscoveryRequest => $_getN(20); + @$pb.TagNumber(22) + set userDiscoveryRequest(EncryptedContent_UserDiscoveryRequest value) => + $_setField(22, value); + @$pb.TagNumber(22) + $core.bool hasUserDiscoveryRequest() => $_has(20); + @$pb.TagNumber(22) + void clearUserDiscoveryRequest() => $_clearField(22); + @$pb.TagNumber(22) + EncryptedContent_UserDiscoveryRequest ensureUserDiscoveryRequest() => + $_ensure(20); + + @$pb.TagNumber(23) + EncryptedContent_UserDiscoveryUpdate get userDiscoveryUpdate => $_getN(21); + @$pb.TagNumber(23) + set userDiscoveryUpdate(EncryptedContent_UserDiscoveryUpdate value) => + $_setField(23, value); + @$pb.TagNumber(23) + $core.bool hasUserDiscoveryUpdate() => $_has(21); + @$pb.TagNumber(23) + void clearUserDiscoveryUpdate() => $_clearField(23); + @$pb.TagNumber(23) + EncryptedContent_UserDiscoveryUpdate ensureUserDiscoveryUpdate() => + $_ensure(21); } const $core.bool _omitFieldNames = diff --git a/lib/src/model/protobuf/client/generated/messages.pbjson.dart b/lib/src/model/protobuf/client/generated/messages.pbjson.dart index fe0555c6..b29eb4d1 100644 --- a/lib/src/model/protobuf/client/generated/messages.pbjson.dart +++ b/lib/src/model/protobuf/client/generated/messages.pbjson.dart @@ -19,9 +19,9 @@ const Message$json = { '1': 'Message', '2': [ {'1': 'type', '3': 1, '4': 1, '5': 14, '6': '.Message.Type', '10': 'type'}, - {'1': 'receiptId', '3': 2, '4': 1, '5': 9, '10': 'receiptId'}, + {'1': 'receipt_id', '3': 2, '4': 1, '5': 9, '10': 'receiptId'}, { - '1': 'encryptedContent', + '1': 'encrypted_content', '3': 3, '4': 1, '5': 12, @@ -30,7 +30,7 @@ const Message$json = { '17': true }, { - '1': 'plaintextContent', + '1': 'plaintext_content', '3': 4, '4': 1, '5': 11, @@ -42,8 +42,8 @@ const Message$json = { ], '4': [Message_Type$json], '8': [ - {'1': '_encryptedContent'}, - {'1': '_plaintextContent'}, + {'1': '_encrypted_content'}, + {'1': '_plaintext_content'}, ], }; @@ -61,20 +61,20 @@ const Message_Type$json = { /// Descriptor for `Message`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List messageDescriptor = $convert.base64Decode( - 'CgdNZXNzYWdlEiEKBHR5cGUYASABKA4yDS5NZXNzYWdlLlR5cGVSBHR5cGUSHAoJcmVjZWlwdE' - 'lkGAIgASgJUglyZWNlaXB0SWQSLwoQZW5jcnlwdGVkQ29udGVudBgDIAEoDEgAUhBlbmNyeXB0' - 'ZWRDb250ZW50iAEBEkIKEHBsYWludGV4dENvbnRlbnQYBCABKAsyES5QbGFpbnRleHRDb250ZW' - '50SAFSEHBsYWludGV4dENvbnRlbnSIAQEidAoEVHlwZRIbChdTRU5ERVJfREVMSVZFUllfUkVD' - 'RUlQVBAAEhUKEVBMQUlOVEVYVF9DT05URU5UEAESDgoKQ0lQSEVSVEVYVBACEhEKDVBSRUtFWV' - '9CVU5ETEUQAxIVChFURVNUX05PVElGSUNBVElPThAEQhMKEV9lbmNyeXB0ZWRDb250ZW50QhMK' - 'EV9wbGFpbnRleHRDb250ZW50'); + 'CgdNZXNzYWdlEiEKBHR5cGUYASABKA4yDS5NZXNzYWdlLlR5cGVSBHR5cGUSHQoKcmVjZWlwdF' + '9pZBgCIAEoCVIJcmVjZWlwdElkEjAKEWVuY3J5cHRlZF9jb250ZW50GAMgASgMSABSEGVuY3J5' + 'cHRlZENvbnRlbnSIAQESQwoRcGxhaW50ZXh0X2NvbnRlbnQYBCABKAsyES5QbGFpbnRleHRDb2' + '50ZW50SAFSEHBsYWludGV4dENvbnRlbnSIAQEidAoEVHlwZRIbChdTRU5ERVJfREVMSVZFUllf' + 'UkVDRUlQVBAAEhUKEVBMQUlOVEVYVF9DT05URU5UEAESDgoKQ0lQSEVSVEVYVBACEhEKDVBSRU' + 'tFWV9CVU5ETEUQAxIVChFURVNUX05PVElGSUNBVElPThAEQhQKEl9lbmNyeXB0ZWRfY29udGVu' + 'dEIUChJfcGxhaW50ZXh0X2NvbnRlbnQ='); @$core.Deprecated('Use plaintextContentDescriptor instead') const PlaintextContent$json = { '1': 'PlaintextContent', '2': [ { - '1': 'decryptionErrorMessage', + '1': 'decryption_error_message', '3': 1, '4': 1, '5': 11, @@ -84,7 +84,7 @@ const PlaintextContent$json = { '17': true }, { - '1': 'retryControlError', + '1': 'retry_control_error', '3': 2, '4': 1, '5': 11, @@ -99,8 +99,8 @@ const PlaintextContent$json = { PlaintextContent_DecryptionErrorMessage$json ], '8': [ - {'1': '_decryptionErrorMessage'}, - {'1': '_retryControlError'}, + {'1': '_decryption_error_message'}, + {'1': '_retry_control_error'}, ], }; @@ -136,21 +136,21 @@ const PlaintextContent_DecryptionErrorMessage_Type$json = { /// Descriptor for `PlaintextContent`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List plaintextContentDescriptor = $convert.base64Decode( - 'ChBQbGFpbnRleHRDb250ZW50EmUKFmRlY3J5cHRpb25FcnJvck1lc3NhZ2UYASABKAsyKC5QbG' - 'FpbnRleHRDb250ZW50LkRlY3J5cHRpb25FcnJvck1lc3NhZ2VIAFIWZGVjcnlwdGlvbkVycm9y' - 'TWVzc2FnZYgBARJWChFyZXRyeUNvbnRyb2xFcnJvchgCIAEoCzIjLlBsYWludGV4dENvbnRlbn' - 'QuUmV0cnlFcnJvck1lc3NhZ2VIAVIRcmV0cnlDb250cm9sRXJyb3KIAQEaEwoRUmV0cnlFcnJv' - 'ck1lc3NhZ2UahAEKFkRlY3J5cHRpb25FcnJvck1lc3NhZ2USQQoEdHlwZRgBIAEoDjItLlBsYW' - 'ludGV4dENvbnRlbnQuRGVjcnlwdGlvbkVycm9yTWVzc2FnZS5UeXBlUgR0eXBlIicKBFR5cGUS' - 'CwoHVU5LTk9XThAAEhIKDlBSRUtFWV9VTktOT1dOEAFCGQoXX2RlY3J5cHRpb25FcnJvck1lc3' - 'NhZ2VCFAoSX3JldHJ5Q29udHJvbEVycm9y'); + 'ChBQbGFpbnRleHRDb250ZW50EmcKGGRlY3J5cHRpb25fZXJyb3JfbWVzc2FnZRgBIAEoCzIoLl' + 'BsYWludGV4dENvbnRlbnQuRGVjcnlwdGlvbkVycm9yTWVzc2FnZUgAUhZkZWNyeXB0aW9uRXJy' + 'b3JNZXNzYWdliAEBElgKE3JldHJ5X2NvbnRyb2xfZXJyb3IYAiABKAsyIy5QbGFpbnRleHRDb2' + '50ZW50LlJldHJ5RXJyb3JNZXNzYWdlSAFSEXJldHJ5Q29udHJvbEVycm9yiAEBGhMKEVJldHJ5' + 'RXJyb3JNZXNzYWdlGoQBChZEZWNyeXB0aW9uRXJyb3JNZXNzYWdlEkEKBHR5cGUYASABKA4yLS' + '5QbGFpbnRleHRDb250ZW50LkRlY3J5cHRpb25FcnJvck1lc3NhZ2UuVHlwZVIEdHlwZSInCgRU' + 'eXBlEgsKB1VOS05PV04QABISCg5QUkVLRVlfVU5LTk9XThABQhsKGV9kZWNyeXB0aW9uX2Vycm' + '9yX21lc3NhZ2VCFgoUX3JldHJ5X2NvbnRyb2xfZXJyb3I='); @$core.Deprecated('Use encryptedContentDescriptor instead') const EncryptedContent$json = { '1': 'EncryptedContent', '2': [ { - '1': 'groupId', + '1': 'group_id', '3': 2, '4': 1, '5': 9, @@ -159,7 +159,7 @@ const EncryptedContent$json = { '17': true }, { - '1': 'isDirectChat', + '1': 'is_direct_chat', '3': 3, '4': 1, '5': 8, @@ -168,7 +168,7 @@ const EncryptedContent$json = { '17': true }, { - '1': 'senderProfileCounter', + '1': 'sender_profile_counter', '3': 4, '4': 1, '5': 3, @@ -177,12 +177,21 @@ const EncryptedContent$json = { '17': true }, { - '1': 'messageUpdate', + '1': 'sender_user_discovery_version', + '3': 21, + '4': 1, + '5': 12, + '9': 3, + '10': 'senderUserDiscoveryVersion', + '17': true + }, + { + '1': 'message_update', '3': 5, '4': 1, '5': 11, '6': '.EncryptedContent.MessageUpdate', - '9': 3, + '9': 4, '10': 'messageUpdate', '17': true }, @@ -192,57 +201,57 @@ const EncryptedContent$json = { '4': 1, '5': 11, '6': '.EncryptedContent.Media', - '9': 4, + '9': 5, '10': 'media', '17': true }, { - '1': 'mediaUpdate', + '1': 'media_update', '3': 7, '4': 1, '5': 11, '6': '.EncryptedContent.MediaUpdate', - '9': 5, + '9': 6, '10': 'mediaUpdate', '17': true }, { - '1': 'contactUpdate', + '1': 'contact_update', '3': 8, '4': 1, '5': 11, '6': '.EncryptedContent.ContactUpdate', - '9': 6, + '9': 7, '10': 'contactUpdate', '17': true }, { - '1': 'contactRequest', + '1': 'contact_request', '3': 9, '4': 1, '5': 11, '6': '.EncryptedContent.ContactRequest', - '9': 7, + '9': 8, '10': 'contactRequest', '17': true }, { - '1': 'flameSync', + '1': 'flame_sync', '3': 10, '4': 1, '5': 11, '6': '.EncryptedContent.FlameSync', - '9': 8, + '9': 9, '10': 'flameSync', '17': true }, { - '1': 'pushKeys', + '1': 'push_keys', '3': 11, '4': 1, '5': 11, '6': '.EncryptedContent.PushKeys', - '9': 9, + '9': 10, '10': 'pushKeys', '17': true }, @@ -252,57 +261,57 @@ const EncryptedContent$json = { '4': 1, '5': 11, '6': '.EncryptedContent.Reaction', - '9': 10, + '9': 11, '10': 'reaction', '17': true }, { - '1': 'textMessage', + '1': 'text_message', '3': 13, '4': 1, '5': 11, '6': '.EncryptedContent.TextMessage', - '9': 11, + '9': 12, '10': 'textMessage', '17': true }, { - '1': 'groupCreate', + '1': 'group_create', '3': 14, '4': 1, '5': 11, '6': '.EncryptedContent.GroupCreate', - '9': 12, + '9': 13, '10': 'groupCreate', '17': true }, { - '1': 'groupJoin', + '1': 'group_join', '3': 15, '4': 1, '5': 11, '6': '.EncryptedContent.GroupJoin', - '9': 13, + '9': 14, '10': 'groupJoin', '17': true }, { - '1': 'groupUpdate', + '1': 'group_update', '3': 16, '4': 1, '5': 11, '6': '.EncryptedContent.GroupUpdate', - '9': 14, + '9': 15, '10': 'groupUpdate', '17': true }, { - '1': 'resendGroupPublicKey', + '1': 'resend_group_public_key', '3': 17, '4': 1, '5': 11, '6': '.EncryptedContent.ResendGroupPublicKey', - '9': 15, + '9': 16, '10': 'resendGroupPublicKey', '17': true }, @@ -312,7 +321,7 @@ const EncryptedContent$json = { '4': 1, '5': 11, '6': '.EncryptedContent.ErrorMessages', - '9': 16, + '9': 17, '10': 'errorMessages', '17': true }, @@ -322,7 +331,7 @@ const EncryptedContent$json = { '4': 1, '5': 11, '6': '.EncryptedContent.AdditionalDataMessage', - '9': 17, + '9': 18, '10': 'additionalDataMessage', '17': true }, @@ -332,10 +341,30 @@ const EncryptedContent$json = { '4': 1, '5': 11, '6': '.EncryptedContent.TypingIndicator', - '9': 18, + '9': 19, '10': 'typingIndicator', '17': true }, + { + '1': 'user_discovery_request', + '3': 22, + '4': 1, + '5': 11, + '6': '.EncryptedContent.UserDiscoveryRequest', + '9': 20, + '10': 'userDiscoveryRequest', + '17': true + }, + { + '1': 'user_discovery_update', + '3': 23, + '4': 1, + '5': 11, + '6': '.EncryptedContent.UserDiscoveryUpdate', + '9': 21, + '10': 'userDiscoveryUpdate', + '17': true + }, ], '3': [ EncryptedContent_ErrorMessages$json, @@ -353,28 +382,33 @@ const EncryptedContent$json = { EncryptedContent_ContactUpdate$json, EncryptedContent_PushKeys$json, EncryptedContent_FlameSync$json, - EncryptedContent_TypingIndicator$json + EncryptedContent_TypingIndicator$json, + EncryptedContent_UserDiscoveryRequest$json, + EncryptedContent_UserDiscoveryUpdate$json ], '8': [ - {'1': '_groupId'}, - {'1': '_isDirectChat'}, - {'1': '_senderProfileCounter'}, - {'1': '_messageUpdate'}, + {'1': '_group_id'}, + {'1': '_is_direct_chat'}, + {'1': '_sender_profile_counter'}, + {'1': '_sender_user_discovery_version'}, + {'1': '_message_update'}, {'1': '_media'}, - {'1': '_mediaUpdate'}, - {'1': '_contactUpdate'}, - {'1': '_contactRequest'}, - {'1': '_flameSync'}, - {'1': '_pushKeys'}, + {'1': '_media_update'}, + {'1': '_contact_update'}, + {'1': '_contact_request'}, + {'1': '_flame_sync'}, + {'1': '_push_keys'}, {'1': '_reaction'}, - {'1': '_textMessage'}, - {'1': '_groupCreate'}, - {'1': '_groupJoin'}, - {'1': '_groupUpdate'}, - {'1': '_resendGroupPublicKey'}, + {'1': '_text_message'}, + {'1': '_group_create'}, + {'1': '_group_join'}, + {'1': '_group_update'}, + {'1': '_resend_group_public_key'}, {'1': '_error_messages'}, {'1': '_additional_data_message'}, {'1': '_typing_indicator'}, + {'1': '_user_discovery_request'}, + {'1': '_user_discovery_update'}, ], }; @@ -415,8 +449,8 @@ const EncryptedContent_ErrorMessages_Type$json = { const EncryptedContent_GroupCreate$json = { '1': 'GroupCreate', '2': [ - {'1': 'stateKey', '3': 3, '4': 1, '5': 12, '10': 'stateKey'}, - {'1': 'groupPublicKey', '3': 4, '4': 1, '5': 12, '10': 'groupPublicKey'}, + {'1': 'state_key', '3': 3, '4': 1, '5': 12, '10': 'stateKey'}, + {'1': 'group_public_key', '3': 4, '4': 1, '5': 12, '10': 'groupPublicKey'}, ], }; @@ -424,7 +458,7 @@ const EncryptedContent_GroupCreate$json = { const EncryptedContent_GroupJoin$json = { '1': 'GroupJoin', '2': [ - {'1': 'groupPublicKey', '3': 1, '4': 1, '5': 12, '10': 'groupPublicKey'}, + {'1': 'group_public_key', '3': 1, '4': 1, '5': 12, '10': 'groupPublicKey'}, ], }; @@ -437,9 +471,9 @@ const EncryptedContent_ResendGroupPublicKey$json = { const EncryptedContent_GroupUpdate$json = { '1': 'GroupUpdate', '2': [ - {'1': 'groupActionType', '3': 1, '4': 1, '5': 9, '10': 'groupActionType'}, + {'1': 'group_action_type', '3': 1, '4': 1, '5': 9, '10': 'groupActionType'}, { - '1': 'affectedContactId', + '1': 'affected_contact_id', '3': 2, '4': 1, '5': 3, @@ -448,7 +482,7 @@ const EncryptedContent_GroupUpdate$json = { '17': true }, { - '1': 'newGroupName', + '1': 'new_group_name', '3': 3, '4': 1, '5': 9, @@ -457,7 +491,7 @@ const EncryptedContent_GroupUpdate$json = { '17': true }, { - '1': 'newDeleteMessagesAfterMilliseconds', + '1': 'new_delete_messages_after_milliseconds', '3': 4, '4': 1, '5': 3, @@ -467,9 +501,9 @@ const EncryptedContent_GroupUpdate$json = { }, ], '8': [ - {'1': '_affectedContactId'}, - {'1': '_newGroupName'}, - {'1': '_newDeleteMessagesAfterMilliseconds'}, + {'1': '_affected_contact_id'}, + {'1': '_new_group_name'}, + {'1': '_new_delete_messages_after_milliseconds'}, ], }; @@ -477,11 +511,11 @@ const EncryptedContent_GroupUpdate$json = { const EncryptedContent_TextMessage$json = { '1': 'TextMessage', '2': [ - {'1': 'senderMessageId', '3': 1, '4': 1, '5': 9, '10': 'senderMessageId'}, + {'1': 'sender_message_id', '3': 1, '4': 1, '5': 9, '10': 'senderMessageId'}, {'1': 'text', '3': 2, '4': 1, '5': 9, '10': 'text'}, {'1': 'timestamp', '3': 3, '4': 1, '5': 3, '10': 'timestamp'}, { - '1': 'quoteMessageId', + '1': 'quote_message_id', '3': 4, '4': 1, '5': 9, @@ -491,7 +525,7 @@ const EncryptedContent_TextMessage$json = { }, ], '8': [ - {'1': '_quoteMessageId'}, + {'1': '_quote_message_id'}, ], }; @@ -521,7 +555,7 @@ const EncryptedContent_AdditionalDataMessage$json = { const EncryptedContent_Reaction$json = { '1': 'Reaction', '2': [ - {'1': 'targetMessageId', '3': 1, '4': 1, '5': 9, '10': 'targetMessageId'}, + {'1': 'target_message_id', '3': 1, '4': 1, '5': 9, '10': 'targetMessageId'}, {'1': 'emoji', '3': 2, '4': 1, '5': 9, '10': 'emoji'}, {'1': 'remove', '3': 3, '4': 1, '5': 8, '10': 'remove'}, ], @@ -540,7 +574,7 @@ const EncryptedContent_MessageUpdate$json = { '10': 'type' }, { - '1': 'senderMessageId', + '1': 'sender_message_id', '3': 2, '4': 1, '5': 9, @@ -549,7 +583,7 @@ const EncryptedContent_MessageUpdate$json = { '17': true }, { - '1': 'multipleTargetMessageIds', + '1': 'multiple_target_message_ids', '3': 3, '4': 3, '5': 9, @@ -560,7 +594,7 @@ const EncryptedContent_MessageUpdate$json = { ], '4': [EncryptedContent_MessageUpdate_Type$json], '8': [ - {'1': '_senderMessageId'}, + {'1': '_sender_message_id'}, {'1': '_text'}, ], }; @@ -579,7 +613,7 @@ const EncryptedContent_MessageUpdate_Type$json = { const EncryptedContent_Media$json = { '1': 'Media', '2': [ - {'1': 'senderMessageId', '3': 1, '4': 1, '5': 9, '10': 'senderMessageId'}, + {'1': 'sender_message_id', '3': 1, '4': 1, '5': 9, '10': 'senderMessageId'}, { '1': 'type', '3': 2, @@ -589,7 +623,7 @@ const EncryptedContent_Media$json = { '10': 'type' }, { - '1': 'displayLimitInMilliseconds', + '1': 'display_limit_in_milliseconds', '3': 3, '4': 1, '5': 3, @@ -598,7 +632,7 @@ const EncryptedContent_Media$json = { '17': true }, { - '1': 'requiresAuthentication', + '1': 'requires_authentication', '3': 4, '4': 1, '5': 8, @@ -606,7 +640,7 @@ const EncryptedContent_Media$json = { }, {'1': 'timestamp', '3': 5, '4': 1, '5': 3, '10': 'timestamp'}, { - '1': 'quoteMessageId', + '1': 'quote_message_id', '3': 6, '4': 1, '5': 9, @@ -615,7 +649,7 @@ const EncryptedContent_Media$json = { '17': true }, { - '1': 'downloadToken', + '1': 'download_token', '3': 7, '4': 1, '5': 12, @@ -624,7 +658,7 @@ const EncryptedContent_Media$json = { '17': true }, { - '1': 'encryptionKey', + '1': 'encryption_key', '3': 8, '4': 1, '5': 12, @@ -633,7 +667,7 @@ const EncryptedContent_Media$json = { '17': true }, { - '1': 'encryptionMac', + '1': 'encryption_mac', '3': 9, '4': 1, '5': 12, @@ -642,7 +676,7 @@ const EncryptedContent_Media$json = { '17': true }, { - '1': 'encryptionNonce', + '1': 'encryption_nonce', '3': 10, '4': 1, '5': 12, @@ -662,12 +696,12 @@ const EncryptedContent_Media$json = { ], '4': [EncryptedContent_Media_Type$json], '8': [ - {'1': '_displayLimitInMilliseconds'}, - {'1': '_quoteMessageId'}, - {'1': '_downloadToken'}, - {'1': '_encryptionKey'}, - {'1': '_encryptionMac'}, - {'1': '_encryptionNonce'}, + {'1': '_display_limit_in_milliseconds'}, + {'1': '_quote_message_id'}, + {'1': '_download_token'}, + {'1': '_encryption_key'}, + {'1': '_encryption_mac'}, + {'1': '_encryption_nonce'}, {'1': '_additional_message_data'}, ], }; @@ -696,7 +730,7 @@ const EncryptedContent_MediaUpdate$json = { '6': '.EncryptedContent.MediaUpdate.Type', '10': 'type' }, - {'1': 'targetMessageId', '3': 2, '4': 1, '5': 9, '10': 'targetMessageId'}, + {'1': 'target_message_id', '3': 2, '4': 1, '5': 9, '10': 'targetMessageId'}, ], '4': [EncryptedContent_MediaUpdate_Type$json], }; @@ -750,7 +784,7 @@ const EncryptedContent_ContactUpdate$json = { '10': 'type' }, { - '1': 'avatarSvgCompressed', + '1': 'avatar_svg_compressed', '3': 2, '4': 1, '5': 12, @@ -768,7 +802,7 @@ const EncryptedContent_ContactUpdate$json = { '17': true }, { - '1': 'displayName', + '1': 'display_name', '3': 4, '4': 1, '5': 9, @@ -779,9 +813,9 @@ const EncryptedContent_ContactUpdate$json = { ], '4': [EncryptedContent_ContactUpdate_Type$json], '8': [ - {'1': '_avatarSvgCompressed'}, + {'1': '_avatar_svg_compressed'}, {'1': '_username'}, - {'1': '_displayName'}, + {'1': '_display_name'}, ], }; @@ -806,10 +840,10 @@ const EncryptedContent_PushKeys$json = { '6': '.EncryptedContent.PushKeys.Type', '10': 'type' }, - {'1': 'keyId', '3': 2, '4': 1, '5': 3, '9': 0, '10': 'keyId', '17': true}, + {'1': 'key_id', '3': 2, '4': 1, '5': 3, '9': 0, '10': 'keyId', '17': true}, {'1': 'key', '3': 3, '4': 1, '5': 12, '9': 1, '10': 'key', '17': true}, { - '1': 'createdAt', + '1': 'created_at', '3': 4, '4': 1, '5': 3, @@ -820,9 +854,9 @@ const EncryptedContent_PushKeys$json = { ], '4': [EncryptedContent_PushKeys_Type$json], '8': [ - {'1': '_keyId'}, + {'1': '_key_id'}, {'1': '_key'}, - {'1': '_createdAt'}, + {'1': '_created_at'}, ], }; @@ -839,16 +873,16 @@ const EncryptedContent_PushKeys_Type$json = { const EncryptedContent_FlameSync$json = { '1': 'FlameSync', '2': [ - {'1': 'flameCounter', '3': 1, '4': 1, '5': 3, '10': 'flameCounter'}, + {'1': 'flame_counter', '3': 1, '4': 1, '5': 3, '10': 'flameCounter'}, { - '1': 'lastFlameCounterChange', + '1': 'last_flame_counter_change', '3': 2, '4': 1, '5': 3, '10': 'lastFlameCounterChange' }, - {'1': 'bestFriend', '3': 3, '4': 1, '5': 8, '10': 'bestFriend'}, - {'1': 'forceUpdate', '3': 4, '4': 1, '5': 8, '10': 'forceUpdate'}, + {'1': 'best_friend', '3': 3, '4': 1, '5': 8, '10': 'bestFriend'}, + {'1': 'force_update', '3': 4, '4': 1, '5': 8, '10': 'forceUpdate'}, ], }; @@ -861,95 +895,121 @@ const EncryptedContent_TypingIndicator$json = { ], }; +@$core.Deprecated('Use encryptedContentDescriptor instead') +const EncryptedContent_UserDiscoveryRequest$json = { + '1': 'UserDiscoveryRequest', + '2': [ + {'1': 'current_version', '3': 1, '4': 1, '5': 12, '10': 'currentVersion'}, + ], +}; + +@$core.Deprecated('Use encryptedContentDescriptor instead') +const EncryptedContent_UserDiscoveryUpdate$json = { + '1': 'UserDiscoveryUpdate', + '2': [ + {'1': 'messages', '3': 1, '4': 3, '5': 12, '10': 'messages'}, + ], +}; + /// Descriptor for `EncryptedContent`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List encryptedContentDescriptor = $convert.base64Decode( - 'ChBFbmNyeXB0ZWRDb250ZW50Eh0KB2dyb3VwSWQYAiABKAlIAFIHZ3JvdXBJZIgBARInCgxpc0' - 'RpcmVjdENoYXQYAyABKAhIAVIMaXNEaXJlY3RDaGF0iAEBEjcKFHNlbmRlclByb2ZpbGVDb3Vu' - 'dGVyGAQgASgDSAJSFHNlbmRlclByb2ZpbGVDb3VudGVyiAEBEkoKDW1lc3NhZ2VVcGRhdGUYBS' - 'ABKAsyHy5FbmNyeXB0ZWRDb250ZW50Lk1lc3NhZ2VVcGRhdGVIA1INbWVzc2FnZVVwZGF0ZYgB' - 'ARIyCgVtZWRpYRgGIAEoCzIXLkVuY3J5cHRlZENvbnRlbnQuTWVkaWFIBFIFbWVkaWGIAQESRA' - 'oLbWVkaWFVcGRhdGUYByABKAsyHS5FbmNyeXB0ZWRDb250ZW50Lk1lZGlhVXBkYXRlSAVSC21l' - 'ZGlhVXBkYXRliAEBEkoKDWNvbnRhY3RVcGRhdGUYCCABKAsyHy5FbmNyeXB0ZWRDb250ZW50Lk' - 'NvbnRhY3RVcGRhdGVIBlINY29udGFjdFVwZGF0ZYgBARJNCg5jb250YWN0UmVxdWVzdBgJIAEo' - 'CzIgLkVuY3J5cHRlZENvbnRlbnQuQ29udGFjdFJlcXVlc3RIB1IOY29udGFjdFJlcXVlc3SIAQ' - 'ESPgoJZmxhbWVTeW5jGAogASgLMhsuRW5jcnlwdGVkQ29udGVudC5GbGFtZVN5bmNICFIJZmxh' - 'bWVTeW5jiAEBEjsKCHB1c2hLZXlzGAsgASgLMhouRW5jcnlwdGVkQ29udGVudC5QdXNoS2V5c0' - 'gJUghwdXNoS2V5c4gBARI7CghyZWFjdGlvbhgMIAEoCzIaLkVuY3J5cHRlZENvbnRlbnQuUmVh' - 'Y3Rpb25IClIIcmVhY3Rpb26IAQESRAoLdGV4dE1lc3NhZ2UYDSABKAsyHS5FbmNyeXB0ZWRDb2' - '50ZW50LlRleHRNZXNzYWdlSAtSC3RleHRNZXNzYWdliAEBEkQKC2dyb3VwQ3JlYXRlGA4gASgL' - 'Mh0uRW5jcnlwdGVkQ29udGVudC5Hcm91cENyZWF0ZUgMUgtncm91cENyZWF0ZYgBARI+Cglncm' - '91cEpvaW4YDyABKAsyGy5FbmNyeXB0ZWRDb250ZW50Lkdyb3VwSm9pbkgNUglncm91cEpvaW6I' - 'AQESRAoLZ3JvdXBVcGRhdGUYECABKAsyHS5FbmNyeXB0ZWRDb250ZW50Lkdyb3VwVXBkYXRlSA' - '5SC2dyb3VwVXBkYXRliAEBEl8KFHJlc2VuZEdyb3VwUHVibGljS2V5GBEgASgLMiYuRW5jcnlw' - 'dGVkQ29udGVudC5SZXNlbmRHcm91cFB1YmxpY0tleUgPUhRyZXNlbmRHcm91cFB1YmxpY0tleY' - 'gBARJLCg5lcnJvcl9tZXNzYWdlcxgSIAEoCzIfLkVuY3J5cHRlZENvbnRlbnQuRXJyb3JNZXNz' - 'YWdlc0gQUg1lcnJvck1lc3NhZ2VziAEBEmQKF2FkZGl0aW9uYWxfZGF0YV9tZXNzYWdlGBMgAS' - 'gLMicuRW5jcnlwdGVkQ29udGVudC5BZGRpdGlvbmFsRGF0YU1lc3NhZ2VIEVIVYWRkaXRpb25h' - 'bERhdGFNZXNzYWdliAEBElEKEHR5cGluZ19pbmRpY2F0b3IYFCABKAsyIS5FbmNyeXB0ZWRDb2' - '50ZW50LlR5cGluZ0luZGljYXRvckgSUg90eXBpbmdJbmRpY2F0b3KIAQEa8AEKDUVycm9yTWVz' - 'c2FnZXMSOAoEdHlwZRgBIAEoDjIkLkVuY3J5cHRlZENvbnRlbnQuRXJyb3JNZXNzYWdlcy5UeX' - 'BlUgR0eXBlEiwKEnJlbGF0ZWRfcmVjZWlwdF9pZBgCIAEoCVIQcmVsYXRlZFJlY2VpcHRJZCJ3' - 'CgRUeXBlEjwKOEVSUk9SX1BST0NFU1NJTkdfTUVTU0FHRV9DUkVBVEVEX0FDQ09VTlRfUkVRVU' - 'VTVF9JTlNURUFEEAASGAoUVU5LTk9XTl9NRVNTQUdFX1RZUEUQAhIXChNTRVNTSU9OX09VVF9P' - 'Rl9TWU5DEAMaUQoLR3JvdXBDcmVhdGUSGgoIc3RhdGVLZXkYAyABKAxSCHN0YXRlS2V5EiYKDm' - 'dyb3VwUHVibGljS2V5GAQgASgMUg5ncm91cFB1YmxpY0tleRozCglHcm91cEpvaW4SJgoOZ3Jv' - 'dXBQdWJsaWNLZXkYASABKAxSDmdyb3VwUHVibGljS2V5GhYKFFJlc2VuZEdyb3VwUHVibGljS2' - 'V5GrYCCgtHcm91cFVwZGF0ZRIoCg9ncm91cEFjdGlvblR5cGUYASABKAlSD2dyb3VwQWN0aW9u' - 'VHlwZRIxChFhZmZlY3RlZENvbnRhY3RJZBgCIAEoA0gAUhFhZmZlY3RlZENvbnRhY3RJZIgBAR' - 'InCgxuZXdHcm91cE5hbWUYAyABKAlIAVIMbmV3R3JvdXBOYW1liAEBElMKIm5ld0RlbGV0ZU1l' - 'c3NhZ2VzQWZ0ZXJNaWxsaXNlY29uZHMYBCABKANIAlIibmV3RGVsZXRlTWVzc2FnZXNBZnRlck' - '1pbGxpc2Vjb25kc4gBAUIUChJfYWZmZWN0ZWRDb250YWN0SWRCDwoNX25ld0dyb3VwTmFtZUIl' - 'CiNfbmV3RGVsZXRlTWVzc2FnZXNBZnRlck1pbGxpc2Vjb25kcxqpAQoLVGV4dE1lc3NhZ2USKA' - 'oPc2VuZGVyTWVzc2FnZUlkGAEgASgJUg9zZW5kZXJNZXNzYWdlSWQSEgoEdGV4dBgCIAEoCVIE' - 'dGV4dBIcCgl0aW1lc3RhbXAYAyABKANSCXRpbWVzdGFtcBIrCg5xdW90ZU1lc3NhZ2VJZBgEIA' - 'EoCUgAUg5xdW90ZU1lc3NhZ2VJZIgBAUIRCg9fcXVvdGVNZXNzYWdlSWQazgEKFUFkZGl0aW9u' - 'YWxEYXRhTWVzc2FnZRIqChFzZW5kZXJfbWVzc2FnZV9pZBgBIAEoCVIPc2VuZGVyTWVzc2FnZU' - 'lkEhwKCXRpbWVzdGFtcBgCIAEoA1IJdGltZXN0YW1wEhIKBHR5cGUYAyABKAlSBHR5cGUSOwoX' - 'YWRkaXRpb25hbF9tZXNzYWdlX2RhdGEYBCABKAxIAFIVYWRkaXRpb25hbE1lc3NhZ2VEYXRhiA' - 'EBQhoKGF9hZGRpdGlvbmFsX21lc3NhZ2VfZGF0YRpiCghSZWFjdGlvbhIoCg90YXJnZXRNZXNz' - 'YWdlSWQYASABKAlSD3RhcmdldE1lc3NhZ2VJZBIUCgVlbW9qaRgCIAEoCVIFZW1vamkSFgoGcm' - 'Vtb3ZlGAMgASgIUgZyZW1vdmUatwIKDU1lc3NhZ2VVcGRhdGUSOAoEdHlwZRgBIAEoDjIkLkVu' - 'Y3J5cHRlZENvbnRlbnQuTWVzc2FnZVVwZGF0ZS5UeXBlUgR0eXBlEi0KD3NlbmRlck1lc3NhZ2' - 'VJZBgCIAEoCUgAUg9zZW5kZXJNZXNzYWdlSWSIAQESOgoYbXVsdGlwbGVUYXJnZXRNZXNzYWdl' - 'SWRzGAMgAygJUhhtdWx0aXBsZVRhcmdldE1lc3NhZ2VJZHMSFwoEdGV4dBgEIAEoCUgBUgR0ZX' - 'h0iAEBEhwKCXRpbWVzdGFtcBgFIAEoA1IJdGltZXN0YW1wIi0KBFR5cGUSCgoGREVMRVRFEAAS' - 'DQoJRURJVF9URVhUEAESCgoGT1BFTkVEEAJCEgoQX3NlbmRlck1lc3NhZ2VJZEIHCgVfdGV4dB' - 'rwBQoFTWVkaWESKAoPc2VuZGVyTWVzc2FnZUlkGAEgASgJUg9zZW5kZXJNZXNzYWdlSWQSMAoE' - 'dHlwZRgCIAEoDjIcLkVuY3J5cHRlZENvbnRlbnQuTWVkaWEuVHlwZVIEdHlwZRJDChpkaXNwbG' - 'F5TGltaXRJbk1pbGxpc2Vjb25kcxgDIAEoA0gAUhpkaXNwbGF5TGltaXRJbk1pbGxpc2Vjb25k' - 'c4gBARI2ChZyZXF1aXJlc0F1dGhlbnRpY2F0aW9uGAQgASgIUhZyZXF1aXJlc0F1dGhlbnRpY2' - 'F0aW9uEhwKCXRpbWVzdGFtcBgFIAEoA1IJdGltZXN0YW1wEisKDnF1b3RlTWVzc2FnZUlkGAYg' - 'ASgJSAFSDnF1b3RlTWVzc2FnZUlkiAEBEikKDWRvd25sb2FkVG9rZW4YByABKAxIAlINZG93bm' - 'xvYWRUb2tlbogBARIpCg1lbmNyeXB0aW9uS2V5GAggASgMSANSDWVuY3J5cHRpb25LZXmIAQES' - 'KQoNZW5jcnlwdGlvbk1hYxgJIAEoDEgEUg1lbmNyeXB0aW9uTWFjiAEBEi0KD2VuY3J5cHRpb2' - '5Ob25jZRgKIAEoDEgFUg9lbmNyeXB0aW9uTm9uY2WIAQESOwoXYWRkaXRpb25hbF9tZXNzYWdl' - 'X2RhdGEYCyABKAxIBlIVYWRkaXRpb25hbE1lc3NhZ2VEYXRhiAEBIj4KBFR5cGUSDAoIUkVVUE' - 'xPQUQQABIJCgVJTUFHRRABEgkKBVZJREVPEAISBwoDR0lGEAMSCQoFQVVESU8QBEIdChtfZGlz' - 'cGxheUxpbWl0SW5NaWxsaXNlY29uZHNCEQoPX3F1b3RlTWVzc2FnZUlkQhAKDl9kb3dubG9hZF' - 'Rva2VuQhAKDl9lbmNyeXB0aW9uS2V5QhAKDl9lbmNyeXB0aW9uTWFjQhIKEF9lbmNyeXB0aW9u' - 'Tm9uY2VCGgoYX2FkZGl0aW9uYWxfbWVzc2FnZV9kYXRhGqcBCgtNZWRpYVVwZGF0ZRI2CgR0eX' - 'BlGAEgASgOMiIuRW5jcnlwdGVkQ29udGVudC5NZWRpYVVwZGF0ZS5UeXBlUgR0eXBlEigKD3Rh' - 'cmdldE1lc3NhZ2VJZBgCIAEoCVIPdGFyZ2V0TWVzc2FnZUlkIjYKBFR5cGUSDAoIUkVPUEVORU' - 'QQABIKCgZTVE9SRUQQARIUChBERUNSWVBUSU9OX0VSUk9SEAIaeAoOQ29udGFjdFJlcXVlc3QS' - 'OQoEdHlwZRgBIAEoDjIlLkVuY3J5cHRlZENvbnRlbnQuQ29udGFjdFJlcXVlc3QuVHlwZVIEdH' - 'lwZSIrCgRUeXBlEgsKB1JFUVVFU1QQABIKCgZSRUpFQ1QQARIKCgZBQ0NFUFQQAhqeAgoNQ29u' - 'dGFjdFVwZGF0ZRI4CgR0eXBlGAEgASgOMiQuRW5jcnlwdGVkQ29udGVudC5Db250YWN0VXBkYX' - 'RlLlR5cGVSBHR5cGUSNQoTYXZhdGFyU3ZnQ29tcHJlc3NlZBgCIAEoDEgAUhNhdmF0YXJTdmdD' - 'b21wcmVzc2VkiAEBEh8KCHVzZXJuYW1lGAMgASgJSAFSCHVzZXJuYW1liAEBEiUKC2Rpc3BsYX' - 'lOYW1lGAQgASgJSAJSC2Rpc3BsYXlOYW1liAEBIh8KBFR5cGUSCwoHUkVRVUVTVBAAEgoKBlVQ' - 'REFURRABQhYKFF9hdmF0YXJTdmdDb21wcmVzc2VkQgsKCV91c2VybmFtZUIOCgxfZGlzcGxheU' - '5hbWUa1QEKCFB1c2hLZXlzEjMKBHR5cGUYASABKA4yHy5FbmNyeXB0ZWRDb250ZW50LlB1c2hL' - 'ZXlzLlR5cGVSBHR5cGUSGQoFa2V5SWQYAiABKANIAFIFa2V5SWSIAQESFQoDa2V5GAMgASgMSA' - 'FSA2tleYgBARIhCgljcmVhdGVkQXQYBCABKANIAlIJY3JlYXRlZEF0iAEBIh8KBFR5cGUSCwoH' - 'UkVRVUVTVBAAEgoKBlVQREFURRABQggKBl9rZXlJZEIGCgRfa2V5QgwKCl9jcmVhdGVkQXQaqQ' - 'EKCUZsYW1lU3luYxIiCgxmbGFtZUNvdW50ZXIYASABKANSDGZsYW1lQ291bnRlchI2ChZsYXN0' - 'RmxhbWVDb3VudGVyQ2hhbmdlGAIgASgDUhZsYXN0RmxhbWVDb3VudGVyQ2hhbmdlEh4KCmJlc3' - 'RGcmllbmQYAyABKAhSCmJlc3RGcmllbmQSIAoLZm9yY2VVcGRhdGUYBCABKAhSC2ZvcmNlVXBk' - 'YXRlGk0KD1R5cGluZ0luZGljYXRvchIbCglpc190eXBpbmcYASABKAhSCGlzVHlwaW5nEh0KCm' - 'NyZWF0ZWRfYXQYAiABKANSCWNyZWF0ZWRBdEIKCghfZ3JvdXBJZEIPCg1faXNEaXJlY3RDaGF0' - 'QhcKFV9zZW5kZXJQcm9maWxlQ291bnRlckIQCg5fbWVzc2FnZVVwZGF0ZUIICgZfbWVkaWFCDg' - 'oMX21lZGlhVXBkYXRlQhAKDl9jb250YWN0VXBkYXRlQhEKD19jb250YWN0UmVxdWVzdEIMCgpf' - 'ZmxhbWVTeW5jQgsKCV9wdXNoS2V5c0ILCglfcmVhY3Rpb25CDgoMX3RleHRNZXNzYWdlQg4KDF' - '9ncm91cENyZWF0ZUIMCgpfZ3JvdXBKb2luQg4KDF9ncm91cFVwZGF0ZUIXChVfcmVzZW5kR3Jv' - 'dXBQdWJsaWNLZXlCEQoPX2Vycm9yX21lc3NhZ2VzQhoKGF9hZGRpdGlvbmFsX2RhdGFfbWVzc2' - 'FnZUITChFfdHlwaW5nX2luZGljYXRvcg=='); + 'ChBFbmNyeXB0ZWRDb250ZW50Eh4KCGdyb3VwX2lkGAIgASgJSABSB2dyb3VwSWSIAQESKQoOaX' + 'NfZGlyZWN0X2NoYXQYAyABKAhIAVIMaXNEaXJlY3RDaGF0iAEBEjkKFnNlbmRlcl9wcm9maWxl' + 'X2NvdW50ZXIYBCABKANIAlIUc2VuZGVyUHJvZmlsZUNvdW50ZXKIAQESRgodc2VuZGVyX3VzZX' + 'JfZGlzY292ZXJ5X3ZlcnNpb24YFSABKAxIA1Iac2VuZGVyVXNlckRpc2NvdmVyeVZlcnNpb26I' + 'AQESSwoObWVzc2FnZV91cGRhdGUYBSABKAsyHy5FbmNyeXB0ZWRDb250ZW50Lk1lc3NhZ2VVcG' + 'RhdGVIBFINbWVzc2FnZVVwZGF0ZYgBARIyCgVtZWRpYRgGIAEoCzIXLkVuY3J5cHRlZENvbnRl' + 'bnQuTWVkaWFIBVIFbWVkaWGIAQESRQoMbWVkaWFfdXBkYXRlGAcgASgLMh0uRW5jcnlwdGVkQ2' + '9udGVudC5NZWRpYVVwZGF0ZUgGUgttZWRpYVVwZGF0ZYgBARJLCg5jb250YWN0X3VwZGF0ZRgI' + 'IAEoCzIfLkVuY3J5cHRlZENvbnRlbnQuQ29udGFjdFVwZGF0ZUgHUg1jb250YWN0VXBkYXRliA' + 'EBEk4KD2NvbnRhY3RfcmVxdWVzdBgJIAEoCzIgLkVuY3J5cHRlZENvbnRlbnQuQ29udGFjdFJl' + 'cXVlc3RICFIOY29udGFjdFJlcXVlc3SIAQESPwoKZmxhbWVfc3luYxgKIAEoCzIbLkVuY3J5cH' + 'RlZENvbnRlbnQuRmxhbWVTeW5jSAlSCWZsYW1lU3luY4gBARI8CglwdXNoX2tleXMYCyABKAsy' + 'Gi5FbmNyeXB0ZWRDb250ZW50LlB1c2hLZXlzSApSCHB1c2hLZXlziAEBEjsKCHJlYWN0aW9uGA' + 'wgASgLMhouRW5jcnlwdGVkQ29udGVudC5SZWFjdGlvbkgLUghyZWFjdGlvbogBARJFCgx0ZXh0' + 'X21lc3NhZ2UYDSABKAsyHS5FbmNyeXB0ZWRDb250ZW50LlRleHRNZXNzYWdlSAxSC3RleHRNZX' + 'NzYWdliAEBEkUKDGdyb3VwX2NyZWF0ZRgOIAEoCzIdLkVuY3J5cHRlZENvbnRlbnQuR3JvdXBD' + 'cmVhdGVIDVILZ3JvdXBDcmVhdGWIAQESPwoKZ3JvdXBfam9pbhgPIAEoCzIbLkVuY3J5cHRlZE' + 'NvbnRlbnQuR3JvdXBKb2luSA5SCWdyb3VwSm9pbogBARJFCgxncm91cF91cGRhdGUYECABKAsy' + 'HS5FbmNyeXB0ZWRDb250ZW50Lkdyb3VwVXBkYXRlSA9SC2dyb3VwVXBkYXRliAEBEmIKF3Jlc2' + 'VuZF9ncm91cF9wdWJsaWNfa2V5GBEgASgLMiYuRW5jcnlwdGVkQ29udGVudC5SZXNlbmRHcm91' + 'cFB1YmxpY0tleUgQUhRyZXNlbmRHcm91cFB1YmxpY0tleYgBARJLCg5lcnJvcl9tZXNzYWdlcx' + 'gSIAEoCzIfLkVuY3J5cHRlZENvbnRlbnQuRXJyb3JNZXNzYWdlc0gRUg1lcnJvck1lc3NhZ2Vz' + 'iAEBEmQKF2FkZGl0aW9uYWxfZGF0YV9tZXNzYWdlGBMgASgLMicuRW5jcnlwdGVkQ29udGVudC' + '5BZGRpdGlvbmFsRGF0YU1lc3NhZ2VIElIVYWRkaXRpb25hbERhdGFNZXNzYWdliAEBElEKEHR5' + 'cGluZ19pbmRpY2F0b3IYFCABKAsyIS5FbmNyeXB0ZWRDb250ZW50LlR5cGluZ0luZGljYXRvck' + 'gTUg90eXBpbmdJbmRpY2F0b3KIAQESYQoWdXNlcl9kaXNjb3ZlcnlfcmVxdWVzdBgWIAEoCzIm' + 'LkVuY3J5cHRlZENvbnRlbnQuVXNlckRpc2NvdmVyeVJlcXVlc3RIFFIUdXNlckRpc2NvdmVyeV' + 'JlcXVlc3SIAQESXgoVdXNlcl9kaXNjb3ZlcnlfdXBkYXRlGBcgASgLMiUuRW5jcnlwdGVkQ29u' + 'dGVudC5Vc2VyRGlzY292ZXJ5VXBkYXRlSBVSE3VzZXJEaXNjb3ZlcnlVcGRhdGWIAQEa8AEKDU' + 'Vycm9yTWVzc2FnZXMSOAoEdHlwZRgBIAEoDjIkLkVuY3J5cHRlZENvbnRlbnQuRXJyb3JNZXNz' + 'YWdlcy5UeXBlUgR0eXBlEiwKEnJlbGF0ZWRfcmVjZWlwdF9pZBgCIAEoCVIQcmVsYXRlZFJlY2' + 'VpcHRJZCJ3CgRUeXBlEjwKOEVSUk9SX1BST0NFU1NJTkdfTUVTU0FHRV9DUkVBVEVEX0FDQ09V' + 'TlRfUkVRVUVTVF9JTlNURUFEEAASGAoUVU5LTk9XTl9NRVNTQUdFX1RZUEUQAhIXChNTRVNTSU' + '9OX09VVF9PRl9TWU5DEAMaVAoLR3JvdXBDcmVhdGUSGwoJc3RhdGVfa2V5GAMgASgMUghzdGF0' + 'ZUtleRIoChBncm91cF9wdWJsaWNfa2V5GAQgASgMUg5ncm91cFB1YmxpY0tleRo1CglHcm91cE' + 'pvaW4SKAoQZ3JvdXBfcHVibGljX2tleRgBIAEoDFIOZ3JvdXBQdWJsaWNLZXkaFgoUUmVzZW5k' + 'R3JvdXBQdWJsaWNLZXkayAIKC0dyb3VwVXBkYXRlEioKEWdyb3VwX2FjdGlvbl90eXBlGAEgAS' + 'gJUg9ncm91cEFjdGlvblR5cGUSMwoTYWZmZWN0ZWRfY29udGFjdF9pZBgCIAEoA0gAUhFhZmZl' + 'Y3RlZENvbnRhY3RJZIgBARIpCg5uZXdfZ3JvdXBfbmFtZRgDIAEoCUgBUgxuZXdHcm91cE5hbW' + 'WIAQESVwombmV3X2RlbGV0ZV9tZXNzYWdlc19hZnRlcl9taWxsaXNlY29uZHMYBCABKANIAlIi' + 'bmV3RGVsZXRlTWVzc2FnZXNBZnRlck1pbGxpc2Vjb25kc4gBAUIWChRfYWZmZWN0ZWRfY29udG' + 'FjdF9pZEIRCg9fbmV3X2dyb3VwX25hbWVCKQonX25ld19kZWxldGVfbWVzc2FnZXNfYWZ0ZXJf' + 'bWlsbGlzZWNvbmRzGq8BCgtUZXh0TWVzc2FnZRIqChFzZW5kZXJfbWVzc2FnZV9pZBgBIAEoCV' + 'IPc2VuZGVyTWVzc2FnZUlkEhIKBHRleHQYAiABKAlSBHRleHQSHAoJdGltZXN0YW1wGAMgASgD' + 'Ugl0aW1lc3RhbXASLQoQcXVvdGVfbWVzc2FnZV9pZBgEIAEoCUgAUg5xdW90ZU1lc3NhZ2VJZI' + 'gBAUITChFfcXVvdGVfbWVzc2FnZV9pZBrOAQoVQWRkaXRpb25hbERhdGFNZXNzYWdlEioKEXNl' + 'bmRlcl9tZXNzYWdlX2lkGAEgASgJUg9zZW5kZXJNZXNzYWdlSWQSHAoJdGltZXN0YW1wGAIgAS' + 'gDUgl0aW1lc3RhbXASEgoEdHlwZRgDIAEoCVIEdHlwZRI7ChdhZGRpdGlvbmFsX21lc3NhZ2Vf' + 'ZGF0YRgEIAEoDEgAUhVhZGRpdGlvbmFsTWVzc2FnZURhdGGIAQFCGgoYX2FkZGl0aW9uYWxfbW' + 'Vzc2FnZV9kYXRhGmQKCFJlYWN0aW9uEioKEXRhcmdldF9tZXNzYWdlX2lkGAEgASgJUg90YXJn' + 'ZXRNZXNzYWdlSWQSFAoFZW1vamkYAiABKAlSBWVtb2ppEhYKBnJlbW92ZRgDIAEoCFIGcmVtb3' + 'ZlGr4CCg1NZXNzYWdlVXBkYXRlEjgKBHR5cGUYASABKA4yJC5FbmNyeXB0ZWRDb250ZW50Lk1l' + 'c3NhZ2VVcGRhdGUuVHlwZVIEdHlwZRIvChFzZW5kZXJfbWVzc2FnZV9pZBgCIAEoCUgAUg9zZW' + '5kZXJNZXNzYWdlSWSIAQESPQobbXVsdGlwbGVfdGFyZ2V0X21lc3NhZ2VfaWRzGAMgAygJUhht' + 'dWx0aXBsZVRhcmdldE1lc3NhZ2VJZHMSFwoEdGV4dBgEIAEoCUgBUgR0ZXh0iAEBEhwKCXRpbW' + 'VzdGFtcBgFIAEoA1IJdGltZXN0YW1wIi0KBFR5cGUSCgoGREVMRVRFEAASDQoJRURJVF9URVhU' + 'EAESCgoGT1BFTkVEEAJCFAoSX3NlbmRlcl9tZXNzYWdlX2lkQgcKBV90ZXh0GoUGCgVNZWRpYR' + 'IqChFzZW5kZXJfbWVzc2FnZV9pZBgBIAEoCVIPc2VuZGVyTWVzc2FnZUlkEjAKBHR5cGUYAiAB' + 'KA4yHC5FbmNyeXB0ZWRDb250ZW50Lk1lZGlhLlR5cGVSBHR5cGUSRgodZGlzcGxheV9saW1pdF' + '9pbl9taWxsaXNlY29uZHMYAyABKANIAFIaZGlzcGxheUxpbWl0SW5NaWxsaXNlY29uZHOIAQES' + 'NwoXcmVxdWlyZXNfYXV0aGVudGljYXRpb24YBCABKAhSFnJlcXVpcmVzQXV0aGVudGljYXRpb2' + '4SHAoJdGltZXN0YW1wGAUgASgDUgl0aW1lc3RhbXASLQoQcXVvdGVfbWVzc2FnZV9pZBgGIAEo' + 'CUgBUg5xdW90ZU1lc3NhZ2VJZIgBARIqCg5kb3dubG9hZF90b2tlbhgHIAEoDEgCUg1kb3dubG' + '9hZFRva2VuiAEBEioKDmVuY3J5cHRpb25fa2V5GAggASgMSANSDWVuY3J5cHRpb25LZXmIAQES' + 'KgoOZW5jcnlwdGlvbl9tYWMYCSABKAxIBFINZW5jcnlwdGlvbk1hY4gBARIuChBlbmNyeXB0aW' + '9uX25vbmNlGAogASgMSAVSD2VuY3J5cHRpb25Ob25jZYgBARI7ChdhZGRpdGlvbmFsX21lc3Nh' + 'Z2VfZGF0YRgLIAEoDEgGUhVhZGRpdGlvbmFsTWVzc2FnZURhdGGIAQEiPgoEVHlwZRIMCghSRV' + 'VQTE9BRBAAEgkKBUlNQUdFEAESCQoFVklERU8QAhIHCgNHSUYQAxIJCgVBVURJTxAEQiAKHl9k' + 'aXNwbGF5X2xpbWl0X2luX21pbGxpc2Vjb25kc0ITChFfcXVvdGVfbWVzc2FnZV9pZEIRCg9fZG' + '93bmxvYWRfdG9rZW5CEQoPX2VuY3J5cHRpb25fa2V5QhEKD19lbmNyeXB0aW9uX21hY0ITChFf' + 'ZW5jcnlwdGlvbl9ub25jZUIaChhfYWRkaXRpb25hbF9tZXNzYWdlX2RhdGEaqQEKC01lZGlhVX' + 'BkYXRlEjYKBHR5cGUYASABKA4yIi5FbmNyeXB0ZWRDb250ZW50Lk1lZGlhVXBkYXRlLlR5cGVS' + 'BHR5cGUSKgoRdGFyZ2V0X21lc3NhZ2VfaWQYAiABKAlSD3RhcmdldE1lc3NhZ2VJZCI2CgRUeX' + 'BlEgwKCFJFT1BFTkVEEAASCgoGU1RPUkVEEAESFAoQREVDUllQVElPTl9FUlJPUhACGngKDkNv' + 'bnRhY3RSZXF1ZXN0EjkKBHR5cGUYASABKA4yJS5FbmNyeXB0ZWRDb250ZW50LkNvbnRhY3RSZX' + 'F1ZXN0LlR5cGVSBHR5cGUiKwoEVHlwZRILCgdSRVFVRVNUEAASCgoGUkVKRUNUEAESCgoGQUND' + 'RVBUEAIapAIKDUNvbnRhY3RVcGRhdGUSOAoEdHlwZRgBIAEoDjIkLkVuY3J5cHRlZENvbnRlbn' + 'QuQ29udGFjdFVwZGF0ZS5UeXBlUgR0eXBlEjcKFWF2YXRhcl9zdmdfY29tcHJlc3NlZBgCIAEo' + 'DEgAUhNhdmF0YXJTdmdDb21wcmVzc2VkiAEBEh8KCHVzZXJuYW1lGAMgASgJSAFSCHVzZXJuYW' + '1liAEBEiYKDGRpc3BsYXlfbmFtZRgEIAEoCUgCUgtkaXNwbGF5TmFtZYgBASIfCgRUeXBlEgsK' + 'B1JFUVVFU1QQABIKCgZVUERBVEUQAUIYChZfYXZhdGFyX3N2Z19jb21wcmVzc2VkQgsKCV91c2' + 'VybmFtZUIPCg1fZGlzcGxheV9uYW1lGtkBCghQdXNoS2V5cxIzCgR0eXBlGAEgASgOMh8uRW5j' + 'cnlwdGVkQ29udGVudC5QdXNoS2V5cy5UeXBlUgR0eXBlEhoKBmtleV9pZBgCIAEoA0gAUgVrZX' + 'lJZIgBARIVCgNrZXkYAyABKAxIAVIDa2V5iAEBEiIKCmNyZWF0ZWRfYXQYBCABKANIAlIJY3Jl' + 'YXRlZEF0iAEBIh8KBFR5cGUSCwoHUkVRVUVTVBAAEgoKBlVQREFURRABQgkKB19rZXlfaWRCBg' + 'oEX2tleUINCgtfY3JlYXRlZF9hdBqvAQoJRmxhbWVTeW5jEiMKDWZsYW1lX2NvdW50ZXIYASAB' + 'KANSDGZsYW1lQ291bnRlchI5ChlsYXN0X2ZsYW1lX2NvdW50ZXJfY2hhbmdlGAIgASgDUhZsYX' + 'N0RmxhbWVDb3VudGVyQ2hhbmdlEh8KC2Jlc3RfZnJpZW5kGAMgASgIUgpiZXN0RnJpZW5kEiEK' + 'DGZvcmNlX3VwZGF0ZRgEIAEoCFILZm9yY2VVcGRhdGUaTQoPVHlwaW5nSW5kaWNhdG9yEhsKCW' + 'lzX3R5cGluZxgBIAEoCFIIaXNUeXBpbmcSHQoKY3JlYXRlZF9hdBgCIAEoA1IJY3JlYXRlZEF0' + 'Gj8KFFVzZXJEaXNjb3ZlcnlSZXF1ZXN0EicKD2N1cnJlbnRfdmVyc2lvbhgBIAEoDFIOY3Vycm' + 'VudFZlcnNpb24aMQoTVXNlckRpc2NvdmVyeVVwZGF0ZRIaCghtZXNzYWdlcxgBIAMoDFIIbWVz' + 'c2FnZXNCCwoJX2dyb3VwX2lkQhEKD19pc19kaXJlY3RfY2hhdEIZChdfc2VuZGVyX3Byb2ZpbG' + 'VfY291bnRlckIgCh5fc2VuZGVyX3VzZXJfZGlzY292ZXJ5X3ZlcnNpb25CEQoPX21lc3NhZ2Vf' + 'dXBkYXRlQggKBl9tZWRpYUIPCg1fbWVkaWFfdXBkYXRlQhEKD19jb250YWN0X3VwZGF0ZUISCh' + 'BfY29udGFjdF9yZXF1ZXN0Qg0KC19mbGFtZV9zeW5jQgwKCl9wdXNoX2tleXNCCwoJX3JlYWN0' + 'aW9uQg8KDV90ZXh0X21lc3NhZ2VCDwoNX2dyb3VwX2NyZWF0ZUINCgtfZ3JvdXBfam9pbkIPCg' + '1fZ3JvdXBfdXBkYXRlQhoKGF9yZXNlbmRfZ3JvdXBfcHVibGljX2tleUIRCg9fZXJyb3JfbWVz' + 'c2FnZXNCGgoYX2FkZGl0aW9uYWxfZGF0YV9tZXNzYWdlQhMKEV90eXBpbmdfaW5kaWNhdG9yQh' + 'kKF191c2VyX2Rpc2NvdmVyeV9yZXF1ZXN0QhgKFl91c2VyX2Rpc2NvdmVyeV91cGRhdGU='); diff --git a/lib/src/model/protobuf/client/generated/push_notification.pb.dart b/lib/src/model/protobuf/client/generated/push_notification.pb.dart index 8bff1bb7..f8e4050a 100644 --- a/lib/src/model/protobuf/client/generated/push_notification.pb.dart +++ b/lib/src/model/protobuf/client/generated/push_notification.pb.dart @@ -48,7 +48,7 @@ class EncryptedPushNotification extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( _omitMessageNames ? '' : 'EncryptedPushNotification', createEmptyInstance: create) - ..aInt64(1, _omitFieldNames ? '' : 'keyId', protoName: 'keyId') + ..aInt64(1, _omitFieldNames ? '' : 'keyId') ..a<$core.List<$core.int>>( 2, _omitFieldNames ? '' : 'nonce', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>( @@ -143,12 +143,11 @@ class PushNotification extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'PushNotification', createEmptyInstance: create) ..e(1, _omitFieldNames ? '' : 'kind', $pb.PbFieldType.OE, - defaultOrMaker: PushKind.reaction, + defaultOrMaker: PushKind.REACTION, valueOf: PushKind.valueOf, enumValues: PushKind.values) - ..aOS(2, _omitFieldNames ? '' : 'messageId', protoName: 'messageId') - ..aOS(3, _omitFieldNames ? '' : 'additionalContent', - protoName: 'additionalContent') + ..aOS(2, _omitFieldNames ? '' : 'messageId') + ..aOS(3, _omitFieldNames ? '' : 'additionalContent') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -277,12 +276,12 @@ class PushUser extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( _omitMessageNames ? '' : 'PushUser', createEmptyInstance: create) - ..aInt64(1, _omitFieldNames ? '' : 'userId', protoName: 'userId') - ..aOS(2, _omitFieldNames ? '' : 'displayName', protoName: 'displayName') + ..aInt64(1, _omitFieldNames ? '' : 'userId') + ..aOS(2, _omitFieldNames ? '' : 'displayName') ..aOB(3, _omitFieldNames ? '' : 'blocked') - ..aOS(4, _omitFieldNames ? '' : 'lastMessageId', protoName: 'lastMessageId') + ..aOS(4, _omitFieldNames ? '' : 'lastMessageId') ..pc(5, _omitFieldNames ? '' : 'pushKeys', $pb.PbFieldType.PM, - protoName: 'pushKeys', subBuilder: PushKey.create) + subBuilder: PushKey.create) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -373,8 +372,7 @@ class PushKey extends $pb.GeneratedMessage { ..aInt64(1, _omitFieldNames ? '' : 'id') ..a<$core.List<$core.int>>( 2, _omitFieldNames ? '' : 'key', $pb.PbFieldType.OY) - ..aInt64(3, _omitFieldNames ? '' : 'createdAtUnixTimestamp', - protoName: 'createdAtUnixTimestamp') + ..aInt64(3, _omitFieldNames ? '' : 'createdAtUnixTimestamp') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') diff --git a/lib/src/model/protobuf/client/generated/push_notification.pbenum.dart b/lib/src/model/protobuf/client/generated/push_notification.pbenum.dart index a315a3b8..946b2b19 100644 --- a/lib/src/model/protobuf/client/generated/push_notification.pbenum.dart +++ b/lib/src/model/protobuf/client/generated/push_notification.pbenum.dart @@ -15,54 +15,54 @@ import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; class PushKind extends $pb.ProtobufEnum { - static const PushKind reaction = - PushKind._(0, _omitEnumNames ? '' : 'reaction'); - static const PushKind response = - PushKind._(1, _omitEnumNames ? '' : 'response'); - static const PushKind text = PushKind._(2, _omitEnumNames ? '' : 'text'); - static const PushKind video = PushKind._(3, _omitEnumNames ? '' : 'video'); - static const PushKind twonly = PushKind._(4, _omitEnumNames ? '' : 'twonly'); - static const PushKind image = PushKind._(5, _omitEnumNames ? '' : 'image'); - static const PushKind contactRequest = - PushKind._(6, _omitEnumNames ? '' : 'contactRequest'); - static const PushKind acceptRequest = - PushKind._(7, _omitEnumNames ? '' : 'acceptRequest'); - static const PushKind storedMediaFile = - PushKind._(8, _omitEnumNames ? '' : 'storedMediaFile'); - static const PushKind testNotification = - PushKind._(9, _omitEnumNames ? '' : 'testNotification'); - static const PushKind reopenedMedia = - PushKind._(10, _omitEnumNames ? '' : 'reopenedMedia'); - static const PushKind reactionToVideo = - PushKind._(11, _omitEnumNames ? '' : 'reactionToVideo'); - static const PushKind reactionToText = - PushKind._(12, _omitEnumNames ? '' : 'reactionToText'); - static const PushKind reactionToImage = - PushKind._(13, _omitEnumNames ? '' : 'reactionToImage'); - static const PushKind reactionToAudio = - PushKind._(14, _omitEnumNames ? '' : 'reactionToAudio'); - static const PushKind addedToGroup = - PushKind._(15, _omitEnumNames ? '' : 'addedToGroup'); - static const PushKind audio = PushKind._(16, _omitEnumNames ? '' : 'audio'); + static const PushKind REACTION = + PushKind._(0, _omitEnumNames ? '' : 'REACTION'); + static const PushKind RESPONSE = + PushKind._(1, _omitEnumNames ? '' : 'RESPONSE'); + static const PushKind TEXT = PushKind._(2, _omitEnumNames ? '' : 'TEXT'); + static const PushKind VIDEO = PushKind._(3, _omitEnumNames ? '' : 'VIDEO'); + static const PushKind TWONLY = PushKind._(4, _omitEnumNames ? '' : 'TWONLY'); + static const PushKind IMAGE = PushKind._(5, _omitEnumNames ? '' : 'IMAGE'); + static const PushKind CONTACT_REQUEST = + PushKind._(6, _omitEnumNames ? '' : 'CONTACT_REQUEST'); + static const PushKind ACCEPT_REQUEST = + PushKind._(7, _omitEnumNames ? '' : 'ACCEPT_REQUEST'); + static const PushKind STORED_MEDIA_FILE = + PushKind._(8, _omitEnumNames ? '' : 'STORED_MEDIA_FILE'); + static const PushKind TEST_NOTIFICATION = + PushKind._(9, _omitEnumNames ? '' : 'TEST_NOTIFICATION'); + static const PushKind REOPENED_MEDIA = + PushKind._(10, _omitEnumNames ? '' : 'REOPENED_MEDIA'); + static const PushKind REACTION_TO_VIDEO = + PushKind._(11, _omitEnumNames ? '' : 'REACTION_TO_VIDEO'); + static const PushKind REACTION_TO_TEXT = + PushKind._(12, _omitEnumNames ? '' : 'REACTION_TO_TEXT'); + static const PushKind REACTION_TO_IMAGE = + PushKind._(13, _omitEnumNames ? '' : 'REACTION_TO_IMAGE'); + static const PushKind REACTION_TO_AUDIO = + PushKind._(14, _omitEnumNames ? '' : 'REACTION_TO_AUDIO'); + static const PushKind ADDED_TO_GROUP = + PushKind._(15, _omitEnumNames ? '' : 'ADDED_TO_GROUP'); + static const PushKind AUDIO = PushKind._(16, _omitEnumNames ? '' : 'AUDIO'); static const $core.List values = [ - reaction, - response, - text, - video, - twonly, - image, - contactRequest, - acceptRequest, - storedMediaFile, - testNotification, - reopenedMedia, - reactionToVideo, - reactionToText, - reactionToImage, - reactionToAudio, - addedToGroup, - audio, + REACTION, + RESPONSE, + TEXT, + VIDEO, + TWONLY, + IMAGE, + CONTACT_REQUEST, + ACCEPT_REQUEST, + STORED_MEDIA_FILE, + TEST_NOTIFICATION, + REOPENED_MEDIA, + REACTION_TO_VIDEO, + REACTION_TO_TEXT, + REACTION_TO_IMAGE, + REACTION_TO_AUDIO, + ADDED_TO_GROUP, + AUDIO, ]; static final $core.List _byValue = diff --git a/lib/src/model/protobuf/client/generated/push_notification.pbjson.dart b/lib/src/model/protobuf/client/generated/push_notification.pbjson.dart index d756e6f0..ef250a28 100644 --- a/lib/src/model/protobuf/client/generated/push_notification.pbjson.dart +++ b/lib/src/model/protobuf/client/generated/push_notification.pbjson.dart @@ -18,40 +18,40 @@ import 'dart:typed_data' as $typed_data; const PushKind$json = { '1': 'PushKind', '2': [ - {'1': 'reaction', '2': 0}, - {'1': 'response', '2': 1}, - {'1': 'text', '2': 2}, - {'1': 'video', '2': 3}, - {'1': 'twonly', '2': 4}, - {'1': 'image', '2': 5}, - {'1': 'contactRequest', '2': 6}, - {'1': 'acceptRequest', '2': 7}, - {'1': 'storedMediaFile', '2': 8}, - {'1': 'testNotification', '2': 9}, - {'1': 'reopenedMedia', '2': 10}, - {'1': 'reactionToVideo', '2': 11}, - {'1': 'reactionToText', '2': 12}, - {'1': 'reactionToImage', '2': 13}, - {'1': 'reactionToAudio', '2': 14}, - {'1': 'addedToGroup', '2': 15}, - {'1': 'audio', '2': 16}, + {'1': 'REACTION', '2': 0}, + {'1': 'RESPONSE', '2': 1}, + {'1': 'TEXT', '2': 2}, + {'1': 'VIDEO', '2': 3}, + {'1': 'TWONLY', '2': 4}, + {'1': 'IMAGE', '2': 5}, + {'1': 'CONTACT_REQUEST', '2': 6}, + {'1': 'ACCEPT_REQUEST', '2': 7}, + {'1': 'STORED_MEDIA_FILE', '2': 8}, + {'1': 'TEST_NOTIFICATION', '2': 9}, + {'1': 'REOPENED_MEDIA', '2': 10}, + {'1': 'REACTION_TO_VIDEO', '2': 11}, + {'1': 'REACTION_TO_TEXT', '2': 12}, + {'1': 'REACTION_TO_IMAGE', '2': 13}, + {'1': 'REACTION_TO_AUDIO', '2': 14}, + {'1': 'ADDED_TO_GROUP', '2': 15}, + {'1': 'AUDIO', '2': 16}, ], }; /// Descriptor for `PushKind`. Decode as a `google.protobuf.EnumDescriptorProto`. final $typed_data.Uint8List pushKindDescriptor = $convert.base64Decode( - 'CghQdXNoS2luZBIMCghyZWFjdGlvbhAAEgwKCHJlc3BvbnNlEAESCAoEdGV4dBACEgkKBXZpZG' - 'VvEAMSCgoGdHdvbmx5EAQSCQoFaW1hZ2UQBRISCg5jb250YWN0UmVxdWVzdBAGEhEKDWFjY2Vw' - 'dFJlcXVlc3QQBxITCg9zdG9yZWRNZWRpYUZpbGUQCBIUChB0ZXN0Tm90aWZpY2F0aW9uEAkSEQ' - 'oNcmVvcGVuZWRNZWRpYRAKEhMKD3JlYWN0aW9uVG9WaWRlbxALEhIKDnJlYWN0aW9uVG9UZXh0' - 'EAwSEwoPcmVhY3Rpb25Ub0ltYWdlEA0SEwoPcmVhY3Rpb25Ub0F1ZGlvEA4SEAoMYWRkZWRUb0' - 'dyb3VwEA8SCQoFYXVkaW8QEA=='); + 'CghQdXNoS2luZBIMCghSRUFDVElPThAAEgwKCFJFU1BPTlNFEAESCAoEVEVYVBACEgkKBVZJRE' + 'VPEAMSCgoGVFdPTkxZEAQSCQoFSU1BR0UQBRITCg9DT05UQUNUX1JFUVVFU1QQBhISCg5BQ0NF' + 'UFRfUkVRVUVTVBAHEhUKEVNUT1JFRF9NRURJQV9GSUxFEAgSFQoRVEVTVF9OT1RJRklDQVRJT0' + '4QCRISCg5SRU9QRU5FRF9NRURJQRAKEhUKEVJFQUNUSU9OX1RPX1ZJREVPEAsSFAoQUkVBQ1RJ' + 'T05fVE9fVEVYVBAMEhUKEVJFQUNUSU9OX1RPX0lNQUdFEA0SFQoRUkVBQ1RJT05fVE9fQVVESU' + '8QDhISCg5BRERFRF9UT19HUk9VUBAPEgkKBUFVRElPEBA='); @$core.Deprecated('Use encryptedPushNotificationDescriptor instead') const EncryptedPushNotification$json = { '1': 'EncryptedPushNotification', '2': [ - {'1': 'keyId', '3': 1, '4': 1, '5': 3, '10': 'keyId'}, + {'1': 'key_id', '3': 1, '4': 1, '5': 3, '10': 'keyId'}, {'1': 'nonce', '3': 2, '4': 1, '5': 12, '10': 'nonce'}, {'1': 'ciphertext', '3': 3, '4': 1, '5': 12, '10': 'ciphertext'}, {'1': 'mac', '3': 4, '4': 1, '5': 12, '10': 'mac'}, @@ -60,9 +60,9 @@ const EncryptedPushNotification$json = { /// Descriptor for `EncryptedPushNotification`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List encryptedPushNotificationDescriptor = $convert.base64Decode( - 'ChlFbmNyeXB0ZWRQdXNoTm90aWZpY2F0aW9uEhQKBWtleUlkGAEgASgDUgVrZXlJZBIUCgVub2' - '5jZRgCIAEoDFIFbm9uY2USHgoKY2lwaGVydGV4dBgDIAEoDFIKY2lwaGVydGV4dBIQCgNtYWMY' - 'BCABKAxSA21hYw=='); + 'ChlFbmNyeXB0ZWRQdXNoTm90aWZpY2F0aW9uEhUKBmtleV9pZBgBIAEoA1IFa2V5SWQSFAoFbm' + '9uY2UYAiABKAxSBW5vbmNlEh4KCmNpcGhlcnRleHQYAyABKAxSCmNpcGhlcnRleHQSEAoDbWFj' + 'GAQgASgMUgNtYWM='); @$core.Deprecated('Use pushNotificationDescriptor instead') const PushNotification$json = { @@ -70,7 +70,7 @@ const PushNotification$json = { '2': [ {'1': 'kind', '3': 1, '4': 1, '5': 14, '6': '.PushKind', '10': 'kind'}, { - '1': 'messageId', + '1': 'message_id', '3': 2, '4': 1, '5': 9, @@ -79,7 +79,7 @@ const PushNotification$json = { '17': true }, { - '1': 'additionalContent', + '1': 'additional_content', '3': 3, '4': 1, '5': 9, @@ -89,17 +89,17 @@ const PushNotification$json = { }, ], '8': [ - {'1': '_messageId'}, - {'1': '_additionalContent'}, + {'1': '_message_id'}, + {'1': '_additional_content'}, ], }; /// Descriptor for `PushNotification`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List pushNotificationDescriptor = $convert.base64Decode( - 'ChBQdXNoTm90aWZpY2F0aW9uEh0KBGtpbmQYASABKA4yCS5QdXNoS2luZFIEa2luZBIhCgltZX' - 'NzYWdlSWQYAiABKAlIAFIJbWVzc2FnZUlkiAEBEjEKEWFkZGl0aW9uYWxDb250ZW50GAMgASgJ' - 'SAFSEWFkZGl0aW9uYWxDb250ZW50iAEBQgwKCl9tZXNzYWdlSWRCFAoSX2FkZGl0aW9uYWxDb2' - '50ZW50'); + 'ChBQdXNoTm90aWZpY2F0aW9uEh0KBGtpbmQYASABKA4yCS5QdXNoS2luZFIEa2luZBIiCgptZX' + 'NzYWdlX2lkGAIgASgJSABSCW1lc3NhZ2VJZIgBARIyChJhZGRpdGlvbmFsX2NvbnRlbnQYAyAB' + 'KAlIAVIRYWRkaXRpb25hbENvbnRlbnSIAQFCDQoLX21lc3NhZ2VfaWRCFQoTX2FkZGl0aW9uYW' + 'xfY29udGVudA=='); @$core.Deprecated('Use pushUsersDescriptor instead') const PushUsers$json = { @@ -117,11 +117,11 @@ final $typed_data.Uint8List pushUsersDescriptor = $convert.base64Decode( const PushUser$json = { '1': 'PushUser', '2': [ - {'1': 'userId', '3': 1, '4': 1, '5': 3, '10': 'userId'}, - {'1': 'displayName', '3': 2, '4': 1, '5': 9, '10': 'displayName'}, + {'1': 'user_id', '3': 1, '4': 1, '5': 3, '10': 'userId'}, + {'1': 'display_name', '3': 2, '4': 1, '5': 9, '10': 'displayName'}, {'1': 'blocked', '3': 3, '4': 1, '5': 8, '10': 'blocked'}, { - '1': 'lastMessageId', + '1': 'last_message_id', '3': 4, '4': 1, '5': 9, @@ -130,7 +130,7 @@ const PushUser$json = { '17': true }, { - '1': 'pushKeys', + '1': 'push_keys', '3': 5, '4': 3, '5': 11, @@ -139,16 +139,16 @@ const PushUser$json = { }, ], '8': [ - {'1': '_lastMessageId'}, + {'1': '_last_message_id'}, ], }; /// Descriptor for `PushUser`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List pushUserDescriptor = $convert.base64Decode( - 'CghQdXNoVXNlchIWCgZ1c2VySWQYASABKANSBnVzZXJJZBIgCgtkaXNwbGF5TmFtZRgCIAEoCV' - 'ILZGlzcGxheU5hbWUSGAoHYmxvY2tlZBgDIAEoCFIHYmxvY2tlZBIpCg1sYXN0TWVzc2FnZUlk' - 'GAQgASgJSABSDWxhc3RNZXNzYWdlSWSIAQESJAoIcHVzaEtleXMYBSADKAsyCC5QdXNoS2V5Ug' - 'hwdXNoS2V5c0IQCg5fbGFzdE1lc3NhZ2VJZA=='); + 'CghQdXNoVXNlchIXCgd1c2VyX2lkGAEgASgDUgZ1c2VySWQSIQoMZGlzcGxheV9uYW1lGAIgAS' + 'gJUgtkaXNwbGF5TmFtZRIYCgdibG9ja2VkGAMgASgIUgdibG9ja2VkEisKD2xhc3RfbWVzc2Fn' + 'ZV9pZBgEIAEoCUgAUg1sYXN0TWVzc2FnZUlkiAEBEiUKCXB1c2hfa2V5cxgFIAMoCzIILlB1c2' + 'hLZXlSCHB1c2hLZXlzQhIKEF9sYXN0X21lc3NhZ2VfaWQ='); @$core.Deprecated('Use pushKeyDescriptor instead') const PushKey$json = { @@ -157,7 +157,7 @@ const PushKey$json = { {'1': 'id', '3': 1, '4': 1, '5': 3, '10': 'id'}, {'1': 'key', '3': 2, '4': 1, '5': 12, '10': 'key'}, { - '1': 'createdAtUnixTimestamp', + '1': 'created_at_unix_timestamp', '3': 3, '4': 1, '5': 3, @@ -168,5 +168,5 @@ const PushKey$json = { /// Descriptor for `PushKey`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List pushKeyDescriptor = $convert.base64Decode( - 'CgdQdXNoS2V5Eg4KAmlkGAEgASgDUgJpZBIQCgNrZXkYAiABKAxSA2tleRI2ChZjcmVhdGVkQX' - 'RVbml4VGltZXN0YW1wGAMgASgDUhZjcmVhdGVkQXRVbml4VGltZXN0YW1w'); + 'CgdQdXNoS2V5Eg4KAmlkGAEgASgDUgJpZBIQCgNrZXkYAiABKAxSA2tleRI5ChljcmVhdGVkX2' + 'F0X3VuaXhfdGltZXN0YW1wGAMgASgDUhZjcmVhdGVkQXRVbml4VGltZXN0YW1w'); diff --git a/lib/src/model/protobuf/client/generated/qr.pb.dart b/lib/src/model/protobuf/client/generated/qr.pb.dart index f4e4cfa9..284eecd1 100644 --- a/lib/src/model/protobuf/client/generated/qr.pb.dart +++ b/lib/src/model/protobuf/client/generated/qr.pb.dart @@ -45,7 +45,7 @@ class QREnvelope extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'QREnvelope', createEmptyInstance: create) ..e(2, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, - defaultOrMaker: QREnvelope_Type.PublicProfile, + defaultOrMaker: QREnvelope_Type.PUBLIC_PROFILE, valueOf: QREnvelope_Type.valueOf, enumValues: QREnvelope_Type.values) ..a<$core.List<$core.int>>( diff --git a/lib/src/model/protobuf/client/generated/qr.pbenum.dart b/lib/src/model/protobuf/client/generated/qr.pbenum.dart index ea18fd02..711781ce 100644 --- a/lib/src/model/protobuf/client/generated/qr.pbenum.dart +++ b/lib/src/model/protobuf/client/generated/qr.pbenum.dart @@ -15,11 +15,11 @@ import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; class QREnvelope_Type extends $pb.ProtobufEnum { - static const QREnvelope_Type PublicProfile = - QREnvelope_Type._(0, _omitEnumNames ? '' : 'PublicProfile'); + static const QREnvelope_Type PUBLIC_PROFILE = + QREnvelope_Type._(0, _omitEnumNames ? '' : 'PUBLIC_PROFILE'); static const $core.List values = [ - PublicProfile, + PUBLIC_PROFILE, ]; static final $core.List _byValue = diff --git a/lib/src/model/protobuf/client/generated/qr.pbjson.dart b/lib/src/model/protobuf/client/generated/qr.pbjson.dart index 40bc65e4..2d9d1da5 100644 --- a/lib/src/model/protobuf/client/generated/qr.pbjson.dart +++ b/lib/src/model/protobuf/client/generated/qr.pbjson.dart @@ -35,14 +35,14 @@ const QREnvelope$json = { const QREnvelope_Type$json = { '1': 'Type', '2': [ - {'1': 'PublicProfile', '2': 0}, + {'1': 'PUBLIC_PROFILE', '2': 0}, ], }; /// Descriptor for `QREnvelope`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List qREnvelopeDescriptor = $convert.base64Decode( 'CgpRUkVudmVsb3BlEiQKBHR5cGUYAiABKA4yEC5RUkVudmVsb3BlLlR5cGVSBHR5cGUSEgoEZG' - 'F0YRgDIAEoDFIEZGF0YSIZCgRUeXBlEhEKDVB1YmxpY1Byb2ZpbGUQAA=='); + 'F0YRgDIAEoDFIEZGF0YSIaCgRUeXBlEhIKDlBVQkxJQ19QUk9GSUxFEAA='); @$core.Deprecated('Use publicProfileDescriptor instead') const PublicProfile$json = { diff --git a/lib/src/model/protobuf/client/groups.proto b/lib/src/model/protobuf/client/groups.proto index 268ad1f6..d4e370d5 100644 --- a/lib/src/model/protobuf/client/groups.proto +++ b/lib/src/model/protobuf/client/groups.proto @@ -2,22 +2,22 @@ syntax = "proto3"; // Stored encrypted on the server in the members columns. message EncryptedGroupState { - repeated int64 memberIds = 1; - repeated int64 adminIds = 2; - string groupName = 3; - optional int64 deleteMessagesAfterMilliseconds = 4; - bytes padding = 5; + repeated int64 member_ids = 1; + repeated int64 admin_ids = 2; + string group_name = 3; + optional int64 delete_messages_after_milliseconds = 4; + bytes padding = 5; } message EncryptedAppendedGroupState { - enum Type { - LEFT_GROUP = 0; - } - Type type = 1; + enum Type { + LEFT_GROUP = 0; + } + Type type = 1; } message EncryptedGroupStateEnvelop { - bytes nonce = 1; - bytes encryptedGroupState = 2; - bytes mac = 3; + bytes nonce = 1; + bytes encrypted_group_state = 2; + bytes mac = 3; } \ No newline at end of file diff --git a/lib/src/model/protobuf/client/messages.proto b/lib/src/model/protobuf/client/messages.proto index 9ac0f291..c3303c5a 100644 --- a/lib/src/model/protobuf/client/messages.proto +++ b/lib/src/model/protobuf/client/messages.proto @@ -1,203 +1,212 @@ syntax = "proto3"; message Message { - enum Type { - SENDER_DELIVERY_RECEIPT = 0; - PLAINTEXT_CONTENT = 1; - CIPHERTEXT = 2; - PREKEY_BUNDLE = 3; - TEST_NOTIFICATION = 4; - } - Type type = 1; - string receiptId = 2; - optional bytes encryptedContent = 3; - optional PlaintextContent plaintextContent = 4; + enum Type { + SENDER_DELIVERY_RECEIPT = 0; + PLAINTEXT_CONTENT = 1; + CIPHERTEXT = 2; + PREKEY_BUNDLE = 3; + TEST_NOTIFICATION = 4; + } + Type type = 1; + string receipt_id = 2; + optional bytes encrypted_content = 3; + optional PlaintextContent plaintext_content = 4; } message PlaintextContent { - optional DecryptionErrorMessage decryptionErrorMessage = 1; - optional RetryErrorMessage retryControlError = 2; + optional DecryptionErrorMessage decryption_error_message = 1; + optional RetryErrorMessage retry_control_error = 2; - message RetryErrorMessage { } + message RetryErrorMessage { } - message DecryptionErrorMessage { - enum Type { - UNKNOWN = 0; - PREKEY_UNKNOWN = 1; - } - Type type = 1; + message DecryptionErrorMessage { + enum Type { + UNKNOWN = 0; + PREKEY_UNKNOWN = 1; } + Type type = 1; + } } - message EncryptedContent { - optional string groupId = 2; - optional bool isDirectChat = 3; + optional string group_id = 2; + optional bool is_direct_chat = 3; /// This can be added, so the receiver can check weather he is up to date with the current profile - optional int64 senderProfileCounter = 4; + optional int64 sender_profile_counter = 4; + optional bytes sender_user_discovery_version = 21; - optional MessageUpdate messageUpdate = 5; - optional Media media = 6; - optional MediaUpdate mediaUpdate = 7; - optional ContactUpdate contactUpdate = 8; - optional ContactRequest contactRequest = 9; - optional FlameSync flameSync = 10; - optional PushKeys pushKeys = 11; - optional Reaction reaction = 12; - optional TextMessage textMessage = 13; - optional GroupCreate groupCreate = 14; - optional GroupJoin groupJoin = 15; - optional GroupUpdate groupUpdate = 16; - optional ResendGroupPublicKey resendGroupPublicKey = 17; - optional ErrorMessages error_messages = 18; - optional AdditionalDataMessage additional_data_message = 19; - optional TypingIndicator typing_indicator = 20; + optional MessageUpdate message_update = 5; + optional Media media = 6; + optional MediaUpdate media_update = 7; + optional ContactUpdate contact_update = 8; + optional ContactRequest contact_request = 9; + optional FlameSync flame_sync = 10; + optional PushKeys push_keys = 11; + optional Reaction reaction = 12; + optional TextMessage text_message = 13; + optional GroupCreate group_create = 14; + optional GroupJoin group_join = 15; + optional GroupUpdate group_update = 16; + optional ResendGroupPublicKey resend_group_public_key = 17; + optional ErrorMessages error_messages = 18; + optional AdditionalDataMessage additional_data_message = 19; + optional TypingIndicator typing_indicator = 20; + optional UserDiscoveryRequest user_discovery_request = 22; + optional UserDiscoveryUpdate user_discovery_update = 23; - message ErrorMessages { - enum Type { - ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD = 0; - UNKNOWN_MESSAGE_TYPE = 2; - SESSION_OUT_OF_SYNC = 3; - } - Type type = 1; - string related_receipt_id = 2; + message ErrorMessages { + enum Type { + ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD = 0; + UNKNOWN_MESSAGE_TYPE = 2; + SESSION_OUT_OF_SYNC = 3; } + Type type = 1; + string related_receipt_id = 2; + } + message GroupCreate { + // key for the state stored on the server + bytes state_key = 3; + bytes group_public_key = 4; + } - message GroupCreate { + message GroupJoin { // key for the state stored on the server - bytes stateKey = 3; - bytes groupPublicKey = 4; + bytes group_public_key = 1; + } + + message ResendGroupPublicKey { + + } + + message GroupUpdate { + string group_action_type = 1; // GroupActionType.name + optional int64 affected_contact_id = 2; + optional string new_group_name = 3; + optional int64 new_delete_messages_after_milliseconds = 4; + } + + message TextMessage { + string sender_message_id = 1; + string text = 2; + int64 timestamp = 3; + optional string quote_message_id = 4; + } + + message AdditionalDataMessage { + string sender_message_id = 1; + int64 timestamp = 2; + string type = 3; + optional bytes additional_message_data = 4; + } + + message Reaction { + string target_message_id = 1; + string emoji = 2; + bool remove = 3; + } + + message MessageUpdate { + enum Type { + DELETE = 0; + EDIT_TEXT = 1; + OPENED = 2; + } + Type type = 1; + optional string sender_message_id = 2; + repeated string multiple_target_message_ids = 3; + optional string text = 4; + int64 timestamp = 5; + } + + message Media { + enum Type { + REUPLOAD = 0; + IMAGE = 1; + VIDEO = 2; + GIF = 3; + AUDIO = 4; } - message GroupJoin { - // key for the state stored on the server - bytes groupPublicKey = 1; + string sender_message_id = 1; + Type type = 2; + optional int64 display_limit_in_milliseconds = 3; + bool requires_authentication = 4; + int64 timestamp = 5; + optional string quote_message_id = 6; + + optional bytes download_token = 7; + optional bytes encryption_key = 8; + optional bytes encryption_mac = 9; + optional bytes encryption_nonce = 10; + + optional bytes additional_message_data = 11; + } + + message MediaUpdate { + enum Type { + REOPENED = 0; + STORED = 1; + DECRYPTION_ERROR = 2; + } + Type type = 1; + string target_message_id = 2; + } + + message ContactRequest { + enum Type { + REQUEST = 0; + REJECT = 1; + ACCEPT = 2; + } + Type type = 1; + } + + message ContactUpdate { + enum Type { + REQUEST = 0; + UPDATE = 1; } - message ResendGroupPublicKey { + Type type = 1; + optional bytes avatar_svg_compressed = 2; + optional string username = 3; + optional string display_name = 4; + } + message PushKeys { + enum Type { + REQUEST = 0; + UPDATE = 1; } - message GroupUpdate { - string groupActionType = 1; // GroupActionType.name - optional int64 affectedContactId = 2; - optional string newGroupName = 3; - optional int64 newDeleteMessagesAfterMilliseconds = 4; - } + Type type = 1; + optional int64 key_id = 2; + optional bytes key = 3; + optional int64 created_at = 4; + } - message TextMessage { - string senderMessageId = 1; - string text = 2; - int64 timestamp = 3; - optional string quoteMessageId = 4; - } + message FlameSync { + int64 flame_counter = 1; + int64 last_flame_counter_change = 2; + bool best_friend = 3; + bool force_update = 4; + } - message AdditionalDataMessage { - string sender_message_id = 1; - int64 timestamp = 2; - string type = 3; - optional bytes additional_message_data = 4; - } + message TypingIndicator { + bool is_typing = 1; + int64 created_at = 2; + } - message Reaction { - string targetMessageId = 1; - string emoji = 2; - bool remove = 3; - } + message UserDiscoveryRequest { + bytes current_version = 1; + } - message MessageUpdate { - enum Type { - DELETE = 0; - EDIT_TEXT = 1; - OPENED = 2; - } - Type type = 1; - optional string senderMessageId = 2; - repeated string multipleTargetMessageIds = 3; - optional string text = 4; - int64 timestamp = 5; - } - - message Media { - enum Type { - REUPLOAD = 0; - IMAGE = 1; - VIDEO = 2; - GIF = 3; - AUDIO = 4; - } - - string senderMessageId = 1; - Type type = 2; - optional int64 displayLimitInMilliseconds = 3; - bool requiresAuthentication = 4; - int64 timestamp = 5; - optional string quoteMessageId = 6; - - optional bytes downloadToken = 7; - optional bytes encryptionKey = 8; - optional bytes encryptionMac = 9; - optional bytes encryptionNonce = 10; - - optional bytes additional_message_data = 11; - } - - message MediaUpdate { - enum Type { - REOPENED = 0; - STORED = 1; - DECRYPTION_ERROR = 2; - } - Type type = 1; - string targetMessageId = 2; - } - - message ContactRequest { - enum Type { - REQUEST = 0; - REJECT = 1; - ACCEPT = 2; - } - Type type = 1; - } - - message ContactUpdate { - enum Type { - REQUEST = 0; - UPDATE = 1; - } - - Type type = 1; - optional bytes avatarSvgCompressed = 2; - optional string username = 3; - optional string displayName = 4; - } - - message PushKeys { - enum Type { - REQUEST = 0; - UPDATE = 1; - } - - Type type = 1; - optional int64 keyId = 2; - optional bytes key = 3; - optional int64 createdAt = 4; - } - - message FlameSync { - int64 flameCounter = 1; - int64 lastFlameCounterChange = 2; - bool bestFriend = 3; - bool forceUpdate = 4; - } - - message TypingIndicator { - bool is_typing = 1; - int64 created_at = 2; - } + message UserDiscoveryUpdate { + repeated bytes messages = 1; + } } \ No newline at end of file diff --git a/lib/src/model/protobuf/client/push_notification.proto b/lib/src/model/protobuf/client/push_notification.proto index 5e74e9c4..61b0bc09 100644 --- a/lib/src/model/protobuf/client/push_notification.proto +++ b/lib/src/model/protobuf/client/push_notification.proto @@ -1,53 +1,52 @@ syntax = "proto3"; message EncryptedPushNotification { - int64 keyId = 1; - bytes nonce = 2; - bytes ciphertext = 3; - bytes mac = 4; + int64 key_id = 1; + bytes nonce = 2; + bytes ciphertext = 3; + bytes mac = 4; } enum PushKind { - reaction = 0; - response = 1; - text = 2; - video = 3; - twonly = 4; - image = 5; - contactRequest = 6; - acceptRequest = 7; - storedMediaFile = 8; - testNotification = 9; - reopenedMedia = 10; - reactionToVideo = 11; - reactionToText = 12; - reactionToImage = 13; - reactionToAudio = 14; - addedToGroup = 15; - audio = 16; + REACTION = 0; + RESPONSE = 1; + TEXT = 2; + VIDEO = 3; + TWONLY = 4; + IMAGE = 5; + CONTACT_REQUEST = 6; + ACCEPT_REQUEST = 7; + STORED_MEDIA_FILE = 8; + TEST_NOTIFICATION = 9; + REOPENED_MEDIA = 10; + REACTION_TO_VIDEO = 11; + REACTION_TO_TEXT = 12; + REACTION_TO_IMAGE = 13; + REACTION_TO_AUDIO = 14; + ADDED_TO_GROUP = 15; + AUDIO = 16; }; message PushNotification { - PushKind kind = 1; - optional string messageId = 2; - optional string additionalContent = 3; + PushKind kind = 1; + optional string message_id = 2; + optional string additional_content = 3; } - message PushUsers { - repeated PushUser users = 1; + repeated PushUser users = 1; } message PushUser { - int64 userId = 1; - string displayName = 2; - bool blocked = 3; - optional string lastMessageId = 4; - repeated PushKey pushKeys = 5; + int64 user_id = 1; + string display_name = 2; + bool blocked = 3; + optional string last_message_id = 4; + repeated PushKey push_keys = 5; } message PushKey { - int64 id = 1; - bytes key = 2; - int64 createdAtUnixTimestamp = 3; + int64 id = 1; + bytes key = 2; + int64 created_at_unix_timestamp = 3; } \ No newline at end of file diff --git a/lib/src/model/protobuf/client/qr.proto b/lib/src/model/protobuf/client/qr.proto index 29440b9e..3024c87b 100644 --- a/lib/src/model/protobuf/client/qr.proto +++ b/lib/src/model/protobuf/client/qr.proto @@ -1,19 +1,19 @@ syntax = "proto3"; message QREnvelope { - enum Type { - PublicProfile = 0; - } - Type type = 2; - bytes data = 3; + enum Type { + PUBLIC_PROFILE = 0; + } + Type type = 2; + bytes data = 3; } message PublicProfile { - int64 user_id = 1; - string username = 2; - bytes public_identity_key = 3; - bytes signed_prekey = 4; - int64 registration_id = 5; - bytes signed_prekey_signature = 6; - int64 signed_prekey_id = 7; + int64 user_id = 1; + string username = 2; + bytes public_identity_key = 3; + bytes signed_prekey = 4; + int64 registration_id = 5; + bytes signed_prekey_signature = 6; + int64 signed_prekey_id = 7; } diff --git a/lib/src/services/api/messages.dart b/lib/src/services/api/messages.dart index 07865ec6..a85dcca9 100644 --- a/lib/src/services/api/messages.dart +++ b/lib/src/services/api/messages.dart @@ -120,7 +120,7 @@ Future<(Uint8List, Uint8List?)?> tryToSendCompleteMessage({ } if (message.type == pb.Message_Type.TEST_NOTIFICATION) { - pushData = (PushNotification()..kind = PushKind.testNotification) + pushData = (PushNotification()..kind = PushKind.TEST_NOTIFICATION) .writeToBuffer(); } diff --git a/lib/src/services/notifications/background.notifications.dart b/lib/src/services/notifications/background.notifications.dart index 50d78206..52b5c7e8 100644 --- a/lib/src/services/notifications/background.notifications.dart +++ b/lib/src/services/notifications/background.notifications.dart @@ -100,7 +100,7 @@ Future handlePushData(String pushDataB64) async { } if (pushNotification != null) { - if (pushNotification.kind == PushKind.testNotification) { + if (pushNotification.kind == PushKind.TEST_NOTIFICATION) { await customLocalPushNotification( 'Test notification', 'This is a test notification.', @@ -206,13 +206,13 @@ Future showLocalPushNotification( String? payload; if (groupId != null && - (pushNotification.kind == PushKind.text || - pushNotification.kind == PushKind.response || - pushNotification.kind == PushKind.reactionToAudio || - pushNotification.kind == PushKind.storedMediaFile || - pushNotification.kind == PushKind.reactionToImage || - pushNotification.kind == PushKind.reactionToText || - pushNotification.kind == PushKind.reactionToAudio)) { + (pushNotification.kind == PushKind.TEXT || + pushNotification.kind == PushKind.RESPONSE || + pushNotification.kind == PushKind.REACTION_TO_AUDIO || + pushNotification.kind == PushKind.STORED_MEDIA_FILE || + pushNotification.kind == PushKind.REACTION_TO_IMAGE || + pushNotification.kind == PushKind.REACTION_TO_TEXT || + pushNotification.kind == PushKind.REACTION_TO_VIDEO)) { payload = Routes.chatsMessages(groupId); } @@ -234,7 +234,7 @@ Future showLocalPushNotificationWithoutUserId( var title = lang.notificationTitleUnknown; var body = lang.notificationBodyUnknown; - if (pushNotification.kind == PushKind.contactRequest) { + if (pushNotification.kind == PushKind.CONTACT_REQUEST) { title = lang.you; body = lang.notificationContactRequestUnknownUser; } @@ -291,30 +291,30 @@ String getPushNotificationText(PushNotification pushNotification) { } final pushNotificationText = { - PushKind.text.name: lang.notificationText(inGroup), - PushKind.twonly.name: lang.notificationTwonly(inGroup), - PushKind.video.name: lang.notificationVideo(inGroup), - PushKind.image.name: lang.notificationImage(inGroup), - PushKind.audio.name: lang.notificationAudio(inGroup), - PushKind.contactRequest.name: lang.notificationContactRequest, - PushKind.acceptRequest.name: lang.notificationAcceptRequest, - PushKind.storedMediaFile.name: lang.notificationStoredMediaFile, - PushKind.reaction.name: lang.notificationReaction, - PushKind.reopenedMedia.name: lang.notificationReopenedMedia, - PushKind.reactionToVideo.name: lang.notificationReactionToVideo( + PushKind.TEXT.name: lang.notificationText(inGroup), + PushKind.TWONLY.name: lang.notificationTwonly(inGroup), + PushKind.VIDEO.name: lang.notificationVideo(inGroup), + PushKind.IMAGE.name: lang.notificationImage(inGroup), + PushKind.AUDIO.name: lang.notificationAudio(inGroup), + PushKind.CONTACT_REQUEST.name: lang.notificationContactRequest, + PushKind.ACCEPT_REQUEST.name: lang.notificationAcceptRequest, + PushKind.STORED_MEDIA_FILE.name: lang.notificationStoredMediaFile, + PushKind.REACTION.name: lang.notificationReaction, + PushKind.REOPENED_MEDIA.name: lang.notificationReopenedMedia, + PushKind.REACTION_TO_VIDEO.name: lang.notificationReactionToVideo( pushNotification.additionalContent, ), - PushKind.reactionToAudio.name: lang.notificationReactionToAudio( + PushKind.REACTION_TO_AUDIO.name: lang.notificationReactionToAudio( pushNotification.additionalContent, ), - PushKind.reactionToText.name: lang.notificationReactionToText( + PushKind.REACTION_TO_TEXT.name: lang.notificationReactionToText( pushNotification.additionalContent, ), - PushKind.reactionToImage.name: lang.notificationReactionToImage( + PushKind.REACTION_TO_IMAGE.name: lang.notificationReactionToImage( pushNotification.additionalContent, ), - PushKind.response.name: lang.notificationResponse(inGroup), - PushKind.addedToGroup.name: lang.notificationAddedToGroup( + PushKind.RESPONSE.name: lang.notificationResponse(inGroup), + PushKind.ADDED_TO_GROUP.name: lang.notificationAddedToGroup( pushNotification.additionalContent, ), }; diff --git a/lib/src/services/notifications/pushkeys.notifications.dart b/lib/src/services/notifications/pushkeys.notifications.dart index 4d00549e..a9ce4e13 100644 --- a/lib/src/services/notifications/pushkeys.notifications.dart +++ b/lib/src/services/notifications/pushkeys.notifications.dart @@ -216,28 +216,28 @@ Future getPushNotificationFromEncryptedContent( return null; } if (msg.content != null) { - kind = PushKind.reactionToText; + kind = PushKind.REACTION_TO_TEXT; } else if (msg.mediaId != null) { final media = await twonlyDB.mediaFilesDao.getMediaFileById(msg.mediaId!); if (media == null) return null; switch (media.type) { case MediaType.image: - kind = PushKind.reactionToImage; + kind = PushKind.REACTION_TO_IMAGE; case MediaType.audio: - kind = PushKind.reactionToAudio; + kind = PushKind.REACTION_TO_AUDIO; case MediaType.video: - kind = PushKind.reactionToVideo; + kind = PushKind.REACTION_TO_VIDEO; case MediaType.gif: - kind = PushKind.reaction; + kind = PushKind.REACTION; } } additionalContent = content.reaction.emoji; } if (content.hasTextMessage()) { - kind = PushKind.text; + kind = PushKind.TEXT; if (content.textMessage.hasQuoteMessageId()) { - kind = PushKind.response; + kind = PushKind.RESPONSE; } final group = await twonlyDB.groupsDao.getGroup(content.groupId); if (group != null && !group.isDirectChat) { @@ -246,7 +246,7 @@ Future getPushNotificationFromEncryptedContent( } if (content.hasAdditionalDataMessage()) { - kind = PushKind.text; + kind = PushKind.TEXT; } if (content.hasMedia()) { @@ -254,16 +254,16 @@ Future getPushNotificationFromEncryptedContent( case EncryptedContent_Media_Type.REUPLOAD: return null; case EncryptedContent_Media_Type.IMAGE: - kind = PushKind.image; + kind = PushKind.IMAGE; case EncryptedContent_Media_Type.VIDEO: - kind = PushKind.video; + kind = PushKind.VIDEO; case EncryptedContent_Media_Type.GIF: - kind = PushKind.image; + kind = PushKind.IMAGE; case EncryptedContent_Media_Type.AUDIO: - kind = PushKind.audio; + kind = PushKind.AUDIO; } if (content.media.requiresAuthentication) { - kind = PushKind.twonly; + kind = PushKind.TWONLY; } final group = await twonlyDB.groupsDao.getGroup(content.groupId); if (group != null && !group.isDirectChat) { @@ -274,9 +274,9 @@ Future getPushNotificationFromEncryptedContent( if (content.hasContactRequest()) { switch (content.contactRequest.type) { case EncryptedContent_ContactRequest_Type.REQUEST: - kind = PushKind.contactRequest; + kind = PushKind.CONTACT_REQUEST; case EncryptedContent_ContactRequest_Type.ACCEPT: - kind = PushKind.acceptRequest; + kind = PushKind.ACCEPT_REQUEST; case EncryptedContent_ContactRequest_Type.REJECT: return null; } @@ -292,16 +292,16 @@ Future getPushNotificationFromEncryptedContent( } switch (content.mediaUpdate.type) { case EncryptedContent_MediaUpdate_Type.REOPENED: - kind = PushKind.reopenedMedia; + kind = PushKind.REOPENED_MEDIA; case EncryptedContent_MediaUpdate_Type.STORED: - kind = PushKind.storedMediaFile; + kind = PushKind.STORED_MEDIA_FILE; case EncryptedContent_MediaUpdate_Type.DECRYPTION_ERROR: return null; } } if (content.hasGroupCreate()) { - kind = PushKind.addedToGroup; + kind = PushKind.ADDED_TO_GROUP; final group = await twonlyDB.groupsDao.getGroup(content.groupId); additionalContent = group!.groupName; } @@ -344,9 +344,9 @@ Future encryptPushNotification( // user does not have send any push keys // only allow accept request and contact request to be send in an insecure way :/ // In future find a better way, e.g. use the signal protocol in a native way.. - if (content.kind != PushKind.acceptRequest && - content.kind != PushKind.contactRequest && - content.kind != PushKind.testNotification) { + if (content.kind != PushKind.ACCEPT_REQUEST && + content.kind != PushKind.CONTACT_REQUEST && + content.kind != PushKind.TEST_NOTIFICATION) { // this will be enforced after every app uses this system... :/ // return null; Log.warn('Using insecure key as the receiver does not send a push key!'); diff --git a/lib/src/utils/qr.dart b/lib/src/utils/qr.dart index 87b98ef2..ceb6c401 100644 --- a/lib/src/utils/qr.dart +++ b/lib/src/utils/qr.dart @@ -31,7 +31,7 @@ Future getProfileQrCodeData() async { final data = publicProfile.writeToBuffer(); final qrEnvelope = QREnvelope( - type: QREnvelope_Type.PublicProfile, + type: QREnvelope_Type.PUBLIC_PROFILE, data: data, ); @@ -47,7 +47,7 @@ Future getUserPublicKey() async { PublicProfile? parseQrCodeData(Uint8List rawBytes) { try { final envelop = QREnvelope.fromBuffer(rawBytes); - if (envelop.type == QREnvelope_Type.PublicProfile) { + if (envelop.type == QREnvelope_Type.PUBLIC_PROFILE) { return PublicProfile.fromBuffer(envelop.data); } } catch (e) { diff --git a/lib/src/views/settings/notification.view.dart b/lib/src/views/settings/notification.view.dart index 4319afaa..b1f1164a 100644 --- a/lib/src/views/settings/notification.view.dart +++ b/lib/src/views/settings/notification.view.dart @@ -61,7 +61,7 @@ class _NotificationViewState extends State { user.userId, PushNotification( messageId: uuid.v4(), - kind: PushKind.testNotification, + kind: PushKind.TEST_NOTIFICATION, ), ); await apiService.sendTextMessage( From f2493a2b5680c2e3ca2df1128d17c654a1b89701 Mon Sep 17 00:00:00 2001 From: otsmr Date: Mon, 20 Apr 2026 01:13:11 +0200 Subject: [PATCH 15/86] handling server messages --- ...simple_test.dart => api_service.test.dart} | 9 +- lib/core/bridge/wrapper/user_discovery.dart | 6 +- lib/core/frb_generated.dart | 18 +- .../callbacks/user_discovery.callbacks.dart | 8 +- lib/src/database/daos/user_discovery.dao.dart | 86 + .../schemas/twonly_db/drift_schema_v14.json | 2713 +++++ .../database/tables/user_discovery.table.dart | 7 + lib/src/database/twonly.db.dart | 16 +- lib/src/database/twonly.db.g.dart | 217 +- lib/src/database/twonly.db.steps.dart | 456 + .../generated/app_localizations.dart | 6 + .../generated/app_localizations_de.dart | 3 + .../generated/app_localizations_en.dart | 3 + .../generated/app_localizations_sv.dart | 3 + lib/src/services/api.service.dart | 4 + .../api/client2client/user_discovery.c2c.dart | 78 + lib/src/services/api/messages.dart | 12 + lib/src/services/api/server_messages.dart | 23 + lib/src/services/user_discovery.service.dart | 78 +- lib/src/views/chats/add_new_user.view.dart | 16 +- lib/src/views/chats/chat_list.view.dart | 70 +- rust/src/bridge/wrapper/user_discovery.rs | 12 +- rust/src/frb_generated.rs | 10 +- .../protocols/src/user_discovery.rs | 13 +- .../protocols/src/user_discovery/tests.rs | 11 +- test/drift/twonly_db/generated/schema.dart | 5 +- .../drift/twonly_db/generated/schema_v14.dart | 9556 +++++++++++++++++ 27 files changed, 13369 insertions(+), 70 deletions(-) rename integration_test/{simple_test.dart => api_service.test.dart} (55%) create mode 100644 lib/src/database/schemas/twonly_db/drift_schema_v14.json create mode 100644 lib/src/services/api/client2client/user_discovery.c2c.dart create mode 100644 test/drift/twonly_db/generated/schema_v14.dart diff --git a/integration_test/simple_test.dart b/integration_test/api_service.test.dart similarity index 55% rename from integration_test/simple_test.dart rename to integration_test/api_service.test.dart index 2923b76c..91f780ed 100644 --- a/integration_test/simple_test.dart +++ b/integration_test/api_service.test.dart @@ -1,13 +1,12 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:twonly/core/frb_generated.dart'; -import 'package:twonly/main.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); setUpAll(() async => RustLib.init()); - testWidgets('Can call rust function', (tester) async { - await tester.pumpWidget(const MyApp()); - expect(find.textContaining('Result: `Hello, Tom!`'), findsOneWidget); - }); + // testWidgets('Can call rust function', (tester) async { + // await tester.pumpWidget(const MyApp()); + // expect(find.textContaining('Result: `Hello, Tom!`'), findsOneWidget); + // }); } diff --git a/lib/core/bridge/wrapper/user_discovery.dart b/lib/core/bridge/wrapper/user_discovery.dart index b4d4edf3..48dde562 100644 --- a/lib/core/bridge/wrapper/user_discovery.dart +++ b/lib/core/bridge/wrapper/user_discovery.dart @@ -22,11 +22,11 @@ class FlutterUserDiscovery { receivedVersion: receivedVersion, ); - static Future handleUserDiscoveryMessages({ + static Future handleNewMessages({ required PlatformInt64 contactId, required List messages, }) => RustLib.instance.api - .crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleUserDiscoveryMessages( + .crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleNewMessages( contactId: contactId, messages: messages, ); @@ -42,7 +42,7 @@ class FlutterUserDiscovery { publicKey: publicKey, ); - static Future shouldRequestNewMessages({ + static Future shouldRequestNewMessages({ required PlatformInt64 contactId, required List version, }) => RustLib.instance.api diff --git a/lib/core/frb_generated.dart b/lib/core/frb_generated.dart index a1248a9a..50a36415 100644 --- a/lib/core/frb_generated.dart +++ b/lib/core/frb_generated.dart @@ -71,7 +71,7 @@ class RustLib extends BaseEntrypoint { String get codegenVersion => '2.12.0'; @override - int get rustContentHash => 523281685; + int get rustContentHash => -630534473; static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig( @@ -92,7 +92,7 @@ abstract class RustLibApi extends BaseApi { }); Future - crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleUserDiscoveryMessages({ + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleNewMessages({ required PlatformInt64 contactId, required List messages, }); @@ -104,7 +104,7 @@ abstract class RustLibApi extends BaseApi { required List publicKey, }); - Future + Future crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryShouldRequestNewMessages({ required PlatformInt64 contactId, required List version, @@ -228,7 +228,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { @override Future - crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleUserDiscoveryMessages({ + crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleNewMessages({ required PlatformInt64 contactId, required List messages, }) { @@ -250,7 +250,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { decodeErrorData: sse_decode_AnyhowException, ), constMeta: - kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleUserDiscoveryMessagesConstMeta, + kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleNewMessagesConstMeta, argValues: [contactId, messages], apiImpl: this, ), @@ -258,9 +258,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } TaskConstMeta - get kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleUserDiscoveryMessagesConstMeta => + get kCrateBridgeWrapperUserDiscoveryFlutterUserDiscoveryHandleNewMessagesConstMeta => const TaskConstMeta( - debugName: 'flutter_user_discovery_handle_user_discovery_messages', + debugName: 'flutter_user_discovery_handle_new_messages', argNames: ['contactId', 'messages'], ); @@ -305,7 +305,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); @override - Future + Future crateBridgeWrapperUserDiscoveryFlutterUserDiscoveryShouldRequestNewMessages({ required PlatformInt64 contactId, required List version, @@ -324,7 +324,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); }, codec: SseCodec( - decodeSuccessData: sse_decode_bool, + decodeSuccessData: sse_decode_opt_list_prim_u_8_strict, decodeErrorData: sse_decode_AnyhowException, ), constMeta: diff --git a/lib/src/callbacks/user_discovery.callbacks.dart b/lib/src/callbacks/user_discovery.callbacks.dart index 8d4964db..73af1d1c 100644 --- a/lib/src/callbacks/user_discovery.callbacks.dart +++ b/lib/src/callbacks/user_discovery.callbacks.dart @@ -216,10 +216,10 @@ class UserDiscoveryCallbacks { await twonlyDB .into(twonlyDB.userDiscoveryAnnouncedUsers) .insertOnConflictUpdate( - UserDiscoveryAnnouncedUser( - announcedUserId: announcedUser.userId, - announcedPublicKey: announcedUser.publicKey, - publicId: announcedUser.publicId, + UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: Value(announcedUser.userId), + announcedPublicKey: Value(announcedUser.publicKey), + publicId: Value(announcedUser.publicId), ), ); diff --git a/lib/src/database/daos/user_discovery.dao.dart b/lib/src/database/daos/user_discovery.dao.dart index 143e2d4c..2710663c 100644 --- a/lib/src/database/daos/user_discovery.dao.dart +++ b/lib/src/database/daos/user_discovery.dao.dart @@ -18,4 +18,90 @@ class UserDiscoveryDao extends DatabaseAccessor // of this object. // ignore: matching_super_parameters UserDiscoveryDao(super.db); + + /// 1. Get count for contacts which are in announced but not in the contacts table + + /// Returns all users which are not yet in the contacts table but have no data loaded (e.g. Avatar, username and display name) + Future> + getNewAnnouncementsWithoutData() async { + final query = + select(userDiscoveryAnnouncedUsers).join([ + leftOuterJoin( + contacts, + contacts.userId.equalsExp( + userDiscoveryAnnouncedUsers.announcedUserId, + ), + ), + ]) + // Apply filters: + // 1. The user must NOT exist in the contacts table + // 2. The username must be null + ..where( + contacts.userId.isNull() & + userDiscoveryAnnouncedUsers.username.isNull(), + ); + + return (await query.get()) + .map((row) => row.readTable(userDiscoveryAnnouncedUsers)) + .toList(); + } + + Future>> + getAnnouncedUsersWithRelations() async { + final query = select(userDiscoveryAnnouncedUsers).join([ + innerJoin( + userDiscoveryUserRelations, + userDiscoveryUserRelations.announcedUserId.equalsExp( + userDiscoveryAnnouncedUsers.announcedUserId, + ), + ), + ]); + + final rows = await query.get(); + + final results = >{}; + + for (final row in rows) { + final user = row.readTable(userDiscoveryAnnouncedUsers); + final relation = row.readTable(userDiscoveryUserRelations); + + final relationData = ( + relation.fromContactId, + relation.publicKeyVerifiedTimestamp, + ); + + if (!results.containsKey(user)) { + results[user] = []; + } + results[user]!.add(relationData); + } + + return results; + } + + Stream watchNewAnnouncementsWithDataCount() { + final countExp = userDiscoveryAnnouncedUsers.announcedUserId.count(); + + final query = selectOnly(userDiscoveryAnnouncedUsers) + ..addColumns([countExp]) + ..where( + // Filters: Has a username AND has not been shown to the user yet + userDiscoveryAnnouncedUsers.username.isNotNull() & + userDiscoveryAnnouncedUsers.wasShownToTheUser.equals(false) & + userDiscoveryAnnouncedUsers.isHidden.equals(false), + ); + + return query.watchSingle().map((row) => row.read(countExp) ?? 0); + } + + Future updateAnnouncedUser( + int announcedUserId, + UserDiscoveryAnnouncedUsersCompanion updatedValues, + ) async { + await (update( + userDiscoveryAnnouncedUsers, + )..where((c) => c.announcedUserId.equals(announcedUserId))).write( + updatedValues, + ); + } } diff --git a/lib/src/database/schemas/twonly_db/drift_schema_v14.json b/lib/src/database/schemas/twonly_db/drift_schema_v14.json new file mode 100644 index 00000000..53bef4a6 --- /dev/null +++ b/lib/src/database/schemas/twonly_db/drift_schema_v14.json @@ -0,0 +1,2713 @@ +{ + "_meta": { + "description": "This file contains a serialized version of schema entities for drift.", + "version": "1.3.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, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "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_compressed", + "getter_name": "avatarSvgCompressed", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_profile_counter", + "getter_name": "senderProfileCounter", + "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": "deleted_by_user", + "getter_name": "deletedByUser", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"deleted_by_user\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"deleted_by_user\" 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": "account_deleted", + "getter_name": "accountDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"account_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"account_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "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": "user_discovery_version", + "getter_name": "userDiscoveryVersion", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "media_send_counter", + "getter_name": "mediaSendCounter", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "media_received_counter", + "getter_name": "mediaReceivedCounter", + "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": [], + "type": "table", + "data": { + "name": "groups", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_group_admin", + "getter_name": "isGroupAdmin", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_group_admin\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_group_admin\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_direct_chat", + "getter_name": "isDirectChat", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_direct_chat\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_direct_chat\" 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": "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": "joined_group", + "getter_name": "joinedGroup", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"joined_group\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"joined_group\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "left_group", + "getter_name": "leftGroup", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"left_group\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"left_group\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "deleted_content", + "getter_name": "deletedContent", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"deleted_content\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"deleted_content\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "state_version_id", + "getter_name": "stateVersionId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "state_encryption_key", + "getter_name": "stateEncryptionKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "my_group_private_key", + "getter_name": "myGroupPrivateKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "group_name", + "getter_name": "groupName", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "draft_message", + "getter_name": "draftMessage", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "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": "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_milliseconds", + "getter_name": "deleteMessagesAfterMilliseconds", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('86400000')", + "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": "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": "flame_counter", + "getter_name": "flameCounter", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "max_flame_counter", + "getter_name": "maxFlameCounter", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "max_flame_counter_from", + "getter_name": "maxFlameCounterFrom", + "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": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "group_id" + ] + } + }, + { + "id": 2, + "references": [], + "type": "table", + "data": { + "name": "media_files", + "was_declared_in_moor": false, + "columns": [ + { + "name": "media_id", + "getter_name": "mediaId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MediaType.values)", + "dart_type_name": "MediaType" + } + }, + { + "name": "upload_state", + "getter_name": "uploadState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(UploadState.values)", + "dart_type_name": "UploadState" + } + }, + { + "name": "download_state", + "getter_name": "downloadState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(DownloadState.values)", + "dart_type_name": "DownloadState" + } + }, + { + "name": "requires_authentication", + "getter_name": "requiresAuthentication", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"requires_authentication\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"requires_authentication\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "stored", + "getter_name": "stored", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"stored\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"stored\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_draft_media", + "getter_name": "isDraftMedia", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_draft_media\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_draft_media\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pre_progressing_process", + "getter_name": "preProgressingProcess", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "reupload_requested_by", + "getter_name": "reuploadRequestedBy", + "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": "display_limit_in_milliseconds", + "getter_name": "displayLimitInMilliseconds", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "remove_audio", + "getter_name": "removeAudio", + "moor_type": "bool", + "nullable": true, + "customConstraints": null, + "defaultConstraints": "CHECK (\"remove_audio\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"remove_audio\" IN (0, 1))" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "download_token", + "getter_name": "downloadToken", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_key", + "getter_name": "encryptionKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_mac", + "getter_name": "encryptionMac", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_nonce", + "getter_name": "encryptionNonce", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "stored_file_hash", + "getter_name": "storedFileHash", + "moor_type": "blob", + "nullable": true, + "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": [ + "media_id" + ] + } + }, + { + "id": 3, + "references": [ + 1, + 0, + 2 + ], + "type": "table", + "data": { + "name": "messages", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_id", + "getter_name": "senderId", + "moor_type": "int", + "nullable": true, + "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "content", + "getter_name": "content", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "media_id", + "getter_name": "mediaId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "defaultConstraints": "REFERENCES media_files (media_id) ON DELETE SET NULL", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES media_files (media_id) ON DELETE SET NULL" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "media_files", + "column": "media_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "setNull" + } + } + ] + }, + { + "name": "additional_message_data", + "getter_name": "additionalMessageData", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "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": "media_reopened", + "getter_name": "mediaReopened", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"media_reopened\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"media_reopened\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "download_token", + "getter_name": "downloadToken", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quotes_message_id", + "getter_name": "quotesMessageId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted_from_sender", + "getter_name": "isDeletedFromSender", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted_from_sender\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted_from_sender\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "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": "opened_by_all", + "getter_name": "openedByAll", + "moor_type": "dateTime", + "nullable": true, + "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": [] + }, + { + "name": "modified_at", + "getter_name": "modifiedAt", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_user", + "getter_name": "ackByUser", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_server", + "getter_name": "ackByServer", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "message_id" + ] + } + }, + { + "id": 4, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "message_histories", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "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_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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": "content", + "getter_name": "content", + "moor_type": "string", + "nullable": true, + "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": [] + } + }, + { + "id": 5, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "reactions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "emoji", + "getter_name": "emoji", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_id", + "getter_name": "senderId", + "moor_type": "int", + "nullable": true, + "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": "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": [ + "message_id", + "sender_id", + "emoji" + ] + } + }, + { + "id": 6, + "references": [ + 1, + 0 + ], + "type": "table", + "data": { + "name": "group_members", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "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": "member_state", + "getter_name": "memberState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MemberState.values)", + "dart_type_name": "MemberState" + } + }, + { + "name": "group_public_key", + "getter_name": "groupPublicKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_chat_opened", + "getter_name": "lastChatOpened", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_type_indicator", + "getter_name": "lastTypeIndicator", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_message", + "getter_name": "lastMessage", + "moor_type": "dateTime", + "nullable": true, + "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": [ + "group_id", + "contact_id" + ] + } + }, + { + "id": 7, + "references": [ + 0, + 3 + ], + "type": "table", + "data": { + "name": "receipts", + "was_declared_in_moor": false, + "columns": [ + { + "name": "receipt_id", + "getter_name": "receiptId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "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": "string", + "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": "message", + "getter_name": "message", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "contact_will_sends_receipt", + "getter_name": "contactWillSendsReceipt", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"contact_will_sends_receipt\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"contact_will_sends_receipt\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "will_be_retried_by_media_upload", + "getter_name": "willBeRetriedByMediaUpload", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"will_be_retried_by_media_upload\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"will_be_retried_by_media_upload\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mark_for_retry", + "getter_name": "markForRetry", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mark_for_retry_after_accepted", + "getter_name": "markForRetryAfterAccepted", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_server_at", + "getter_name": "ackByServerAt", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "retry_count", + "getter_name": "retryCount", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_retry", + "getter_name": "lastRetry", + "moor_type": "dateTime", + "nullable": true, + "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": [ + "receipt_id" + ] + } + }, + { + "id": 8, + "references": [], + "type": "table", + "data": { + "name": "received_receipts", + "was_declared_in_moor": false, + "columns": [ + { + "name": "receipt_id", + "getter_name": "receiptId", + "moor_type": "string", + "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": [ + "receipt_id" + ] + } + }, + { + "id": 9, + "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": 10, + "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": 11, + "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": 12, + "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": 13, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "message_actions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MessageActionType.values)", + "dart_type_name": "MessageActionType" + } + }, + { + "name": "action_at", + "getter_name": "actionAt", + "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": [ + "message_id", + "contact_id", + "type" + ] + } + }, + { + "id": 14, + "references": [ + 1, + 0 + ], + "type": "table", + "data": { + "name": "group_histories", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_history_id", + "getter_name": "groupHistoryId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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": "affected_contact_id", + "getter_name": "affectedContactId", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "old_group_name", + "getter_name": "oldGroupName", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "new_group_name", + "getter_name": "newGroupName", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "new_delete_messages_after_milliseconds", + "getter_name": "newDeleteMessagesAfterMilliseconds", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(GroupActionType.values)", + "dart_type_name": "GroupActionType" + } + }, + { + "name": "action_at", + "getter_name": "actionAt", + "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": [ + "group_history_id" + ] + } + }, + { + "id": 15, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "key_verifications", + "was_declared_in_moor": false, + "columns": [ + { + "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(VerificationType.values)", + "dart_type_name": "VerificationType" + } + }, + { + "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": 16, + "references": [], + "type": "table", + "data": { + "name": "verification_tokens", + "was_declared_in_moor": false, + "columns": [ + { + "name": "token_id", + "getter_name": "tokenId", + "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": "token", + "getter_name": "token", + "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": [] + } + }, + { + "id": 17, + "references": [], + "type": "table", + "data": { + "name": "user_discovery_announced_users", + "was_declared_in_moor": false, + "columns": [ + { + "name": "announced_user_id", + "getter_name": "announcedUserId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "announced_public_key", + "getter_name": "announcedPublicKey", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_id", + "getter_name": "publicId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "UNIQUE", + "dialectAwareDefaultConstraints": { + "sqlite": "UNIQUE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + "unique" + ] + }, + { + "name": "username", + "getter_name": "username", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "was_shown_to_the_user", + "getter_name": "wasShownToTheUser", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"was_shown_to_the_user\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"was_shown_to_the_user\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_hidden", + "getter_name": "isHidden", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_hidden\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_hidden\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "announced_user_id" + ] + } + }, + { + "id": 18, + "references": [ + 17, + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_user_relations", + "was_declared_in_moor": false, + "columns": [ + { + "name": "announced_user_id", + "getter_name": "announcedUserId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "user_discovery_announced_users", + "column": "announced_user_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "from_contact_id", + "getter_name": "fromContactId", + "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": "public_key_verified_timestamp", + "getter_name": "publicKeyVerifiedTimestamp", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "announced_user_id", + "from_contact_id" + ] + } + }, + { + "id": 19, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_other_promotions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "from_contact_id", + "getter_name": "fromContactId", + "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": "promotion_id", + "getter_name": "promotionId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_id", + "getter_name": "publicId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "threshold", + "getter_name": "threshold", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "announcement_share", + "getter_name": "announcementShare", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_key_verified_timestamp", + "getter_name": "publicKeyVerifiedTimestamp", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "from_contact_id", + "promotion_id" + ] + } + }, + { + "id": 20, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_own_promotions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "version_id", + "getter_name": "versionId", + "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": "promotion", + "getter_name": "promotion", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [] + } + }, + { + "id": 21, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_shares", + "was_declared_in_moor": false, + "columns": [ + { + "name": "share_id", + "getter_name": "shareId", + "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": "share", + "getter_name": "share", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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" + } + } + ] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [] + } + } + ], + "fixed_sql": [ + { + "name": "contacts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"contacts\" (\"user_id\" INTEGER NOT NULL, \"username\" TEXT NOT NULL, \"display_name\" TEXT NULL, \"nick_name\" TEXT NULL, \"avatar_svg_compressed\" BLOB NULL, \"sender_profile_counter\" INTEGER NOT NULL DEFAULT 0, \"accepted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"accepted\" IN (0, 1)), \"deleted_by_user\" INTEGER NOT NULL DEFAULT 0 CHECK (\"deleted_by_user\" IN (0, 1)), \"requested\" INTEGER NOT NULL DEFAULT 0 CHECK (\"requested\" IN (0, 1)), \"blocked\" INTEGER NOT NULL DEFAULT 0 CHECK (\"blocked\" IN (0, 1)), \"verified\" INTEGER NOT NULL DEFAULT 0 CHECK (\"verified\" IN (0, 1)), \"account_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"account_deleted\" IN (0, 1)), \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"user_discovery_version\" BLOB NULL, \"media_send_counter\" INTEGER NOT NULL DEFAULT 0, \"media_received_counter\" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (\"user_id\"));" + } + ] + }, + { + "name": "groups", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"groups\" (\"group_id\" TEXT NOT NULL, \"is_group_admin\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_group_admin\" IN (0, 1)), \"is_direct_chat\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_direct_chat\" IN (0, 1)), \"pinned\" INTEGER NOT NULL DEFAULT 0 CHECK (\"pinned\" IN (0, 1)), \"archived\" INTEGER NOT NULL DEFAULT 0 CHECK (\"archived\" IN (0, 1)), \"joined_group\" INTEGER NOT NULL DEFAULT 0 CHECK (\"joined_group\" IN (0, 1)), \"left_group\" INTEGER NOT NULL DEFAULT 0 CHECK (\"left_group\" IN (0, 1)), \"deleted_content\" INTEGER NOT NULL DEFAULT 0 CHECK (\"deleted_content\" IN (0, 1)), \"state_version_id\" INTEGER NOT NULL DEFAULT 0, \"state_encryption_key\" BLOB NULL, \"my_group_private_key\" BLOB NULL, \"group_name\" TEXT NOT NULL, \"draft_message\" TEXT NULL, \"total_media_counter\" INTEGER NOT NULL DEFAULT 0, \"also_best_friend\" INTEGER NOT NULL DEFAULT 0 CHECK (\"also_best_friend\" IN (0, 1)), \"delete_messages_after_milliseconds\" INTEGER NOT NULL DEFAULT 86400000, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"last_message_send\" INTEGER NULL, \"last_message_received\" INTEGER NULL, \"last_flame_counter_change\" INTEGER NULL, \"last_flame_sync\" INTEGER NULL, \"flame_counter\" INTEGER NOT NULL DEFAULT 0, \"max_flame_counter\" INTEGER NOT NULL DEFAULT 0, \"max_flame_counter_from\" INTEGER NULL, \"last_message_exchange\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_id\"));" + } + ] + }, + { + "name": "media_files", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"media_files\" (\"media_id\" TEXT NOT NULL, \"type\" TEXT NOT NULL, \"upload_state\" TEXT NULL, \"download_state\" TEXT NULL, \"requires_authentication\" INTEGER NOT NULL DEFAULT 0 CHECK (\"requires_authentication\" IN (0, 1)), \"stored\" INTEGER NOT NULL DEFAULT 0 CHECK (\"stored\" IN (0, 1)), \"is_draft_media\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_draft_media\" IN (0, 1)), \"pre_progressing_process\" INTEGER NULL, \"reupload_requested_by\" TEXT NULL, \"display_limit_in_milliseconds\" INTEGER NULL, \"remove_audio\" INTEGER NULL CHECK (\"remove_audio\" IN (0, 1)), \"download_token\" BLOB NULL, \"encryption_key\" BLOB NULL, \"encryption_mac\" BLOB NULL, \"encryption_nonce\" BLOB NULL, \"stored_file_hash\" BLOB NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"media_id\"));" + } + ] + }, + { + "name": "messages", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"messages\" (\"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"message_id\" TEXT NOT NULL, \"sender_id\" INTEGER NULL REFERENCES contacts (user_id), \"type\" TEXT NOT NULL, \"content\" TEXT NULL, \"media_id\" TEXT NULL REFERENCES media_files (media_id) ON DELETE SET NULL, \"additional_message_data\" BLOB NULL, \"media_stored\" INTEGER NOT NULL DEFAULT 0 CHECK (\"media_stored\" IN (0, 1)), \"media_reopened\" INTEGER NOT NULL DEFAULT 0 CHECK (\"media_reopened\" IN (0, 1)), \"download_token\" BLOB NULL, \"quotes_message_id\" TEXT NULL, \"is_deleted_from_sender\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted_from_sender\" IN (0, 1)), \"opened_at\" INTEGER NULL, \"opened_by_all\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"modified_at\" INTEGER NULL, \"ack_by_user\" INTEGER NULL, \"ack_by_server\" INTEGER NULL, PRIMARY KEY (\"message_id\"));" + } + ] + }, + { + "name": "message_histories", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"message_histories\" (\"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"content\" TEXT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)));" + } + ] + }, + { + "name": "reactions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"reactions\" (\"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"emoji\" TEXT NOT NULL, \"sender_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"message_id\", \"sender_id\", \"emoji\"));" + } + ] + }, + { + "name": "group_members", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"group_members\" (\"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id), \"member_state\" TEXT NULL, \"group_public_key\" BLOB NULL, \"last_chat_opened\" INTEGER NULL, \"last_type_indicator\" INTEGER NULL, \"last_message\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_id\", \"contact_id\"));" + } + ] + }, + { + "name": "receipts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"receipts\" (\"receipt_id\" TEXT NOT NULL, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"message_id\" TEXT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"message\" BLOB NOT NULL, \"contact_will_sends_receipt\" INTEGER NOT NULL DEFAULT 1 CHECK (\"contact_will_sends_receipt\" IN (0, 1)), \"will_be_retried_by_media_upload\" INTEGER NOT NULL DEFAULT 0 CHECK (\"will_be_retried_by_media_upload\" IN (0, 1)), \"mark_for_retry\" INTEGER NULL, \"mark_for_retry_after_accepted\" INTEGER NULL, \"ack_by_server_at\" INTEGER NULL, \"retry_count\" INTEGER NOT NULL DEFAULT 0, \"last_retry\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"receipt_id\"));" + } + ] + }, + { + "name": "received_receipts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"received_receipts\" (\"receipt_id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"receipt_id\"));" + } + ] + }, + { + "name": "signal_identity_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_identity_key_stores\" (\"device_id\" INTEGER NOT NULL, \"name\" TEXT NOT NULL, \"identity_key\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"device_id\", \"name\"));" + } + ] + }, + { + "name": "signal_pre_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_pre_key_stores\" (\"pre_key_id\" INTEGER NOT NULL, \"pre_key\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"pre_key_id\"));" + } + ] + }, + { + "name": "signal_sender_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_sender_key_stores\" (\"sender_key_name\" TEXT NOT NULL, \"sender_key\" BLOB NOT NULL, PRIMARY KEY (\"sender_key_name\"));" + } + ] + }, + { + "name": "signal_session_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_session_stores\" (\"device_id\" INTEGER NOT NULL, \"name\" TEXT NOT NULL, \"session_record\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"device_id\", \"name\"));" + } + ] + }, + { + "name": "message_actions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"message_actions\" (\"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"type\" TEXT NOT NULL, \"action_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"message_id\", \"contact_id\", \"type\"));" + } + ] + }, + { + "name": "group_histories", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"group_histories\" (\"group_history_id\" TEXT NOT NULL, \"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id), \"affected_contact_id\" INTEGER NULL, \"old_group_name\" TEXT NULL, \"new_group_name\" TEXT NULL, \"new_delete_messages_after_milliseconds\" INTEGER NULL, \"type\" TEXT NOT NULL, \"action_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_history_id\"));" + } + ] + }, + { + "name": "key_verifications", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"key_verifications\" (\"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"type\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"contact_id\"));" + } + ] + }, + { + "name": "verification_tokens", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"verification_tokens\" (\"token_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"token\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)));" + } + ] + }, + { + "name": "user_discovery_announced_users", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_announced_users\" (\"announced_user_id\" INTEGER NOT NULL, \"announced_public_key\" BLOB NOT NULL, \"public_id\" INTEGER NOT NULL UNIQUE, \"username\" TEXT NULL, \"was_shown_to_the_user\" INTEGER NOT NULL DEFAULT 0 CHECK (\"was_shown_to_the_user\" IN (0, 1)), \"is_hidden\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_hidden\" IN (0, 1)), PRIMARY KEY (\"announced_user_id\"));" + } + ] + }, + { + "name": "user_discovery_user_relations", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_user_relations\" (\"announced_user_id\" INTEGER NOT NULL REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE, \"from_contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"public_key_verified_timestamp\" INTEGER NULL, PRIMARY KEY (\"announced_user_id\", \"from_contact_id\"));" + } + ] + }, + { + "name": "user_discovery_other_promotions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_other_promotions\" (\"from_contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"promotion_id\" INTEGER NOT NULL, \"public_id\" INTEGER NOT NULL, \"threshold\" INTEGER NOT NULL, \"announcement_share\" BLOB NOT NULL, \"public_key_verified_timestamp\" INTEGER NULL, PRIMARY KEY (\"from_contact_id\", \"promotion_id\"));" + } + ] + }, + { + "name": "user_discovery_own_promotions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_own_promotions\" (\"version_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"promotion\" BLOB NOT NULL);" + } + ] + }, + { + "name": "user_discovery_shares", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_shares\" (\"share_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"share\" BLOB NOT NULL, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE);" + } + ] + } + ] +} \ No newline at end of file diff --git a/lib/src/database/tables/user_discovery.table.dart b/lib/src/database/tables/user_discovery.table.dart index 5239dc5b..2e609ed0 100644 --- a/lib/src/database/tables/user_discovery.table.dart +++ b/lib/src/database/tables/user_discovery.table.dart @@ -10,6 +10,13 @@ class UserDiscoveryAnnouncedUsers extends Table { BlobColumn get announcedPublicKey => blob()(); IntColumn get publicId => integer().unique()(); + // When a new user got announced this data will be requested without adding the users to the contacts... + TextColumn get username => text().nullable()(); + + BoolColumn get wasShownToTheUser => + boolean().withDefault(const Constant(false))(); + BoolColumn get isHidden => boolean().withDefault(const Constant(false))(); + @override Set get primaryKey => {announcedUserId}; } diff --git a/lib/src/database/twonly.db.dart b/lib/src/database/twonly.db.dart index 44e7f9f6..2df1d81d 100644 --- a/lib/src/database/twonly.db.dart +++ b/lib/src/database/twonly.db.dart @@ -72,7 +72,7 @@ class TwonlyDB extends _$TwonlyDB { TwonlyDB.forTesting(DatabaseConnection super.connection); @override - int get schemaVersion => 13; + int get schemaVersion => 14; static QueryExecutor _openConnection() { return driftDatabase( @@ -191,6 +191,20 @@ class TwonlyDB extends _$TwonlyDB { schema.contacts.mediaSendCounter, ); }, + from13To14: (m, schema) async { + await m.addColumn( + schema.userDiscoveryAnnouncedUsers, + schema.userDiscoveryAnnouncedUsers.wasShownToTheUser, + ); + await m.addColumn( + schema.userDiscoveryAnnouncedUsers, + schema.userDiscoveryAnnouncedUsers.isHidden, + ); + await m.addColumn( + schema.userDiscoveryAnnouncedUsers, + schema.userDiscoveryAnnouncedUsers.username, + ); + }, )(m, from, to); }, ); diff --git a/lib/src/database/twonly.db.g.dart b/lib/src/database/twonly.db.g.dart index 1dced0bc..57649abd 100644 --- a/lib/src/database/twonly.db.g.dart +++ b/lib/src/database/twonly.db.g.dart @@ -9537,11 +9537,55 @@ class $UserDiscoveryAnnouncedUsersTable extends UserDiscoveryAnnouncedUsers requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways('UNIQUE'), ); + static const VerificationMeta _usernameMeta = const VerificationMeta( + 'username', + ); + @override + late final GeneratedColumn username = GeneratedColumn( + 'username', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _wasShownToTheUserMeta = const VerificationMeta( + 'wasShownToTheUser', + ); + @override + late final GeneratedColumn wasShownToTheUser = GeneratedColumn( + 'was_shown_to_the_user', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("was_shown_to_the_user" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _isHiddenMeta = const VerificationMeta( + 'isHidden', + ); + @override + late final GeneratedColumn isHidden = GeneratedColumn( + 'is_hidden', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_hidden" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); @override List get $columns => [ announcedUserId, announcedPublicKey, publicId, + username, + wasShownToTheUser, + isHidden, ]; @override String get aliasedName => _alias ?? actualTableName; @@ -9583,6 +9627,27 @@ class $UserDiscoveryAnnouncedUsersTable extends UserDiscoveryAnnouncedUsers } else if (isInserting) { context.missing(_publicIdMeta); } + if (data.containsKey('username')) { + context.handle( + _usernameMeta, + username.isAcceptableOrUnknown(data['username']!, _usernameMeta), + ); + } + if (data.containsKey('was_shown_to_the_user')) { + context.handle( + _wasShownToTheUserMeta, + wasShownToTheUser.isAcceptableOrUnknown( + data['was_shown_to_the_user']!, + _wasShownToTheUserMeta, + ), + ); + } + if (data.containsKey('is_hidden')) { + context.handle( + _isHiddenMeta, + isHidden.isAcceptableOrUnknown(data['is_hidden']!, _isHiddenMeta), + ); + } return context; } @@ -9607,6 +9672,18 @@ class $UserDiscoveryAnnouncedUsersTable extends UserDiscoveryAnnouncedUsers DriftSqlType.int, data['${effectivePrefix}public_id'], )!, + username: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}username'], + ), + wasShownToTheUser: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}was_shown_to_the_user'], + )!, + isHidden: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_hidden'], + )!, ); } @@ -9621,10 +9698,16 @@ class UserDiscoveryAnnouncedUser extends DataClass final int announcedUserId; final Uint8List announcedPublicKey; final int publicId; + final String? username; + final bool wasShownToTheUser; + final bool isHidden; const UserDiscoveryAnnouncedUser({ required this.announcedUserId, required this.announcedPublicKey, required this.publicId, + this.username, + required this.wasShownToTheUser, + required this.isHidden, }); @override Map toColumns(bool nullToAbsent) { @@ -9632,6 +9715,11 @@ class UserDiscoveryAnnouncedUser extends DataClass map['announced_user_id'] = Variable(announcedUserId); map['announced_public_key'] = Variable(announcedPublicKey); map['public_id'] = Variable(publicId); + if (!nullToAbsent || username != null) { + map['username'] = Variable(username); + } + map['was_shown_to_the_user'] = Variable(wasShownToTheUser); + map['is_hidden'] = Variable(isHidden); return map; } @@ -9640,6 +9728,11 @@ class UserDiscoveryAnnouncedUser extends DataClass announcedUserId: Value(announcedUserId), announcedPublicKey: Value(announcedPublicKey), publicId: Value(publicId), + username: username == null && nullToAbsent + ? const Value.absent() + : Value(username), + wasShownToTheUser: Value(wasShownToTheUser), + isHidden: Value(isHidden), ); } @@ -9654,6 +9747,9 @@ class UserDiscoveryAnnouncedUser extends DataClass json['announcedPublicKey'], ), publicId: serializer.fromJson(json['publicId']), + username: serializer.fromJson(json['username']), + wasShownToTheUser: serializer.fromJson(json['wasShownToTheUser']), + isHidden: serializer.fromJson(json['isHidden']), ); } @override @@ -9663,6 +9759,9 @@ class UserDiscoveryAnnouncedUser extends DataClass 'announcedUserId': serializer.toJson(announcedUserId), 'announcedPublicKey': serializer.toJson(announcedPublicKey), 'publicId': serializer.toJson(publicId), + 'username': serializer.toJson(username), + 'wasShownToTheUser': serializer.toJson(wasShownToTheUser), + 'isHidden': serializer.toJson(isHidden), }; } @@ -9670,10 +9769,16 @@ class UserDiscoveryAnnouncedUser extends DataClass int? announcedUserId, Uint8List? announcedPublicKey, int? publicId, + Value username = const Value.absent(), + bool? wasShownToTheUser, + bool? isHidden, }) => UserDiscoveryAnnouncedUser( announcedUserId: announcedUserId ?? this.announcedUserId, announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, publicId: publicId ?? this.publicId, + username: username.present ? username.value : this.username, + wasShownToTheUser: wasShownToTheUser ?? this.wasShownToTheUser, + isHidden: isHidden ?? this.isHidden, ); UserDiscoveryAnnouncedUser copyWithCompanion( UserDiscoveryAnnouncedUsersCompanion data, @@ -9686,6 +9791,11 @@ class UserDiscoveryAnnouncedUser extends DataClass ? data.announcedPublicKey.value : this.announcedPublicKey, publicId: data.publicId.present ? data.publicId.value : this.publicId, + username: data.username.present ? data.username.value : this.username, + wasShownToTheUser: data.wasShownToTheUser.present + ? data.wasShownToTheUser.value + : this.wasShownToTheUser, + isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden, ); } @@ -9694,7 +9804,10 @@ class UserDiscoveryAnnouncedUser extends DataClass return (StringBuffer('UserDiscoveryAnnouncedUser(') ..write('announcedUserId: $announcedUserId, ') ..write('announcedPublicKey: $announcedPublicKey, ') - ..write('publicId: $publicId') + ..write('publicId: $publicId, ') + ..write('username: $username, ') + ..write('wasShownToTheUser: $wasShownToTheUser, ') + ..write('isHidden: $isHidden') ..write(')')) .toString(); } @@ -9704,6 +9817,9 @@ class UserDiscoveryAnnouncedUser extends DataClass announcedUserId, $driftBlobEquality.hash(announcedPublicKey), publicId, + username, + wasShownToTheUser, + isHidden, ); @override bool operator ==(Object other) => @@ -9714,7 +9830,10 @@ class UserDiscoveryAnnouncedUser extends DataClass other.announcedPublicKey, this.announcedPublicKey, ) && - other.publicId == this.publicId); + other.publicId == this.publicId && + other.username == this.username && + other.wasShownToTheUser == this.wasShownToTheUser && + other.isHidden == this.isHidden); } class UserDiscoveryAnnouncedUsersCompanion @@ -9722,27 +9841,42 @@ class UserDiscoveryAnnouncedUsersCompanion final Value announcedUserId; final Value announcedPublicKey; final Value publicId; + final Value username; + final Value wasShownToTheUser; + final Value isHidden; const UserDiscoveryAnnouncedUsersCompanion({ this.announcedUserId = const Value.absent(), this.announcedPublicKey = const Value.absent(), this.publicId = const Value.absent(), + this.username = const Value.absent(), + this.wasShownToTheUser = const Value.absent(), + this.isHidden = const Value.absent(), }); UserDiscoveryAnnouncedUsersCompanion.insert({ this.announcedUserId = const Value.absent(), required Uint8List announcedPublicKey, required int publicId, + this.username = const Value.absent(), + this.wasShownToTheUser = const Value.absent(), + this.isHidden = const Value.absent(), }) : announcedPublicKey = Value(announcedPublicKey), publicId = Value(publicId); static Insertable custom({ Expression? announcedUserId, Expression? announcedPublicKey, Expression? publicId, + Expression? username, + Expression? wasShownToTheUser, + Expression? isHidden, }) { return RawValuesInsertable({ if (announcedUserId != null) 'announced_user_id': announcedUserId, if (announcedPublicKey != null) 'announced_public_key': announcedPublicKey, if (publicId != null) 'public_id': publicId, + if (username != null) 'username': username, + if (wasShownToTheUser != null) 'was_shown_to_the_user': wasShownToTheUser, + if (isHidden != null) 'is_hidden': isHidden, }); } @@ -9750,11 +9884,17 @@ class UserDiscoveryAnnouncedUsersCompanion Value? announcedUserId, Value? announcedPublicKey, Value? publicId, + Value? username, + Value? wasShownToTheUser, + Value? isHidden, }) { return UserDiscoveryAnnouncedUsersCompanion( announcedUserId: announcedUserId ?? this.announcedUserId, announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, publicId: publicId ?? this.publicId, + username: username ?? this.username, + wasShownToTheUser: wasShownToTheUser ?? this.wasShownToTheUser, + isHidden: isHidden ?? this.isHidden, ); } @@ -9772,6 +9912,15 @@ class UserDiscoveryAnnouncedUsersCompanion if (publicId.present) { map['public_id'] = Variable(publicId.value); } + if (username.present) { + map['username'] = Variable(username.value); + } + if (wasShownToTheUser.present) { + map['was_shown_to_the_user'] = Variable(wasShownToTheUser.value); + } + if (isHidden.present) { + map['is_hidden'] = Variable(isHidden.value); + } return map; } @@ -9780,7 +9929,10 @@ class UserDiscoveryAnnouncedUsersCompanion return (StringBuffer('UserDiscoveryAnnouncedUsersCompanion(') ..write('announcedUserId: $announcedUserId, ') ..write('announcedPublicKey: $announcedPublicKey, ') - ..write('publicId: $publicId') + ..write('publicId: $publicId, ') + ..write('username: $username, ') + ..write('wasShownToTheUser: $wasShownToTheUser, ') + ..write('isHidden: $isHidden') ..write(')')) .toString(); } @@ -19690,12 +19842,18 @@ typedef $$UserDiscoveryAnnouncedUsersTableCreateCompanionBuilder = Value announcedUserId, required Uint8List announcedPublicKey, required int publicId, + Value username, + Value wasShownToTheUser, + Value isHidden, }); typedef $$UserDiscoveryAnnouncedUsersTableUpdateCompanionBuilder = UserDiscoveryAnnouncedUsersCompanion Function({ Value announcedUserId, Value announcedPublicKey, Value publicId, + Value username, + Value wasShownToTheUser, + Value isHidden, }); final class $$UserDiscoveryAnnouncedUsersTableReferences @@ -19769,6 +19927,21 @@ class $$UserDiscoveryAnnouncedUsersTableFilterComposer builder: (column) => ColumnFilters(column), ); + ColumnFilters get username => $composableBuilder( + column: $table.username, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get wasShownToTheUser => $composableBuilder( + column: $table.wasShownToTheUser, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isHidden => $composableBuilder( + column: $table.isHidden, + builder: (column) => ColumnFilters(column), + ); + Expression userDiscoveryUserRelationsRefs( Expression Function($$UserDiscoveryUserRelationsTableFilterComposer f) f, @@ -19820,6 +19993,21 @@ class $$UserDiscoveryAnnouncedUsersTableOrderingComposer column: $table.publicId, builder: (column) => ColumnOrderings(column), ); + + ColumnOrderings get username => $composableBuilder( + column: $table.username, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get wasShownToTheUser => $composableBuilder( + column: $table.wasShownToTheUser, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isHidden => $composableBuilder( + column: $table.isHidden, + builder: (column) => ColumnOrderings(column), + ); } class $$UserDiscoveryAnnouncedUsersTableAnnotationComposer @@ -19844,6 +20032,17 @@ class $$UserDiscoveryAnnouncedUsersTableAnnotationComposer GeneratedColumn get publicId => $composableBuilder(column: $table.publicId, builder: (column) => column); + GeneratedColumn get username => + $composableBuilder(column: $table.username, builder: (column) => column); + + GeneratedColumn get wasShownToTheUser => $composableBuilder( + column: $table.wasShownToTheUser, + builder: (column) => column, + ); + + GeneratedColumn get isHidden => + $composableBuilder(column: $table.isHidden, builder: (column) => column); + Expression userDiscoveryUserRelationsRefs( Expression Function( $$UserDiscoveryUserRelationsTableAnnotationComposer a, @@ -19919,20 +20118,32 @@ class $$UserDiscoveryAnnouncedUsersTableTableManager Value announcedUserId = const Value.absent(), Value announcedPublicKey = const Value.absent(), Value publicId = const Value.absent(), + Value username = const Value.absent(), + Value wasShownToTheUser = const Value.absent(), + Value isHidden = const Value.absent(), }) => UserDiscoveryAnnouncedUsersCompanion( announcedUserId: announcedUserId, announcedPublicKey: announcedPublicKey, publicId: publicId, + username: username, + wasShownToTheUser: wasShownToTheUser, + isHidden: isHidden, ), createCompanionCallback: ({ Value announcedUserId = const Value.absent(), required Uint8List announcedPublicKey, required int publicId, + Value username = const Value.absent(), + Value wasShownToTheUser = const Value.absent(), + Value isHidden = const Value.absent(), }) => UserDiscoveryAnnouncedUsersCompanion.insert( announcedUserId: announcedUserId, announcedPublicKey: announcedPublicKey, publicId: publicId, + username: username, + wasShownToTheUser: wasShownToTheUser, + isHidden: isHidden, ), withReferenceMapper: (p0) => p0 .map( diff --git a/lib/src/database/twonly.db.steps.dart b/lib/src/database/twonly.db.steps.dart index 9bc0f029..3cb3366c 100644 --- a/lib/src/database/twonly.db.steps.dart +++ b/lib/src/database/twonly.db.steps.dart @@ -6932,6 +6932,454 @@ i1.GeneratedColumn _column_229(String aliasedName) => $customConstraints: 'NOT NULL DEFAULT 0', defaultValue: const i1.CustomExpression('0'), ); + +final class Schema14 extends i0.VersionedSchema { + Schema14({required super.database}) : super(version: 14); + @override + late final List entities = [ + contacts, + groups, + mediaFiles, + messages, + messageHistories, + reactions, + groupMembers, + receipts, + receivedReceipts, + signalIdentityKeyStores, + signalPreKeyStores, + signalSenderKeyStores, + signalSessionStores, + messageActions, + groupHistories, + keyVerifications, + verificationTokens, + userDiscoveryAnnouncedUsers, + userDiscoveryUserRelations, + userDiscoveryOtherPromotions, + userDiscoveryOwnPromotions, + userDiscoveryShares, + ]; + late final Shape47 contacts = Shape47( + source: i0.VersionedTable( + entityName: 'contacts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(user_id)'], + columns: [ + _column_106, + _column_107, + _column_108, + _column_109, + _column_110, + _column_111, + _column_112, + _column_113, + _column_114, + _column_115, + _column_116, + _column_117, + _column_118, + _column_211, + _column_228, + _column_229, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape23 groups = Shape23( + source: i0.VersionedTable( + entityName: 'groups', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_id)'], + columns: [ + _column_119, + _column_120, + _column_121, + _column_122, + _column_123, + _column_124, + _column_125, + _column_126, + _column_127, + _column_128, + _column_129, + _column_130, + _column_131, + _column_132, + _column_133, + _column_134, + _column_118, + _column_135, + _column_136, + _column_137, + _column_138, + _column_139, + _column_140, + _column_141, + _column_142, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape36 mediaFiles = Shape36( + source: i0.VersionedTable( + entityName: 'media_files', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(media_id)'], + columns: [ + _column_143, + _column_144, + _column_145, + _column_146, + _column_147, + _column_148, + _column_149, + _column_207, + _column_150, + _column_151, + _column_152, + _column_153, + _column_154, + _column_155, + _column_156, + _column_157, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape25 messages = Shape25( + source: i0.VersionedTable( + entityName: 'messages', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id)'], + columns: [ + _column_158, + _column_159, + _column_160, + _column_144, + _column_161, + _column_162, + _column_163, + _column_164, + _column_165, + _column_153, + _column_166, + _column_167, + _column_168, + _column_169, + _column_118, + _column_170, + _column_171, + _column_172, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape26 messageHistories = Shape26( + source: i0.VersionedTable( + entityName: 'message_histories', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_173, + _column_174, + _column_175, + _column_161, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape27 reactions = Shape27( + source: i0.VersionedTable( + entityName: 'reactions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id, sender_id, emoji)'], + columns: [_column_174, _column_176, _column_177, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape38 groupMembers = Shape38( + source: i0.VersionedTable( + entityName: 'group_members', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_id, contact_id)'], + columns: [ + _column_158, + _column_178, + _column_179, + _column_180, + _column_209, + _column_210, + _column_181, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape37 receipts = Shape37( + source: i0.VersionedTable( + entityName: 'receipts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(receipt_id)'], + columns: [ + _column_182, + _column_183, + _column_184, + _column_185, + _column_186, + _column_208, + _column_187, + _column_188, + _column_189, + _column_190, + _column_191, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape30 receivedReceipts = Shape30( + source: i0.VersionedTable( + entityName: 'received_receipts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(receipt_id)'], + columns: [_column_182, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape31 signalIdentityKeyStores = Shape31( + source: i0.VersionedTable( + entityName: 'signal_identity_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(device_id, name)'], + columns: [_column_192, _column_193, _column_194, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape32 signalPreKeyStores = Shape32( + source: i0.VersionedTable( + entityName: 'signal_pre_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(pre_key_id)'], + columns: [_column_195, _column_196, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape11 signalSenderKeyStores = Shape11( + source: i0.VersionedTable( + entityName: 'signal_sender_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(sender_key_name)'], + columns: [_column_197, _column_198], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape33 signalSessionStores = Shape33( + source: i0.VersionedTable( + entityName: 'signal_session_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(device_id, name)'], + columns: [_column_192, _column_193, _column_199, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape34 messageActions = Shape34( + source: i0.VersionedTable( + entityName: 'message_actions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id, contact_id, type)'], + columns: [_column_174, _column_183, _column_144, _column_200], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape35 groupHistories = Shape35( + source: i0.VersionedTable( + entityName: 'group_histories', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_history_id)'], + columns: [ + _column_201, + _column_158, + _column_202, + _column_203, + _column_204, + _column_205, + _column_206, + _column_144, + _column_200, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape40 keyVerifications = Shape40( + source: i0.VersionedTable( + entityName: 'key_verifications', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(contact_id)'], + columns: [_column_183, _column_144, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape41 verificationTokens = Shape41( + source: i0.VersionedTable( + entityName: 'verification_tokens', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_212, _column_213, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape48 userDiscoveryAnnouncedUsers = Shape48( + source: i0.VersionedTable( + entityName: 'user_discovery_announced_users', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(announced_user_id)'], + columns: [ + _column_214, + _column_215, + _column_216, + _column_230, + _column_231, + _column_232, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape43 userDiscoveryUserRelations = Shape43( + source: i0.VersionedTable( + entityName: 'user_discovery_user_relations', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(announced_user_id, from_contact_id)'], + columns: [_column_217, _column_218, _column_219], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape44 userDiscoveryOtherPromotions = Shape44( + source: i0.VersionedTable( + entityName: 'user_discovery_other_promotions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(from_contact_id, promotion_id)'], + columns: [ + _column_218, + _column_220, + _column_221, + _column_222, + _column_223, + _column_219, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape45 userDiscoveryOwnPromotions = Shape45( + source: i0.VersionedTable( + entityName: 'user_discovery_own_promotions', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_224, _column_183, _column_225], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape46 userDiscoveryShares = Shape46( + source: i0.VersionedTable( + entityName: 'user_discovery_shares', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_226, _column_227, _column_175], + attachedDatabase: database, + ), + alias: null, + ); +} + +class Shape48 extends i0.VersionedTable { + Shape48({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get announcedUserId => + columnsByName['announced_user_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get announcedPublicKey => + columnsByName['announced_public_key']! + as i1.GeneratedColumn; + i1.GeneratedColumn get publicId => + columnsByName['public_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get username => + columnsByName['username']! as i1.GeneratedColumn; + i1.GeneratedColumn get wasShownToTheUser => + columnsByName['was_shown_to_the_user']! as i1.GeneratedColumn; + i1.GeneratedColumn get isHidden => + columnsByName['is_hidden']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_230(String aliasedName) => + i1.GeneratedColumn( + 'username', + aliasedName, + true, + type: i1.DriftSqlType.string, + $customConstraints: 'NULL', + ); +i1.GeneratedColumn _column_231(String aliasedName) => + i1.GeneratedColumn( + 'was_shown_to_the_user', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (was_shown_to_the_user IN (0, 1))', + defaultValue: const i1.CustomExpression('0'), + ); +i1.GeneratedColumn _column_232(String aliasedName) => + i1.GeneratedColumn( + 'is_hidden', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_hidden IN (0, 1))', + defaultValue: const i1.CustomExpression('0'), + ); i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema2 schema) from1To2, required Future Function(i1.Migrator m, Schema3 schema) from2To3, @@ -6945,6 +7393,7 @@ i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema11 schema) from10To11, required Future Function(i1.Migrator m, Schema12 schema) from11To12, required Future Function(i1.Migrator m, Schema13 schema) from12To13, + required Future Function(i1.Migrator m, Schema14 schema) from13To14, }) { return (currentVersion, database) async { switch (currentVersion) { @@ -7008,6 +7457,11 @@ i0.MigrationStepWithVersion migrationSteps({ final migrator = i1.Migrator(database, schema); await from12To13(migrator, schema); return 13; + case 13: + final schema = Schema14(database: database); + final migrator = i1.Migrator(database, schema); + await from13To14(migrator, schema); + return 14; default: throw ArgumentError.value('Unknown migration from $currentVersion'); } @@ -7027,6 +7481,7 @@ i1.OnUpgrade stepByStep({ required Future Function(i1.Migrator m, Schema11 schema) from10To11, required Future Function(i1.Migrator m, Schema12 schema) from11To12, required Future Function(i1.Migrator m, Schema13 schema) from12To13, + required Future Function(i1.Migrator m, Schema14 schema) from13To14, }) => i0.VersionedSchema.stepByStepHelper( step: migrationSteps( from1To2: from1To2, @@ -7041,5 +7496,6 @@ i1.OnUpgrade stepByStep({ from10To11: from10To11, from11To12: from11To12, from12To13: from12To13, + from13To14: from13To14, ), ); diff --git a/lib/src/localization/generated/app_localizations.dart b/lib/src/localization/generated/app_localizations.dart index 0990dd4a..02d07574 100644 --- a/lib/src/localization/generated/app_localizations.dart +++ b/lib/src/localization/generated/app_localizations.dart @@ -3141,6 +3141,12 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'When the typing indicator is turned off, you can\'t see when others are typing a message.'** String get settingsTypingIndicationSubtitle; + + /// No description provided for @scanQrOrShow. + /// + /// In en, this message translates to: + /// **'Scan / Show QR'** + String get scanQrOrShow; } class _AppLocalizationsDelegate diff --git a/lib/src/localization/generated/app_localizations_de.dart b/lib/src/localization/generated/app_localizations_de.dart index eb3a0e83..4760d924 100644 --- a/lib/src/localization/generated/app_localizations_de.dart +++ b/lib/src/localization/generated/app_localizations_de.dart @@ -1761,4 +1761,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String get settingsTypingIndicationSubtitle => 'Bei deaktivierten Tipp-Indikatoren kannst du nicht sehen, wenn andere gerade eine Nachricht tippen.'; + + @override + String get scanQrOrShow => 'QR scannen / anzeigen'; } diff --git a/lib/src/localization/generated/app_localizations_en.dart b/lib/src/localization/generated/app_localizations_en.dart index 3d84bc39..258e732b 100644 --- a/lib/src/localization/generated/app_localizations_en.dart +++ b/lib/src/localization/generated/app_localizations_en.dart @@ -1749,4 +1749,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get settingsTypingIndicationSubtitle => 'When the typing indicator is turned off, you can\'t see when others are typing a message.'; + + @override + String get scanQrOrShow => 'Scan / Show QR'; } diff --git a/lib/src/localization/generated/app_localizations_sv.dart b/lib/src/localization/generated/app_localizations_sv.dart index 0ee81ee4..8a162e2b 100644 --- a/lib/src/localization/generated/app_localizations_sv.dart +++ b/lib/src/localization/generated/app_localizations_sv.dart @@ -1749,4 +1749,7 @@ class AppLocalizationsSv extends AppLocalizations { @override String get settingsTypingIndicationSubtitle => 'When the typing indicator is turned off, you can\'t see when others are typing a message.'; + + @override + String get scanQrOrShow => 'Scan / Show QR'; } diff --git a/lib/src/services/api.service.dart b/lib/src/services/api.service.dart index 432b16b8..45bedd86 100644 --- a/lib/src/services/api.service.dart +++ b/lib/src/services/api.service.dart @@ -37,6 +37,7 @@ import 'package:twonly/src/services/notifications/pushkeys.notifications.dart'; import 'package:twonly/src/services/signal/identity.signal.dart'; import 'package:twonly/src/services/signal/utils.signal.dart'; import 'package:twonly/src/services/subscription.service.dart'; +import 'package:twonly/src/services/user_discovery.service.dart'; import 'package:twonly/src/utils/keyvalue.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; @@ -100,6 +101,7 @@ class ApiService { unawaited(retransmitAllMessages()); unawaited(tryDownloadAllMediaFiles()); unawaited(reuploadMediaFiles()); + twonlyDB.markUpdated(); unawaited(syncFlameCounters()); unawaited(setupNotificationWithUsers()); @@ -108,6 +110,8 @@ class ApiService { unawaited(fetchMissingGroupPublicKey()); unawaited(checkForDeletedUsernames()); + unawaited(UserDiscoveryService.checkForNewAnnouncedUsers()); + if (gUser.userStudyParticipantsToken != null) { // In case the user participates in the user study, call the handler after authenticated, to be sure there is a internet connection unawaited(handleUserStudyUpload()); diff --git a/lib/src/services/api/client2client/user_discovery.c2c.dart b/lib/src/services/api/client2client/user_discovery.c2c.dart new file mode 100644 index 00000000..10f383f7 --- /dev/null +++ b/lib/src/services/api/client2client/user_discovery.c2c.dart @@ -0,0 +1,78 @@ +import 'dart:typed_data'; + +import 'package:twonly/globals.dart'; +import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart'; +import 'package:twonly/src/services/api/messages.dart'; +import 'package:twonly/src/services/user_discovery.service.dart'; +import 'package:twonly/src/utils/log.dart'; + +Future checkForUserDiscoveryChanges( + int fromUserId, + List receivedVersion, +) async { + final currentVersion = await UserDiscoveryService.shouldRequestNewMessages( + fromUserId, + receivedVersion, + ); + + if (currentVersion != null) { + await sendCipherText( + fromUserId, + EncryptedContent( + userDiscoveryRequest: EncryptedContent_UserDiscoveryRequest( + currentVersion: currentVersion.toList(), + ), + ), + ); + } +} + +Future handleUserDiscoveryRequest( + int fromUserId, + EncryptedContent_UserDiscoveryRequest request, +) async { + if (!gUser.isUserDiscoveryEnabled) { + Log.warn('Got a user discovery request while it is disabled'); + return; + } + final contact = await twonlyDB.contactsDao.getContactById(fromUserId); + if (contact == null) return; + + if (contact.mediaSendCounter < gUser.minimumRequiredImagesExchanged) { + Log.warn( + 'Got a request to update user discovery, but mediaSendCounter (${contact.mediaSendCounter}) < ${gUser.minimumRequiredImagesExchanged}', + ); + return; + } + + final newMessages = await UserDiscoveryService.getNewMessages( + fromUserId, + request.currentVersion, + ); + if (newMessages != null && newMessages.isNotEmpty) { + await sendCipherText( + fromUserId, + EncryptedContent( + userDiscoveryUpdate: EncryptedContent_UserDiscoveryUpdate( + messages: newMessages, + ), + ), + ); + } else { + Log.info('Got update request, but there are no new updates for the user'); + } +} + +Future handleUserDiscoveryUpdate( + int fromUserId, + EncryptedContent_UserDiscoveryUpdate update, +) async { + if (!gUser.isUserDiscoveryEnabled) { + Log.warn('Got a user discovery update while it is disabled'); + return; + } + await UserDiscoveryService.handleNewMessages( + fromUserId, + update.messages.map(Uint8List.fromList).toList(), + ); +} diff --git a/lib/src/services/api/messages.dart b/lib/src/services/api/messages.dart index a85dcca9..11967bf3 100644 --- a/lib/src/services/api/messages.dart +++ b/lib/src/services/api/messages.dart @@ -18,6 +18,7 @@ import 'package:twonly/src/model/protobuf/client/generated/push_notification.pb. import 'package:twonly/src/services/notifications/pushkeys.notifications.dart'; import 'package:twonly/src/services/signal/encryption.signal.dart'; import 'package:twonly/src/services/signal/session.signal.dart'; +import 'package:twonly/src/services/user_discovery.service.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; @@ -344,6 +345,17 @@ Future<(Uint8List, Uint8List?)?> sendCipherText( } encryptedContent.senderProfileCounter = Int64(gUser.avatarCounter); + if (gUser.isUserDiscoveryEnabled) { + final contact = await twonlyDB.contactsDao.getContactById(contactId); + if (contact != null && + contact.mediaSendCounter >= gUser.minimumRequiredImagesExchanged) { + final version = await UserDiscoveryService.getCurrentVersion(); + if (version != null) { + encryptedContent.senderUserDiscoveryVersion = version; + } + } + } + final response = pb.Message() ..type = pb.Message_Type.CIPHERTEXT ..encryptedContent = encryptedContent.writeToBuffer(); diff --git a/lib/src/services/api/server_messages.dart b/lib/src/services/api/server_messages.dart index 3722523d..3db815c3 100644 --- a/lib/src/services/api/server_messages.dart +++ b/lib/src/services/api/server_messages.dart @@ -24,6 +24,7 @@ import 'package:twonly/src/services/api/client2client/prekeys.c2c.dart'; import 'package:twonly/src/services/api/client2client/pushkeys.c2c.dart'; import 'package:twonly/src/services/api/client2client/reaction.c2c.dart'; import 'package:twonly/src/services/api/client2client/text_message.c2c.dart'; +import 'package:twonly/src/services/api/client2client/user_discovery.c2c.dart'; import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/services/group.services.dart'; import 'package:twonly/src/services/notifications/background.notifications.dart'; @@ -262,6 +263,12 @@ Future<(EncryptedContent?, PlaintextContent?)> handleEncryptedMessage( await twonlyDB.receiptsDao.markMessagesForRetry(fromUserId); final senderProfileCounter = await checkForProfileUpdate(fromUserId, content); + if (gUser.isUserDiscoveryEnabled && content.hasSenderUserDiscoveryVersion()) { + await checkForUserDiscoveryChanges( + fromUserId, + content.senderUserDiscoveryVersion, + ); + } if (content.hasContactRequest()) { if (!await handleContactRequest(fromUserId, content.contactRequest)) { @@ -291,6 +298,22 @@ Future<(EncryptedContent?, PlaintextContent?)> handleEncryptedMessage( return (null, null); } + if (content.hasUserDiscoveryRequest()) { + await handleUserDiscoveryRequest( + fromUserId, + content.userDiscoveryRequest, + ); + return (null, null); + } + + if (content.hasUserDiscoveryUpdate()) { + await handleUserDiscoveryUpdate( + fromUserId, + content.userDiscoveryUpdate, + ); + return (null, null); + } + if (content.hasPushKeys()) { await handlePushKey(fromUserId, content.pushKeys); return (null, null); diff --git a/lib/src/services/user_discovery.service.dart b/lib/src/services/user_discovery.service.dart index 0f341fce..b46248a4 100644 --- a/lib/src/services/user_discovery.service.dart +++ b/lib/src/services/user_discovery.service.dart @@ -1,13 +1,43 @@ -import 'dart:typed_data'; - +import 'dart:convert'; +import 'package:drift/drift.dart'; import 'package:twonly/core/bridge/wrapper/user_discovery.dart'; import 'package:twonly/globals.dart'; +import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/model/protobuf/client/generated/user_discovery/types.pb.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/qr.dart'; import 'package:twonly/src/utils/storage.dart'; class UserDiscoveryService { + static Future checkForNewAnnouncedUsers() async { + final announcedUsers = await twonlyDB.userDiscoveryDao + .getNewAnnouncementsWithoutData(); + + for (final announcedUser in announcedUsers) { + final userdata = await apiService.getUserById( + announcedUser.announcedUserId, + ); + if (userdata == null) continue; + if (userdata.publicIdentityKey != + announcedUser.announcedPublicKey.toList()) { + Log.error( + 'Server delivered a different public key then received from the announcement.', + ); + continue; + } + + Log.info('Updating the username from the announced user'); + + // Updating the username, so the data will not be requested again.. + await twonlyDB.userDiscoveryDao.updateAnnouncedUser( + announcedUser.announcedUserId, + UserDiscoveryAnnouncedUsersCompanion( + username: Value(utf8.decode(userdata.username)), + ), + ); + } + } + static Future initializeOrUpdate({ required int threshold, required int minimumRequiredImagesExchanged, @@ -44,6 +74,50 @@ class UserDiscoveryService { return UserDiscoveryVersion.fromBuffer(version); } + static Future shouldRequestNewMessages( + int fromUserId, + List receivedVersion, + ) async { + try { + return await FlutterUserDiscovery.shouldRequestNewMessages( + contactId: fromUserId, + version: receivedVersion, + ); + } catch (e) { + Log.error(e); + return null; + } + } + + static Future?> getNewMessages( + int fromUserId, + List receivedVersion, + ) async { + try { + return await FlutterUserDiscovery.getNewMessages( + contactId: fromUserId, + receivedVersion: receivedVersion, + ); + } catch (e) { + Log.error(e); + return null; + } + } + + static Future handleNewMessages( + int fromUserId, + List messages, + ) async { + try { + return await FlutterUserDiscovery.handleNewMessages( + contactId: fromUserId, + messages: messages, + ); + } catch (e) { + Log.error(e); + } + } + static Future disable() async { await updateUserdata((u) { u.isUserDiscoveryEnabled = false; diff --git a/lib/src/views/chats/add_new_user.view.dart b/lib/src/views/chats/add_new_user.view.dart index f5831361..63cc643b 100644 --- a/lib/src/views/chats/add_new_user.view.dart +++ b/lib/src/views/chats/add_new_user.view.dart @@ -167,17 +167,17 @@ class _SearchUsernameView extends State { ), ), ), - Align( - alignment: Alignment.centerRight, - child: IconButton( - onPressed: () => - context.push(Routes.settingsPublicProfile), - icon: const FaIcon(FontAwesomeIcons.qrcode), - ), - ), ], ), ), + const SizedBox( + height: 20, + ), + OutlinedButton.icon( + onPressed: () => context.push(Routes.settingsPublicProfile), + icon: const FaIcon(FontAwesomeIcons.qrcode), + label: Text(context.lang.scanQrOrShow), + ), const SizedBox(height: 20), if (contacts.isNotEmpty) HeadLineComponent( diff --git a/lib/src/views/chats/chat_list.view.dart b/lib/src/views/chats/chat_list.view.dart index 9776910a..802c360e 100644 --- a/lib/src/views/chats/chat_list.view.dart +++ b/lib/src/views/chats/chat_list.view.dart @@ -34,6 +34,11 @@ class _ChatListViewState extends State { GlobalKey searchForOtherUsers = GlobalKey(); bool showFeedbackShortcut = false; + int _countContactRequest = 0; + int _countAnnouncedUsers = 0; + late StreamSubscription _countContactRequestStream; + late StreamSubscription _countAnnouncedStream; + @override void initState() { initAsync(); @@ -52,6 +57,24 @@ class _ChatListViewState extends State { }); }); + _countContactRequestStream = twonlyDB.contactsDao + .watchContactsRequestedCount() + .listen((update) { + if (update != null) { + setState(() { + _countContactRequest = update; + }); + } + }); + + _countContactRequestStream = twonlyDB.userDiscoveryDao + .watchNewAnnouncementsWithDataCount() + .listen((update) { + setState(() { + _countAnnouncedUsers = update; + }); + }); + WidgetsBinding.instance.addPostFrameCallback((_) async { final changeLog = await rootBundle.loadString('CHANGELOG.md'); final changeLogHash = (await compute( @@ -80,6 +103,8 @@ class _ChatListViewState extends State { @override void dispose() { _contactsSub.cancel(); + _countContactRequestStream.cancel(); + _countAnnouncedStream.cancel(); super.dispose(); } @@ -132,23 +157,38 @@ class _ChatListViewState extends State { ), actions: [ const FeedbackIconButton(), - StreamBuilder( - stream: twonlyDB.contactsDao.watchContactsRequestedCount(), - builder: (context, snapshot) { - var count = 0; - if (snapshot.hasData && snapshot.data != null) { - count = snapshot.data!; - } - return NotificationBadge( - count: count.toString(), - child: IconButton( - key: searchForOtherUsers, - icon: const FaIcon(FontAwesomeIcons.userPlus, size: 18), - onPressed: () => context.push(Routes.chatsAddNewUser), + Stack( + children: [ + if (_countAnnouncedUsers + _countContactRequest > 0) + Positioned.fill( + child: Center( + child: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: context.color.primary, + shape: BoxShape.circle, + ), + ), + ), ), - ); - }, + Center( + child: NotificationBadge( + count: (_countAnnouncedUsers + _countContactRequest) + .toString(), + child: IconButton( + color: (_countAnnouncedUsers + _countContactRequest > 0) + ? Colors.black + : null, + key: searchForOtherUsers, + icon: const FaIcon(FontAwesomeIcons.userPlus, size: 18), + onPressed: () => context.push(Routes.chatsAddNewUser), + ), + ), + ), + ], ), + IconButton( onPressed: () async { await context.push(Routes.settings); diff --git a/rust/src/bridge/wrapper/user_discovery.rs b/rust/src/bridge/wrapper/user_discovery.rs index 6aa24137..6c4f35f3 100644 --- a/rust/src/bridge/wrapper/user_discovery.rs +++ b/rust/src/bridge/wrapper/user_discovery.rs @@ -38,7 +38,10 @@ impl FlutterUserDiscovery { .await?) } - pub async fn should_request_new_messages(contact_id: i64, version: &[u8]) -> Result { + pub async fn should_request_new_messages( + contact_id: i64, + version: &[u8], + ) -> Result>> { Ok(get_twonly_flutter()? .user_discovery .get() @@ -47,15 +50,12 @@ impl FlutterUserDiscovery { .await?) } - pub async fn handle_user_discovery_messages( - contact_id: i64, - messages: Vec>, - ) -> Result<()> { + pub async fn handle_new_messages(contact_id: i64, messages: Vec>) -> Result<()> { Ok(get_twonly_flutter()? .user_discovery .get() .await - .handle_user_discovery_messages(contact_id, messages) + .handle_new_messages(contact_id, messages) .await?) } } diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs index 7776993e..fe5347d3 100644 --- a/rust/src/frb_generated.rs +++ b/rust/src/frb_generated.rs @@ -38,7 +38,7 @@ flutter_rust_bridge::frb_generated_boilerplate!( default_rust_auto_opaque = RustAutoOpaqueMoi, ); pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0"; -pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 523281685; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -630534473; // Section: executor @@ -77,19 +77,19 @@ let api_received_version = >::sse_decode(&mut deserializer);deserializer })().await) } }) } -fn wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_handle_user_discovery_messages_impl( +fn wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_handle_new_messages_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, rust_vec_len_: i32, data_len_: i32, ) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "flutter_user_discovery_handle_user_discovery_messages", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "flutter_user_discovery_handle_new_messages", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); let api_contact_id = ::sse_decode(&mut deserializer); let api_messages = >>::sse_decode(&mut deserializer);deserializer.end(); move |context| async move { transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || async move { - let output_ok = crate::bridge::wrapper::user_discovery::FlutterUserDiscovery::handle_user_discovery_messages(api_contact_id, api_messages).await?; Ok(output_ok) + let output_ok = crate::bridge::wrapper::user_discovery::FlutterUserDiscovery::handle_new_messages(api_contact_id, api_messages).await?; Ok(output_ok) })().await) } }) } @@ -900,7 +900,7 @@ fn pde_ffi_dispatcher_primary_impl( match func_id { 1 => wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_get_current_version_impl(port, ptr, rust_vec_len, data_len), 2 => wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_get_new_messages_impl(port, ptr, rust_vec_len, data_len), -3 => wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_handle_user_discovery_messages_impl(port, ptr, rust_vec_len, data_len), +3 => wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_handle_new_messages_impl(port, ptr, rust_vec_len, data_len), 4 => wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_initialize_or_update_impl(port, ptr, rust_vec_len, data_len), 5 => wire__crate__bridge__wrapper__user_discovery__flutter_user_discovery_should_request_new_messages_impl(port, ptr, rust_vec_len, data_len), 6 => wire__crate__bridge__callbacks__init_flutter_callbacks_impl(port, ptr, rust_vec_len, data_len), diff --git a/rust_dependencies/protocols/src/user_discovery.rs b/rust_dependencies/protocols/src/user_discovery.rs index fd54f36a..552e5e75 100644 --- a/rust_dependencies/protocols/src/user_discovery.rs +++ b/rust_dependencies/protocols/src/user_discovery.rs @@ -231,7 +231,7 @@ impl UserDiscovery Result { + ) -> Result>> { let received_version = UserDiscoveryVersion::decode(version)?; let stored_version = match self.store.get_contact_version(contact_id).await? { Some(buf) => UserDiscoveryVersion::decode(buf.as_slice())?, @@ -247,8 +247,13 @@ impl UserDiscovery stored_version.announcement - || received_version.promotion > stored_version.promotion) + if received_version.announcement > stored_version.announcement + || received_version.promotion > stored_version.promotion + { + Ok(Some(stored_version.encode_to_vec())) + } else { + Ok(None) + } } pub(crate) async fn get_contact_version(&self, contact_id: UserID) -> Result>> { @@ -257,7 +262,7 @@ impl UserDiscovery>, diff --git a/rust_dependencies/protocols/src/user_discovery/tests.rs b/rust_dependencies/protocols/src/user_discovery/tests.rs index 43b7db1f..acabc265 100644 --- a/rust_dependencies/protocols/src/user_discovery/tests.rs +++ b/rust_dependencies/protocols/src/user_discovery/tests.rs @@ -38,7 +38,8 @@ async fn assert_new_messages( assert_eq!( to.1.should_request_new_messages(from.0 as UserID, to_received_version) .await - .unwrap(), + .unwrap() + .is_some(), has_new_messages ); } @@ -53,7 +54,8 @@ async fn request_and_handle_messages( assert_eq!( to.1.should_request_new_messages(from.0 as UserID, to_received_version) .await - .unwrap(), + .unwrap() + .is_some(), true ); @@ -72,7 +74,7 @@ async fn request_and_handle_messages( assert!(new_messages.len() <= messages_count); - to.1.handle_user_discovery_messages(from.0 as UserID, new_messages) + to.1.handle_new_messages(from.0 as UserID, new_messages) .await .unwrap(); @@ -82,7 +84,8 @@ async fn request_and_handle_messages( &from.1.get_current_version().await.unwrap() ) .await - .unwrap(), + .unwrap() + .is_some(), false ); } diff --git a/test/drift/twonly_db/generated/schema.dart b/test/drift/twonly_db/generated/schema.dart index ba56c197..938ab126 100644 --- a/test/drift/twonly_db/generated/schema.dart +++ b/test/drift/twonly_db/generated/schema.dart @@ -17,6 +17,7 @@ import 'schema_v10.dart' as v10; import 'schema_v11.dart' as v11; import 'schema_v12.dart' as v12; import 'schema_v13.dart' as v13; +import 'schema_v14.dart' as v14; class GeneratedHelper implements SchemaInstantiationHelper { @override @@ -48,10 +49,12 @@ class GeneratedHelper implements SchemaInstantiationHelper { return v12.DatabaseAtV12(db); case 13: return v13.DatabaseAtV13(db); + case 14: + return v14.DatabaseAtV14(db); default: throw MissingSchemaException(version, versions); } } - static const versions = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]; + static const versions = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; } diff --git a/test/drift/twonly_db/generated/schema_v14.dart b/test/drift/twonly_db/generated/schema_v14.dart new file mode 100644 index 00000000..b71ca169 --- /dev/null +++ b/test/drift/twonly_db/generated/schema_v14.dart @@ -0,0 +1,9556 @@ +// dart format width=80 +import 'dart:typed_data' as i2; +// GENERATED BY drift_dev, DO NOT MODIFY. +// ignore_for_file: type=lint,unused_import +// +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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn username = GeneratedColumn( + 'username', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn displayName = GeneratedColumn( + 'display_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn nickName = GeneratedColumn( + 'nick_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn avatarSvgCompressed = + GeneratedColumn( + 'avatar_svg_compressed', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn senderProfileCounter = GeneratedColumn( + 'sender_profile_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn accepted = GeneratedColumn( + 'accepted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (accepted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deletedByUser = GeneratedColumn( + 'deleted_by_user', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (deleted_by_user IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn requested = GeneratedColumn( + 'requested', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (requested IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn blocked = GeneratedColumn( + 'blocked', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (blocked IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn verified = GeneratedColumn( + 'verified', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (verified IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn accountDeleted = GeneratedColumn( + 'account_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (account_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn userDiscoveryVersion = + GeneratedColumn( + 'user_discovery_version', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mediaSendCounter = GeneratedColumn( + 'media_send_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn mediaReceivedCounter = GeneratedColumn( + 'media_received_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [ + userId, + username, + displayName, + nickName, + avatarSvgCompressed, + senderProfileCounter, + accepted, + deletedByUser, + requested, + blocked, + verified, + accountDeleted, + createdAt, + userDiscoveryVersion, + mediaSendCounter, + mediaReceivedCounter, + ]; + @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'], + ), + avatarSvgCompressed: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}avatar_svg_compressed'], + ), + senderProfileCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_profile_counter'], + )!, + accepted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}accepted'], + )!, + deletedByUser: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}deleted_by_user'], + )!, + requested: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}requested'], + )!, + blocked: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}blocked'], + )!, + verified: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}verified'], + )!, + accountDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}account_deleted'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + userDiscoveryVersion: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}user_discovery_version'], + ), + mediaSendCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_send_counter'], + )!, + mediaReceivedCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_received_counter'], + )!, + ); + } + + @override + Contacts createAlias(String alias) { + return Contacts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(user_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ContactsData extends DataClass implements Insertable { + final int userId; + final String username; + final String? displayName; + final String? nickName; + final i2.Uint8List? avatarSvgCompressed; + final int senderProfileCounter; + final int accepted; + final int deletedByUser; + final int requested; + final int blocked; + final int verified; + final int accountDeleted; + final int createdAt; + final i2.Uint8List? userDiscoveryVersion; + final int mediaSendCounter; + final int mediaReceivedCounter; + const ContactsData({ + required this.userId, + required this.username, + this.displayName, + this.nickName, + this.avatarSvgCompressed, + required this.senderProfileCounter, + required this.accepted, + required this.deletedByUser, + required this.requested, + required this.blocked, + required this.verified, + required this.accountDeleted, + required this.createdAt, + this.userDiscoveryVersion, + required this.mediaSendCounter, + required this.mediaReceivedCounter, + }); + @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 || avatarSvgCompressed != null) { + map['avatar_svg_compressed'] = Variable( + avatarSvgCompressed, + ); + } + map['sender_profile_counter'] = Variable(senderProfileCounter); + map['accepted'] = Variable(accepted); + map['deleted_by_user'] = Variable(deletedByUser); + map['requested'] = Variable(requested); + map['blocked'] = Variable(blocked); + map['verified'] = Variable(verified); + map['account_deleted'] = Variable(accountDeleted); + map['created_at'] = Variable(createdAt); + if (!nullToAbsent || userDiscoveryVersion != null) { + map['user_discovery_version'] = Variable( + userDiscoveryVersion, + ); + } + map['media_send_counter'] = Variable(mediaSendCounter); + map['media_received_counter'] = Variable(mediaReceivedCounter); + 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), + avatarSvgCompressed: avatarSvgCompressed == null && nullToAbsent + ? const Value.absent() + : Value(avatarSvgCompressed), + senderProfileCounter: Value(senderProfileCounter), + accepted: Value(accepted), + deletedByUser: Value(deletedByUser), + requested: Value(requested), + blocked: Value(blocked), + verified: Value(verified), + accountDeleted: Value(accountDeleted), + createdAt: Value(createdAt), + userDiscoveryVersion: userDiscoveryVersion == null && nullToAbsent + ? const Value.absent() + : Value(userDiscoveryVersion), + mediaSendCounter: Value(mediaSendCounter), + mediaReceivedCounter: Value(mediaReceivedCounter), + ); + } + + 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']), + avatarSvgCompressed: serializer.fromJson( + json['avatarSvgCompressed'], + ), + senderProfileCounter: serializer.fromJson( + json['senderProfileCounter'], + ), + accepted: serializer.fromJson(json['accepted']), + deletedByUser: serializer.fromJson(json['deletedByUser']), + requested: serializer.fromJson(json['requested']), + blocked: serializer.fromJson(json['blocked']), + verified: serializer.fromJson(json['verified']), + accountDeleted: serializer.fromJson(json['accountDeleted']), + createdAt: serializer.fromJson(json['createdAt']), + userDiscoveryVersion: serializer.fromJson( + json['userDiscoveryVersion'], + ), + mediaSendCounter: serializer.fromJson(json['mediaSendCounter']), + mediaReceivedCounter: serializer.fromJson( + json['mediaReceivedCounter'], + ), + ); + } + @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), + 'avatarSvgCompressed': serializer.toJson( + avatarSvgCompressed, + ), + 'senderProfileCounter': serializer.toJson(senderProfileCounter), + 'accepted': serializer.toJson(accepted), + 'deletedByUser': serializer.toJson(deletedByUser), + 'requested': serializer.toJson(requested), + 'blocked': serializer.toJson(blocked), + 'verified': serializer.toJson(verified), + 'accountDeleted': serializer.toJson(accountDeleted), + 'createdAt': serializer.toJson(createdAt), + 'userDiscoveryVersion': serializer.toJson( + userDiscoveryVersion, + ), + 'mediaSendCounter': serializer.toJson(mediaSendCounter), + 'mediaReceivedCounter': serializer.toJson(mediaReceivedCounter), + }; + } + + ContactsData copyWith({ + int? userId, + String? username, + Value displayName = const Value.absent(), + Value nickName = const Value.absent(), + Value avatarSvgCompressed = const Value.absent(), + int? senderProfileCounter, + int? accepted, + int? deletedByUser, + int? requested, + int? blocked, + int? verified, + int? accountDeleted, + int? createdAt, + Value userDiscoveryVersion = const Value.absent(), + int? mediaSendCounter, + int? mediaReceivedCounter, + }) => ContactsData( + userId: userId ?? this.userId, + username: username ?? this.username, + displayName: displayName.present ? displayName.value : this.displayName, + nickName: nickName.present ? nickName.value : this.nickName, + avatarSvgCompressed: avatarSvgCompressed.present + ? avatarSvgCompressed.value + : this.avatarSvgCompressed, + senderProfileCounter: senderProfileCounter ?? this.senderProfileCounter, + accepted: accepted ?? this.accepted, + deletedByUser: deletedByUser ?? this.deletedByUser, + requested: requested ?? this.requested, + blocked: blocked ?? this.blocked, + verified: verified ?? this.verified, + accountDeleted: accountDeleted ?? this.accountDeleted, + createdAt: createdAt ?? this.createdAt, + userDiscoveryVersion: userDiscoveryVersion.present + ? userDiscoveryVersion.value + : this.userDiscoveryVersion, + mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter, + mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter, + ); + 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, + avatarSvgCompressed: data.avatarSvgCompressed.present + ? data.avatarSvgCompressed.value + : this.avatarSvgCompressed, + senderProfileCounter: data.senderProfileCounter.present + ? data.senderProfileCounter.value + : this.senderProfileCounter, + accepted: data.accepted.present ? data.accepted.value : this.accepted, + deletedByUser: data.deletedByUser.present + ? data.deletedByUser.value + : this.deletedByUser, + 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, + accountDeleted: data.accountDeleted.present + ? data.accountDeleted.value + : this.accountDeleted, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + userDiscoveryVersion: data.userDiscoveryVersion.present + ? data.userDiscoveryVersion.value + : this.userDiscoveryVersion, + mediaSendCounter: data.mediaSendCounter.present + ? data.mediaSendCounter.value + : this.mediaSendCounter, + mediaReceivedCounter: data.mediaReceivedCounter.present + ? data.mediaReceivedCounter.value + : this.mediaReceivedCounter, + ); + } + + @override + String toString() { + return (StringBuffer('ContactsData(') + ..write('userId: $userId, ') + ..write('username: $username, ') + ..write('displayName: $displayName, ') + ..write('nickName: $nickName, ') + ..write('avatarSvgCompressed: $avatarSvgCompressed, ') + ..write('senderProfileCounter: $senderProfileCounter, ') + ..write('accepted: $accepted, ') + ..write('deletedByUser: $deletedByUser, ') + ..write('requested: $requested, ') + ..write('blocked: $blocked, ') + ..write('verified: $verified, ') + ..write('accountDeleted: $accountDeleted, ') + ..write('createdAt: $createdAt, ') + ..write('userDiscoveryVersion: $userDiscoveryVersion, ') + ..write('mediaSendCounter: $mediaSendCounter, ') + ..write('mediaReceivedCounter: $mediaReceivedCounter') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + userId, + username, + displayName, + nickName, + $driftBlobEquality.hash(avatarSvgCompressed), + senderProfileCounter, + accepted, + deletedByUser, + requested, + blocked, + verified, + accountDeleted, + createdAt, + $driftBlobEquality.hash(userDiscoveryVersion), + mediaSendCounter, + mediaReceivedCounter, + ); + @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 && + $driftBlobEquality.equals( + other.avatarSvgCompressed, + this.avatarSvgCompressed, + ) && + other.senderProfileCounter == this.senderProfileCounter && + other.accepted == this.accepted && + other.deletedByUser == this.deletedByUser && + other.requested == this.requested && + other.blocked == this.blocked && + other.verified == this.verified && + other.accountDeleted == this.accountDeleted && + other.createdAt == this.createdAt && + $driftBlobEquality.equals( + other.userDiscoveryVersion, + this.userDiscoveryVersion, + ) && + other.mediaSendCounter == this.mediaSendCounter && + other.mediaReceivedCounter == this.mediaReceivedCounter); +} + +class ContactsCompanion extends UpdateCompanion { + final Value userId; + final Value username; + final Value displayName; + final Value nickName; + final Value avatarSvgCompressed; + final Value senderProfileCounter; + final Value accepted; + final Value deletedByUser; + final Value requested; + final Value blocked; + final Value verified; + final Value accountDeleted; + final Value createdAt; + final Value userDiscoveryVersion; + final Value mediaSendCounter; + final Value mediaReceivedCounter; + const ContactsCompanion({ + this.userId = const Value.absent(), + this.username = const Value.absent(), + this.displayName = const Value.absent(), + this.nickName = const Value.absent(), + this.avatarSvgCompressed = const Value.absent(), + this.senderProfileCounter = const Value.absent(), + this.accepted = const Value.absent(), + this.deletedByUser = const Value.absent(), + this.requested = const Value.absent(), + this.blocked = const Value.absent(), + this.verified = const Value.absent(), + this.accountDeleted = const Value.absent(), + this.createdAt = const Value.absent(), + this.userDiscoveryVersion = const Value.absent(), + this.mediaSendCounter = const Value.absent(), + this.mediaReceivedCounter = const Value.absent(), + }); + ContactsCompanion.insert({ + this.userId = const Value.absent(), + required String username, + this.displayName = const Value.absent(), + this.nickName = const Value.absent(), + this.avatarSvgCompressed = const Value.absent(), + this.senderProfileCounter = const Value.absent(), + this.accepted = const Value.absent(), + this.deletedByUser = const Value.absent(), + this.requested = const Value.absent(), + this.blocked = const Value.absent(), + this.verified = const Value.absent(), + this.accountDeleted = const Value.absent(), + this.createdAt = const Value.absent(), + this.userDiscoveryVersion = const Value.absent(), + this.mediaSendCounter = const Value.absent(), + this.mediaReceivedCounter = const Value.absent(), + }) : username = Value(username); + static Insertable custom({ + Expression? userId, + Expression? username, + Expression? displayName, + Expression? nickName, + Expression? avatarSvgCompressed, + Expression? senderProfileCounter, + Expression? accepted, + Expression? deletedByUser, + Expression? requested, + Expression? blocked, + Expression? verified, + Expression? accountDeleted, + Expression? createdAt, + Expression? userDiscoveryVersion, + Expression? mediaSendCounter, + Expression? mediaReceivedCounter, + }) { + 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 (avatarSvgCompressed != null) + 'avatar_svg_compressed': avatarSvgCompressed, + if (senderProfileCounter != null) + 'sender_profile_counter': senderProfileCounter, + if (accepted != null) 'accepted': accepted, + if (deletedByUser != null) 'deleted_by_user': deletedByUser, + if (requested != null) 'requested': requested, + if (blocked != null) 'blocked': blocked, + if (verified != null) 'verified': verified, + if (accountDeleted != null) 'account_deleted': accountDeleted, + if (createdAt != null) 'created_at': createdAt, + if (userDiscoveryVersion != null) + 'user_discovery_version': userDiscoveryVersion, + if (mediaSendCounter != null) 'media_send_counter': mediaSendCounter, + if (mediaReceivedCounter != null) + 'media_received_counter': mediaReceivedCounter, + }); + } + + ContactsCompanion copyWith({ + Value? userId, + Value? username, + Value? displayName, + Value? nickName, + Value? avatarSvgCompressed, + Value? senderProfileCounter, + Value? accepted, + Value? deletedByUser, + Value? requested, + Value? blocked, + Value? verified, + Value? accountDeleted, + Value? createdAt, + Value? userDiscoveryVersion, + Value? mediaSendCounter, + Value? mediaReceivedCounter, + }) { + return ContactsCompanion( + userId: userId ?? this.userId, + username: username ?? this.username, + displayName: displayName ?? this.displayName, + nickName: nickName ?? this.nickName, + avatarSvgCompressed: avatarSvgCompressed ?? this.avatarSvgCompressed, + senderProfileCounter: senderProfileCounter ?? this.senderProfileCounter, + accepted: accepted ?? this.accepted, + deletedByUser: deletedByUser ?? this.deletedByUser, + requested: requested ?? this.requested, + blocked: blocked ?? this.blocked, + verified: verified ?? this.verified, + accountDeleted: accountDeleted ?? this.accountDeleted, + createdAt: createdAt ?? this.createdAt, + userDiscoveryVersion: userDiscoveryVersion ?? this.userDiscoveryVersion, + mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter, + mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter, + ); + } + + @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 (avatarSvgCompressed.present) { + map['avatar_svg_compressed'] = Variable( + avatarSvgCompressed.value, + ); + } + if (senderProfileCounter.present) { + map['sender_profile_counter'] = Variable(senderProfileCounter.value); + } + if (accepted.present) { + map['accepted'] = Variable(accepted.value); + } + if (deletedByUser.present) { + map['deleted_by_user'] = Variable(deletedByUser.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 (accountDeleted.present) { + map['account_deleted'] = Variable(accountDeleted.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (userDiscoveryVersion.present) { + map['user_discovery_version'] = Variable( + userDiscoveryVersion.value, + ); + } + if (mediaSendCounter.present) { + map['media_send_counter'] = Variable(mediaSendCounter.value); + } + if (mediaReceivedCounter.present) { + map['media_received_counter'] = Variable(mediaReceivedCounter.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ContactsCompanion(') + ..write('userId: $userId, ') + ..write('username: $username, ') + ..write('displayName: $displayName, ') + ..write('nickName: $nickName, ') + ..write('avatarSvgCompressed: $avatarSvgCompressed, ') + ..write('senderProfileCounter: $senderProfileCounter, ') + ..write('accepted: $accepted, ') + ..write('deletedByUser: $deletedByUser, ') + ..write('requested: $requested, ') + ..write('blocked: $blocked, ') + ..write('verified: $verified, ') + ..write('accountDeleted: $accountDeleted, ') + ..write('createdAt: $createdAt, ') + ..write('userDiscoveryVersion: $userDiscoveryVersion, ') + ..write('mediaSendCounter: $mediaSendCounter, ') + ..write('mediaReceivedCounter: $mediaReceivedCounter') + ..write(')')) + .toString(); + } +} + +class Groups extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Groups(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isGroupAdmin = GeneratedColumn( + 'is_group_admin', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_group_admin IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn isDirectChat = GeneratedColumn( + 'is_direct_chat', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_direct_chat IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn pinned = GeneratedColumn( + 'pinned', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (pinned IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn archived = GeneratedColumn( + 'archived', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (archived IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn joinedGroup = GeneratedColumn( + 'joined_group', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (joined_group IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn leftGroup = GeneratedColumn( + 'left_group', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (left_group IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deletedContent = GeneratedColumn( + 'deleted_content', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (deleted_content IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stateVersionId = GeneratedColumn( + 'state_version_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stateEncryptionKey = + GeneratedColumn( + 'state_encryption_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn myGroupPrivateKey = + GeneratedColumn( + 'my_group_private_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn groupName = GeneratedColumn( + 'group_name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn draftMessage = GeneratedColumn( + 'draft_message', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn totalMediaCounter = GeneratedColumn( + 'total_media_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn alsoBestFriend = GeneratedColumn( + 'also_best_friend', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (also_best_friend IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deleteMessagesAfterMilliseconds = + GeneratedColumn( + 'delete_messages_after_milliseconds', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 86400000', + defaultValue: const CustomExpression('86400000'), + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn lastMessageSend = GeneratedColumn( + 'last_message_send', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessageReceived = GeneratedColumn( + 'last_message_received', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastFlameCounterChange = GeneratedColumn( + 'last_flame_counter_change', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastFlameSync = GeneratedColumn( + 'last_flame_sync', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn flameCounter = GeneratedColumn( + 'flame_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn maxFlameCounter = GeneratedColumn( + 'max_flame_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn maxFlameCounterFrom = GeneratedColumn( + 'max_flame_counter_from', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessageExchange = GeneratedColumn( + 'last_message_exchange', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupId, + isGroupAdmin, + isDirectChat, + pinned, + archived, + joinedGroup, + leftGroup, + deletedContent, + stateVersionId, + stateEncryptionKey, + myGroupPrivateKey, + groupName, + draftMessage, + totalMediaCounter, + alsoBestFriend, + deleteMessagesAfterMilliseconds, + createdAt, + lastMessageSend, + lastMessageReceived, + lastFlameCounterChange, + lastFlameSync, + flameCounter, + maxFlameCounter, + maxFlameCounterFrom, + lastMessageExchange, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'groups'; + @override + Set get $primaryKey => {groupId}; + @override + GroupsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupsData( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + isGroupAdmin: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_group_admin'], + )!, + isDirectChat: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_direct_chat'], + )!, + pinned: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}pinned'], + )!, + archived: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}archived'], + )!, + joinedGroup: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}joined_group'], + )!, + leftGroup: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}left_group'], + )!, + deletedContent: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}deleted_content'], + )!, + stateVersionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}state_version_id'], + )!, + stateEncryptionKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}state_encryption_key'], + ), + myGroupPrivateKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}my_group_private_key'], + ), + groupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_name'], + )!, + draftMessage: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}draft_message'], + ), + totalMediaCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}total_media_counter'], + )!, + alsoBestFriend: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}also_best_friend'], + )!, + deleteMessagesAfterMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}delete_messages_after_milliseconds'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + lastMessageSend: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_send'], + ), + lastMessageReceived: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_received'], + ), + lastFlameCounterChange: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_flame_counter_change'], + ), + lastFlameSync: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_flame_sync'], + ), + flameCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}flame_counter'], + )!, + maxFlameCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}max_flame_counter'], + )!, + maxFlameCounterFrom: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}max_flame_counter_from'], + ), + lastMessageExchange: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_exchange'], + )!, + ); + } + + @override + Groups createAlias(String alias) { + return Groups(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(group_id)']; + @override + bool get dontWriteConstraints => true; +} + +class GroupsData extends DataClass implements Insertable { + final String groupId; + final int isGroupAdmin; + final int isDirectChat; + final int pinned; + final int archived; + final int joinedGroup; + final int leftGroup; + final int deletedContent; + final int stateVersionId; + final i2.Uint8List? stateEncryptionKey; + final i2.Uint8List? myGroupPrivateKey; + final String groupName; + final String? draftMessage; + final int totalMediaCounter; + final int alsoBestFriend; + final int deleteMessagesAfterMilliseconds; + final int createdAt; + final int? lastMessageSend; + final int? lastMessageReceived; + final int? lastFlameCounterChange; + final int? lastFlameSync; + final int flameCounter; + final int maxFlameCounter; + final int? maxFlameCounterFrom; + final int lastMessageExchange; + const GroupsData({ + required this.groupId, + required this.isGroupAdmin, + required this.isDirectChat, + required this.pinned, + required this.archived, + required this.joinedGroup, + required this.leftGroup, + required this.deletedContent, + required this.stateVersionId, + this.stateEncryptionKey, + this.myGroupPrivateKey, + required this.groupName, + this.draftMessage, + required this.totalMediaCounter, + required this.alsoBestFriend, + required this.deleteMessagesAfterMilliseconds, + required this.createdAt, + this.lastMessageSend, + this.lastMessageReceived, + this.lastFlameCounterChange, + this.lastFlameSync, + required this.flameCounter, + required this.maxFlameCounter, + this.maxFlameCounterFrom, + required this.lastMessageExchange, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['is_group_admin'] = Variable(isGroupAdmin); + map['is_direct_chat'] = Variable(isDirectChat); + map['pinned'] = Variable(pinned); + map['archived'] = Variable(archived); + map['joined_group'] = Variable(joinedGroup); + map['left_group'] = Variable(leftGroup); + map['deleted_content'] = Variable(deletedContent); + map['state_version_id'] = Variable(stateVersionId); + if (!nullToAbsent || stateEncryptionKey != null) { + map['state_encryption_key'] = Variable(stateEncryptionKey); + } + if (!nullToAbsent || myGroupPrivateKey != null) { + map['my_group_private_key'] = Variable(myGroupPrivateKey); + } + map['group_name'] = Variable(groupName); + if (!nullToAbsent || draftMessage != null) { + map['draft_message'] = Variable(draftMessage); + } + map['total_media_counter'] = Variable(totalMediaCounter); + map['also_best_friend'] = Variable(alsoBestFriend); + map['delete_messages_after_milliseconds'] = Variable( + deleteMessagesAfterMilliseconds, + ); + map['created_at'] = Variable(createdAt); + 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['flame_counter'] = Variable(flameCounter); + map['max_flame_counter'] = Variable(maxFlameCounter); + if (!nullToAbsent || maxFlameCounterFrom != null) { + map['max_flame_counter_from'] = Variable(maxFlameCounterFrom); + } + map['last_message_exchange'] = Variable(lastMessageExchange); + return map; + } + + GroupsCompanion toCompanion(bool nullToAbsent) { + return GroupsCompanion( + groupId: Value(groupId), + isGroupAdmin: Value(isGroupAdmin), + isDirectChat: Value(isDirectChat), + pinned: Value(pinned), + archived: Value(archived), + joinedGroup: Value(joinedGroup), + leftGroup: Value(leftGroup), + deletedContent: Value(deletedContent), + stateVersionId: Value(stateVersionId), + stateEncryptionKey: stateEncryptionKey == null && nullToAbsent + ? const Value.absent() + : Value(stateEncryptionKey), + myGroupPrivateKey: myGroupPrivateKey == null && nullToAbsent + ? const Value.absent() + : Value(myGroupPrivateKey), + groupName: Value(groupName), + draftMessage: draftMessage == null && nullToAbsent + ? const Value.absent() + : Value(draftMessage), + totalMediaCounter: Value(totalMediaCounter), + alsoBestFriend: Value(alsoBestFriend), + deleteMessagesAfterMilliseconds: Value(deleteMessagesAfterMilliseconds), + createdAt: Value(createdAt), + 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), + flameCounter: Value(flameCounter), + maxFlameCounter: Value(maxFlameCounter), + maxFlameCounterFrom: maxFlameCounterFrom == null && nullToAbsent + ? const Value.absent() + : Value(maxFlameCounterFrom), + lastMessageExchange: Value(lastMessageExchange), + ); + } + + factory GroupsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupsData( + groupId: serializer.fromJson(json['groupId']), + isGroupAdmin: serializer.fromJson(json['isGroupAdmin']), + isDirectChat: serializer.fromJson(json['isDirectChat']), + pinned: serializer.fromJson(json['pinned']), + archived: serializer.fromJson(json['archived']), + joinedGroup: serializer.fromJson(json['joinedGroup']), + leftGroup: serializer.fromJson(json['leftGroup']), + deletedContent: serializer.fromJson(json['deletedContent']), + stateVersionId: serializer.fromJson(json['stateVersionId']), + stateEncryptionKey: serializer.fromJson( + json['stateEncryptionKey'], + ), + myGroupPrivateKey: serializer.fromJson( + json['myGroupPrivateKey'], + ), + groupName: serializer.fromJson(json['groupName']), + draftMessage: serializer.fromJson(json['draftMessage']), + totalMediaCounter: serializer.fromJson(json['totalMediaCounter']), + alsoBestFriend: serializer.fromJson(json['alsoBestFriend']), + deleteMessagesAfterMilliseconds: serializer.fromJson( + json['deleteMessagesAfterMilliseconds'], + ), + createdAt: serializer.fromJson(json['createdAt']), + lastMessageSend: serializer.fromJson(json['lastMessageSend']), + lastMessageReceived: serializer.fromJson( + json['lastMessageReceived'], + ), + lastFlameCounterChange: serializer.fromJson( + json['lastFlameCounterChange'], + ), + lastFlameSync: serializer.fromJson(json['lastFlameSync']), + flameCounter: serializer.fromJson(json['flameCounter']), + maxFlameCounter: serializer.fromJson(json['maxFlameCounter']), + maxFlameCounterFrom: serializer.fromJson( + json['maxFlameCounterFrom'], + ), + lastMessageExchange: serializer.fromJson( + json['lastMessageExchange'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'isGroupAdmin': serializer.toJson(isGroupAdmin), + 'isDirectChat': serializer.toJson(isDirectChat), + 'pinned': serializer.toJson(pinned), + 'archived': serializer.toJson(archived), + 'joinedGroup': serializer.toJson(joinedGroup), + 'leftGroup': serializer.toJson(leftGroup), + 'deletedContent': serializer.toJson(deletedContent), + 'stateVersionId': serializer.toJson(stateVersionId), + 'stateEncryptionKey': serializer.toJson( + stateEncryptionKey, + ), + 'myGroupPrivateKey': serializer.toJson(myGroupPrivateKey), + 'groupName': serializer.toJson(groupName), + 'draftMessage': serializer.toJson(draftMessage), + 'totalMediaCounter': serializer.toJson(totalMediaCounter), + 'alsoBestFriend': serializer.toJson(alsoBestFriend), + 'deleteMessagesAfterMilliseconds': serializer.toJson( + deleteMessagesAfterMilliseconds, + ), + 'createdAt': serializer.toJson(createdAt), + 'lastMessageSend': serializer.toJson(lastMessageSend), + 'lastMessageReceived': serializer.toJson(lastMessageReceived), + 'lastFlameCounterChange': serializer.toJson(lastFlameCounterChange), + 'lastFlameSync': serializer.toJson(lastFlameSync), + 'flameCounter': serializer.toJson(flameCounter), + 'maxFlameCounter': serializer.toJson(maxFlameCounter), + 'maxFlameCounterFrom': serializer.toJson(maxFlameCounterFrom), + 'lastMessageExchange': serializer.toJson(lastMessageExchange), + }; + } + + GroupsData copyWith({ + String? groupId, + int? isGroupAdmin, + int? isDirectChat, + int? pinned, + int? archived, + int? joinedGroup, + int? leftGroup, + int? deletedContent, + int? stateVersionId, + Value stateEncryptionKey = const Value.absent(), + Value myGroupPrivateKey = const Value.absent(), + String? groupName, + Value draftMessage = const Value.absent(), + int? totalMediaCounter, + int? alsoBestFriend, + int? deleteMessagesAfterMilliseconds, + int? createdAt, + Value lastMessageSend = const Value.absent(), + Value lastMessageReceived = const Value.absent(), + Value lastFlameCounterChange = const Value.absent(), + Value lastFlameSync = const Value.absent(), + int? flameCounter, + int? maxFlameCounter, + Value maxFlameCounterFrom = const Value.absent(), + int? lastMessageExchange, + }) => GroupsData( + groupId: groupId ?? this.groupId, + isGroupAdmin: isGroupAdmin ?? this.isGroupAdmin, + isDirectChat: isDirectChat ?? this.isDirectChat, + pinned: pinned ?? this.pinned, + archived: archived ?? this.archived, + joinedGroup: joinedGroup ?? this.joinedGroup, + leftGroup: leftGroup ?? this.leftGroup, + deletedContent: deletedContent ?? this.deletedContent, + stateVersionId: stateVersionId ?? this.stateVersionId, + stateEncryptionKey: stateEncryptionKey.present + ? stateEncryptionKey.value + : this.stateEncryptionKey, + myGroupPrivateKey: myGroupPrivateKey.present + ? myGroupPrivateKey.value + : this.myGroupPrivateKey, + groupName: groupName ?? this.groupName, + draftMessage: draftMessage.present ? draftMessage.value : this.draftMessage, + totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter, + alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + deleteMessagesAfterMilliseconds ?? this.deleteMessagesAfterMilliseconds, + createdAt: createdAt ?? this.createdAt, + 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, + flameCounter: flameCounter ?? this.flameCounter, + maxFlameCounter: maxFlameCounter ?? this.maxFlameCounter, + maxFlameCounterFrom: maxFlameCounterFrom.present + ? maxFlameCounterFrom.value + : this.maxFlameCounterFrom, + lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, + ); + GroupsData copyWithCompanion(GroupsCompanion data) { + return GroupsData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + isGroupAdmin: data.isGroupAdmin.present + ? data.isGroupAdmin.value + : this.isGroupAdmin, + isDirectChat: data.isDirectChat.present + ? data.isDirectChat.value + : this.isDirectChat, + pinned: data.pinned.present ? data.pinned.value : this.pinned, + archived: data.archived.present ? data.archived.value : this.archived, + joinedGroup: data.joinedGroup.present + ? data.joinedGroup.value + : this.joinedGroup, + leftGroup: data.leftGroup.present ? data.leftGroup.value : this.leftGroup, + deletedContent: data.deletedContent.present + ? data.deletedContent.value + : this.deletedContent, + stateVersionId: data.stateVersionId.present + ? data.stateVersionId.value + : this.stateVersionId, + stateEncryptionKey: data.stateEncryptionKey.present + ? data.stateEncryptionKey.value + : this.stateEncryptionKey, + myGroupPrivateKey: data.myGroupPrivateKey.present + ? data.myGroupPrivateKey.value + : this.myGroupPrivateKey, + groupName: data.groupName.present ? data.groupName.value : this.groupName, + draftMessage: data.draftMessage.present + ? data.draftMessage.value + : this.draftMessage, + totalMediaCounter: data.totalMediaCounter.present + ? data.totalMediaCounter.value + : this.totalMediaCounter, + alsoBestFriend: data.alsoBestFriend.present + ? data.alsoBestFriend.value + : this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + data.deleteMessagesAfterMilliseconds.present + ? data.deleteMessagesAfterMilliseconds.value + : this.deleteMessagesAfterMilliseconds, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + 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, + flameCounter: data.flameCounter.present + ? data.flameCounter.value + : this.flameCounter, + maxFlameCounter: data.maxFlameCounter.present + ? data.maxFlameCounter.value + : this.maxFlameCounter, + maxFlameCounterFrom: data.maxFlameCounterFrom.present + ? data.maxFlameCounterFrom.value + : this.maxFlameCounterFrom, + lastMessageExchange: data.lastMessageExchange.present + ? data.lastMessageExchange.value + : this.lastMessageExchange, + ); + } + + @override + String toString() { + return (StringBuffer('GroupsData(') + ..write('groupId: $groupId, ') + ..write('isGroupAdmin: $isGroupAdmin, ') + ..write('isDirectChat: $isDirectChat, ') + ..write('pinned: $pinned, ') + ..write('archived: $archived, ') + ..write('joinedGroup: $joinedGroup, ') + ..write('leftGroup: $leftGroup, ') + ..write('deletedContent: $deletedContent, ') + ..write('stateVersionId: $stateVersionId, ') + ..write('stateEncryptionKey: $stateEncryptionKey, ') + ..write('myGroupPrivateKey: $myGroupPrivateKey, ') + ..write('groupName: $groupName, ') + ..write('draftMessage: $draftMessage, ') + ..write('totalMediaCounter: $totalMediaCounter, ') + ..write('alsoBestFriend: $alsoBestFriend, ') + ..write( + 'deleteMessagesAfterMilliseconds: $deleteMessagesAfterMilliseconds, ', + ) + ..write('createdAt: $createdAt, ') + ..write('lastMessageSend: $lastMessageSend, ') + ..write('lastMessageReceived: $lastMessageReceived, ') + ..write('lastFlameCounterChange: $lastFlameCounterChange, ') + ..write('lastFlameSync: $lastFlameSync, ') + ..write('flameCounter: $flameCounter, ') + ..write('maxFlameCounter: $maxFlameCounter, ') + ..write('maxFlameCounterFrom: $maxFlameCounterFrom, ') + ..write('lastMessageExchange: $lastMessageExchange') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hashAll([ + groupId, + isGroupAdmin, + isDirectChat, + pinned, + archived, + joinedGroup, + leftGroup, + deletedContent, + stateVersionId, + $driftBlobEquality.hash(stateEncryptionKey), + $driftBlobEquality.hash(myGroupPrivateKey), + groupName, + draftMessage, + totalMediaCounter, + alsoBestFriend, + deleteMessagesAfterMilliseconds, + createdAt, + lastMessageSend, + lastMessageReceived, + lastFlameCounterChange, + lastFlameSync, + flameCounter, + maxFlameCounter, + maxFlameCounterFrom, + lastMessageExchange, + ]); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupsData && + other.groupId == this.groupId && + other.isGroupAdmin == this.isGroupAdmin && + other.isDirectChat == this.isDirectChat && + other.pinned == this.pinned && + other.archived == this.archived && + other.joinedGroup == this.joinedGroup && + other.leftGroup == this.leftGroup && + other.deletedContent == this.deletedContent && + other.stateVersionId == this.stateVersionId && + $driftBlobEquality.equals( + other.stateEncryptionKey, + this.stateEncryptionKey, + ) && + $driftBlobEquality.equals( + other.myGroupPrivateKey, + this.myGroupPrivateKey, + ) && + other.groupName == this.groupName && + other.draftMessage == this.draftMessage && + other.totalMediaCounter == this.totalMediaCounter && + other.alsoBestFriend == this.alsoBestFriend && + other.deleteMessagesAfterMilliseconds == + this.deleteMessagesAfterMilliseconds && + other.createdAt == this.createdAt && + other.lastMessageSend == this.lastMessageSend && + other.lastMessageReceived == this.lastMessageReceived && + other.lastFlameCounterChange == this.lastFlameCounterChange && + other.lastFlameSync == this.lastFlameSync && + other.flameCounter == this.flameCounter && + other.maxFlameCounter == this.maxFlameCounter && + other.maxFlameCounterFrom == this.maxFlameCounterFrom && + other.lastMessageExchange == this.lastMessageExchange); +} + +class GroupsCompanion extends UpdateCompanion { + final Value groupId; + final Value isGroupAdmin; + final Value isDirectChat; + final Value pinned; + final Value archived; + final Value joinedGroup; + final Value leftGroup; + final Value deletedContent; + final Value stateVersionId; + final Value stateEncryptionKey; + final Value myGroupPrivateKey; + final Value groupName; + final Value draftMessage; + final Value totalMediaCounter; + final Value alsoBestFriend; + final Value deleteMessagesAfterMilliseconds; + final Value createdAt; + final Value lastMessageSend; + final Value lastMessageReceived; + final Value lastFlameCounterChange; + final Value lastFlameSync; + final Value flameCounter; + final Value maxFlameCounter; + final Value maxFlameCounterFrom; + final Value lastMessageExchange; + final Value rowid; + const GroupsCompanion({ + this.groupId = const Value.absent(), + this.isGroupAdmin = const Value.absent(), + this.isDirectChat = const Value.absent(), + this.pinned = const Value.absent(), + this.archived = const Value.absent(), + this.joinedGroup = const Value.absent(), + this.leftGroup = const Value.absent(), + this.deletedContent = const Value.absent(), + this.stateVersionId = const Value.absent(), + this.stateEncryptionKey = const Value.absent(), + this.myGroupPrivateKey = const Value.absent(), + this.groupName = const Value.absent(), + this.draftMessage = const Value.absent(), + this.totalMediaCounter = const Value.absent(), + this.alsoBestFriend = const Value.absent(), + this.deleteMessagesAfterMilliseconds = const Value.absent(), + this.createdAt = const Value.absent(), + this.lastMessageSend = const Value.absent(), + this.lastMessageReceived = const Value.absent(), + this.lastFlameCounterChange = const Value.absent(), + this.lastFlameSync = const Value.absent(), + this.flameCounter = const Value.absent(), + this.maxFlameCounter = const Value.absent(), + this.maxFlameCounterFrom = const Value.absent(), + this.lastMessageExchange = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupsCompanion.insert({ + required String groupId, + this.isGroupAdmin = const Value.absent(), + this.isDirectChat = const Value.absent(), + this.pinned = const Value.absent(), + this.archived = const Value.absent(), + this.joinedGroup = const Value.absent(), + this.leftGroup = const Value.absent(), + this.deletedContent = const Value.absent(), + this.stateVersionId = const Value.absent(), + this.stateEncryptionKey = const Value.absent(), + this.myGroupPrivateKey = const Value.absent(), + required String groupName, + this.draftMessage = const Value.absent(), + this.totalMediaCounter = const Value.absent(), + this.alsoBestFriend = const Value.absent(), + this.deleteMessagesAfterMilliseconds = const Value.absent(), + this.createdAt = const Value.absent(), + this.lastMessageSend = const Value.absent(), + this.lastMessageReceived = const Value.absent(), + this.lastFlameCounterChange = const Value.absent(), + this.lastFlameSync = const Value.absent(), + this.flameCounter = const Value.absent(), + this.maxFlameCounter = const Value.absent(), + this.maxFlameCounterFrom = const Value.absent(), + this.lastMessageExchange = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + groupName = Value(groupName); + static Insertable custom({ + Expression? groupId, + Expression? isGroupAdmin, + Expression? isDirectChat, + Expression? pinned, + Expression? archived, + Expression? joinedGroup, + Expression? leftGroup, + Expression? deletedContent, + Expression? stateVersionId, + Expression? stateEncryptionKey, + Expression? myGroupPrivateKey, + Expression? groupName, + Expression? draftMessage, + Expression? totalMediaCounter, + Expression? alsoBestFriend, + Expression? deleteMessagesAfterMilliseconds, + Expression? createdAt, + Expression? lastMessageSend, + Expression? lastMessageReceived, + Expression? lastFlameCounterChange, + Expression? lastFlameSync, + Expression? flameCounter, + Expression? maxFlameCounter, + Expression? maxFlameCounterFrom, + Expression? lastMessageExchange, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (isGroupAdmin != null) 'is_group_admin': isGroupAdmin, + if (isDirectChat != null) 'is_direct_chat': isDirectChat, + if (pinned != null) 'pinned': pinned, + if (archived != null) 'archived': archived, + if (joinedGroup != null) 'joined_group': joinedGroup, + if (leftGroup != null) 'left_group': leftGroup, + if (deletedContent != null) 'deleted_content': deletedContent, + if (stateVersionId != null) 'state_version_id': stateVersionId, + if (stateEncryptionKey != null) + 'state_encryption_key': stateEncryptionKey, + if (myGroupPrivateKey != null) 'my_group_private_key': myGroupPrivateKey, + if (groupName != null) 'group_name': groupName, + if (draftMessage != null) 'draft_message': draftMessage, + if (totalMediaCounter != null) 'total_media_counter': totalMediaCounter, + if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend, + if (deleteMessagesAfterMilliseconds != null) + 'delete_messages_after_milliseconds': deleteMessagesAfterMilliseconds, + if (createdAt != null) 'created_at': createdAt, + 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 (flameCounter != null) 'flame_counter': flameCounter, + if (maxFlameCounter != null) 'max_flame_counter': maxFlameCounter, + if (maxFlameCounterFrom != null) + 'max_flame_counter_from': maxFlameCounterFrom, + if (lastMessageExchange != null) + 'last_message_exchange': lastMessageExchange, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupsCompanion copyWith({ + Value? groupId, + Value? isGroupAdmin, + Value? isDirectChat, + Value? pinned, + Value? archived, + Value? joinedGroup, + Value? leftGroup, + Value? deletedContent, + Value? stateVersionId, + Value? stateEncryptionKey, + Value? myGroupPrivateKey, + Value? groupName, + Value? draftMessage, + Value? totalMediaCounter, + Value? alsoBestFriend, + Value? deleteMessagesAfterMilliseconds, + Value? createdAt, + Value? lastMessageSend, + Value? lastMessageReceived, + Value? lastFlameCounterChange, + Value? lastFlameSync, + Value? flameCounter, + Value? maxFlameCounter, + Value? maxFlameCounterFrom, + Value? lastMessageExchange, + Value? rowid, + }) { + return GroupsCompanion( + groupId: groupId ?? this.groupId, + isGroupAdmin: isGroupAdmin ?? this.isGroupAdmin, + isDirectChat: isDirectChat ?? this.isDirectChat, + pinned: pinned ?? this.pinned, + archived: archived ?? this.archived, + joinedGroup: joinedGroup ?? this.joinedGroup, + leftGroup: leftGroup ?? this.leftGroup, + deletedContent: deletedContent ?? this.deletedContent, + stateVersionId: stateVersionId ?? this.stateVersionId, + stateEncryptionKey: stateEncryptionKey ?? this.stateEncryptionKey, + myGroupPrivateKey: myGroupPrivateKey ?? this.myGroupPrivateKey, + groupName: groupName ?? this.groupName, + draftMessage: draftMessage ?? this.draftMessage, + totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter, + alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + deleteMessagesAfterMilliseconds ?? + this.deleteMessagesAfterMilliseconds, + createdAt: createdAt ?? this.createdAt, + lastMessageSend: lastMessageSend ?? this.lastMessageSend, + lastMessageReceived: lastMessageReceived ?? this.lastMessageReceived, + lastFlameCounterChange: + lastFlameCounterChange ?? this.lastFlameCounterChange, + lastFlameSync: lastFlameSync ?? this.lastFlameSync, + flameCounter: flameCounter ?? this.flameCounter, + maxFlameCounter: maxFlameCounter ?? this.maxFlameCounter, + maxFlameCounterFrom: maxFlameCounterFrom ?? this.maxFlameCounterFrom, + lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (isGroupAdmin.present) { + map['is_group_admin'] = Variable(isGroupAdmin.value); + } + if (isDirectChat.present) { + map['is_direct_chat'] = Variable(isDirectChat.value); + } + if (pinned.present) { + map['pinned'] = Variable(pinned.value); + } + if (archived.present) { + map['archived'] = Variable(archived.value); + } + if (joinedGroup.present) { + map['joined_group'] = Variable(joinedGroup.value); + } + if (leftGroup.present) { + map['left_group'] = Variable(leftGroup.value); + } + if (deletedContent.present) { + map['deleted_content'] = Variable(deletedContent.value); + } + if (stateVersionId.present) { + map['state_version_id'] = Variable(stateVersionId.value); + } + if (stateEncryptionKey.present) { + map['state_encryption_key'] = Variable( + stateEncryptionKey.value, + ); + } + if (myGroupPrivateKey.present) { + map['my_group_private_key'] = Variable( + myGroupPrivateKey.value, + ); + } + if (groupName.present) { + map['group_name'] = Variable(groupName.value); + } + if (draftMessage.present) { + map['draft_message'] = Variable(draftMessage.value); + } + if (totalMediaCounter.present) { + map['total_media_counter'] = Variable(totalMediaCounter.value); + } + if (alsoBestFriend.present) { + map['also_best_friend'] = Variable(alsoBestFriend.value); + } + if (deleteMessagesAfterMilliseconds.present) { + map['delete_messages_after_milliseconds'] = Variable( + deleteMessagesAfterMilliseconds.value, + ); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.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 (flameCounter.present) { + map['flame_counter'] = Variable(flameCounter.value); + } + if (maxFlameCounter.present) { + map['max_flame_counter'] = Variable(maxFlameCounter.value); + } + if (maxFlameCounterFrom.present) { + map['max_flame_counter_from'] = Variable(maxFlameCounterFrom.value); + } + if (lastMessageExchange.present) { + map['last_message_exchange'] = Variable(lastMessageExchange.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GroupsCompanion(') + ..write('groupId: $groupId, ') + ..write('isGroupAdmin: $isGroupAdmin, ') + ..write('isDirectChat: $isDirectChat, ') + ..write('pinned: $pinned, ') + ..write('archived: $archived, ') + ..write('joinedGroup: $joinedGroup, ') + ..write('leftGroup: $leftGroup, ') + ..write('deletedContent: $deletedContent, ') + ..write('stateVersionId: $stateVersionId, ') + ..write('stateEncryptionKey: $stateEncryptionKey, ') + ..write('myGroupPrivateKey: $myGroupPrivateKey, ') + ..write('groupName: $groupName, ') + ..write('draftMessage: $draftMessage, ') + ..write('totalMediaCounter: $totalMediaCounter, ') + ..write('alsoBestFriend: $alsoBestFriend, ') + ..write( + 'deleteMessagesAfterMilliseconds: $deleteMessagesAfterMilliseconds, ', + ) + ..write('createdAt: $createdAt, ') + ..write('lastMessageSend: $lastMessageSend, ') + ..write('lastMessageReceived: $lastMessageReceived, ') + ..write('lastFlameCounterChange: $lastFlameCounterChange, ') + ..write('lastFlameSync: $lastFlameSync, ') + ..write('flameCounter: $flameCounter, ') + ..write('maxFlameCounter: $maxFlameCounter, ') + ..write('maxFlameCounterFrom: $maxFlameCounterFrom, ') + ..write('lastMessageExchange: $lastMessageExchange, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class MediaFiles extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MediaFiles(this.attachedDatabase, [this._alias]); + late final GeneratedColumn mediaId = GeneratedColumn( + 'media_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn uploadState = GeneratedColumn( + 'upload_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn downloadState = GeneratedColumn( + 'download_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn requiresAuthentication = GeneratedColumn( + 'requires_authentication', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (requires_authentication IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stored = GeneratedColumn( + 'stored', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK ("stored" IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn isDraftMedia = GeneratedColumn( + 'is_draft_media', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_draft_media IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn preProgressingProcess = GeneratedColumn( + 'pre_progressing_process', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn reuploadRequestedBy = + GeneratedColumn( + 'reupload_requested_by', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn displayLimitInMilliseconds = + GeneratedColumn( + 'display_limit_in_milliseconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn removeAudio = GeneratedColumn( + 'remove_audio', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL CHECK (remove_audio IN (0, 1))', + ); + late final GeneratedColumn downloadToken = + GeneratedColumn( + 'download_token', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionKey = + GeneratedColumn( + 'encryption_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionMac = + GeneratedColumn( + 'encryption_mac', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionNonce = + GeneratedColumn( + 'encryption_nonce', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn storedFileHash = + GeneratedColumn( + 'stored_file_hash', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + mediaId, + type, + uploadState, + downloadState, + requiresAuthentication, + stored, + isDraftMedia, + preProgressingProcess, + reuploadRequestedBy, + displayLimitInMilliseconds, + removeAudio, + downloadToken, + encryptionKey, + encryptionMac, + encryptionNonce, + storedFileHash, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'media_files'; + @override + Set get $primaryKey => {mediaId}; + @override + MediaFilesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MediaFilesData( + mediaId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}media_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + uploadState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}upload_state'], + ), + downloadState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}download_state'], + ), + requiresAuthentication: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}requires_authentication'], + )!, + stored: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}stored'], + )!, + isDraftMedia: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_draft_media'], + )!, + preProgressingProcess: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}pre_progressing_process'], + ), + reuploadRequestedBy: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}reupload_requested_by'], + ), + displayLimitInMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}display_limit_in_milliseconds'], + ), + removeAudio: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}remove_audio'], + ), + downloadToken: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}download_token'], + ), + encryptionKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_key'], + ), + encryptionMac: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_mac'], + ), + encryptionNonce: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_nonce'], + ), + storedFileHash: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}stored_file_hash'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + MediaFiles createAlias(String alias) { + return MediaFiles(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(media_id)']; + @override + bool get dontWriteConstraints => true; +} + +class MediaFilesData extends DataClass implements Insertable { + final String mediaId; + final String type; + final String? uploadState; + final String? downloadState; + final int requiresAuthentication; + final int stored; + final int isDraftMedia; + final int? preProgressingProcess; + final String? reuploadRequestedBy; + final int? displayLimitInMilliseconds; + final int? removeAudio; + final i2.Uint8List? downloadToken; + final i2.Uint8List? encryptionKey; + final i2.Uint8List? encryptionMac; + final i2.Uint8List? encryptionNonce; + final i2.Uint8List? storedFileHash; + final int createdAt; + const MediaFilesData({ + required this.mediaId, + required this.type, + this.uploadState, + this.downloadState, + required this.requiresAuthentication, + required this.stored, + required this.isDraftMedia, + this.preProgressingProcess, + this.reuploadRequestedBy, + this.displayLimitInMilliseconds, + this.removeAudio, + this.downloadToken, + this.encryptionKey, + this.encryptionMac, + this.encryptionNonce, + this.storedFileHash, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['media_id'] = Variable(mediaId); + map['type'] = Variable(type); + if (!nullToAbsent || uploadState != null) { + map['upload_state'] = Variable(uploadState); + } + if (!nullToAbsent || downloadState != null) { + map['download_state'] = Variable(downloadState); + } + map['requires_authentication'] = Variable(requiresAuthentication); + map['stored'] = Variable(stored); + map['is_draft_media'] = Variable(isDraftMedia); + if (!nullToAbsent || preProgressingProcess != null) { + map['pre_progressing_process'] = Variable(preProgressingProcess); + } + if (!nullToAbsent || reuploadRequestedBy != null) { + map['reupload_requested_by'] = Variable(reuploadRequestedBy); + } + if (!nullToAbsent || displayLimitInMilliseconds != null) { + map['display_limit_in_milliseconds'] = Variable( + displayLimitInMilliseconds, + ); + } + if (!nullToAbsent || removeAudio != null) { + map['remove_audio'] = Variable(removeAudio); + } + if (!nullToAbsent || downloadToken != null) { + map['download_token'] = Variable(downloadToken); + } + if (!nullToAbsent || encryptionKey != null) { + map['encryption_key'] = Variable(encryptionKey); + } + if (!nullToAbsent || encryptionMac != null) { + map['encryption_mac'] = Variable(encryptionMac); + } + if (!nullToAbsent || encryptionNonce != null) { + map['encryption_nonce'] = Variable(encryptionNonce); + } + if (!nullToAbsent || storedFileHash != null) { + map['stored_file_hash'] = Variable(storedFileHash); + } + map['created_at'] = Variable(createdAt); + return map; + } + + MediaFilesCompanion toCompanion(bool nullToAbsent) { + return MediaFilesCompanion( + mediaId: Value(mediaId), + type: Value(type), + uploadState: uploadState == null && nullToAbsent + ? const Value.absent() + : Value(uploadState), + downloadState: downloadState == null && nullToAbsent + ? const Value.absent() + : Value(downloadState), + requiresAuthentication: Value(requiresAuthentication), + stored: Value(stored), + isDraftMedia: Value(isDraftMedia), + preProgressingProcess: preProgressingProcess == null && nullToAbsent + ? const Value.absent() + : Value(preProgressingProcess), + reuploadRequestedBy: reuploadRequestedBy == null && nullToAbsent + ? const Value.absent() + : Value(reuploadRequestedBy), + displayLimitInMilliseconds: + displayLimitInMilliseconds == null && nullToAbsent + ? const Value.absent() + : Value(displayLimitInMilliseconds), + removeAudio: removeAudio == null && nullToAbsent + ? const Value.absent() + : Value(removeAudio), + downloadToken: downloadToken == null && nullToAbsent + ? const Value.absent() + : Value(downloadToken), + encryptionKey: encryptionKey == null && nullToAbsent + ? const Value.absent() + : Value(encryptionKey), + encryptionMac: encryptionMac == null && nullToAbsent + ? const Value.absent() + : Value(encryptionMac), + encryptionNonce: encryptionNonce == null && nullToAbsent + ? const Value.absent() + : Value(encryptionNonce), + storedFileHash: storedFileHash == null && nullToAbsent + ? const Value.absent() + : Value(storedFileHash), + createdAt: Value(createdAt), + ); + } + + factory MediaFilesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MediaFilesData( + mediaId: serializer.fromJson(json['mediaId']), + type: serializer.fromJson(json['type']), + uploadState: serializer.fromJson(json['uploadState']), + downloadState: serializer.fromJson(json['downloadState']), + requiresAuthentication: serializer.fromJson( + json['requiresAuthentication'], + ), + stored: serializer.fromJson(json['stored']), + isDraftMedia: serializer.fromJson(json['isDraftMedia']), + preProgressingProcess: serializer.fromJson( + json['preProgressingProcess'], + ), + reuploadRequestedBy: serializer.fromJson( + json['reuploadRequestedBy'], + ), + displayLimitInMilliseconds: serializer.fromJson( + json['displayLimitInMilliseconds'], + ), + removeAudio: serializer.fromJson(json['removeAudio']), + downloadToken: serializer.fromJson(json['downloadToken']), + encryptionKey: serializer.fromJson(json['encryptionKey']), + encryptionMac: serializer.fromJson(json['encryptionMac']), + encryptionNonce: serializer.fromJson( + json['encryptionNonce'], + ), + storedFileHash: serializer.fromJson( + json['storedFileHash'], + ), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'mediaId': serializer.toJson(mediaId), + 'type': serializer.toJson(type), + 'uploadState': serializer.toJson(uploadState), + 'downloadState': serializer.toJson(downloadState), + 'requiresAuthentication': serializer.toJson(requiresAuthentication), + 'stored': serializer.toJson(stored), + 'isDraftMedia': serializer.toJson(isDraftMedia), + 'preProgressingProcess': serializer.toJson(preProgressingProcess), + 'reuploadRequestedBy': serializer.toJson(reuploadRequestedBy), + 'displayLimitInMilliseconds': serializer.toJson( + displayLimitInMilliseconds, + ), + 'removeAudio': serializer.toJson(removeAudio), + 'downloadToken': serializer.toJson(downloadToken), + 'encryptionKey': serializer.toJson(encryptionKey), + 'encryptionMac': serializer.toJson(encryptionMac), + 'encryptionNonce': serializer.toJson(encryptionNonce), + 'storedFileHash': serializer.toJson(storedFileHash), + 'createdAt': serializer.toJson(createdAt), + }; + } + + MediaFilesData copyWith({ + String? mediaId, + String? type, + Value uploadState = const Value.absent(), + Value downloadState = const Value.absent(), + int? requiresAuthentication, + int? stored, + int? isDraftMedia, + Value preProgressingProcess = const Value.absent(), + Value reuploadRequestedBy = const Value.absent(), + Value displayLimitInMilliseconds = const Value.absent(), + Value removeAudio = const Value.absent(), + Value downloadToken = const Value.absent(), + Value encryptionKey = const Value.absent(), + Value encryptionMac = const Value.absent(), + Value encryptionNonce = const Value.absent(), + Value storedFileHash = const Value.absent(), + int? createdAt, + }) => MediaFilesData( + mediaId: mediaId ?? this.mediaId, + type: type ?? this.type, + uploadState: uploadState.present ? uploadState.value : this.uploadState, + downloadState: downloadState.present + ? downloadState.value + : this.downloadState, + requiresAuthentication: + requiresAuthentication ?? this.requiresAuthentication, + stored: stored ?? this.stored, + isDraftMedia: isDraftMedia ?? this.isDraftMedia, + preProgressingProcess: preProgressingProcess.present + ? preProgressingProcess.value + : this.preProgressingProcess, + reuploadRequestedBy: reuploadRequestedBy.present + ? reuploadRequestedBy.value + : this.reuploadRequestedBy, + displayLimitInMilliseconds: displayLimitInMilliseconds.present + ? displayLimitInMilliseconds.value + : this.displayLimitInMilliseconds, + removeAudio: removeAudio.present ? removeAudio.value : this.removeAudio, + downloadToken: downloadToken.present + ? downloadToken.value + : this.downloadToken, + encryptionKey: encryptionKey.present + ? encryptionKey.value + : this.encryptionKey, + encryptionMac: encryptionMac.present + ? encryptionMac.value + : this.encryptionMac, + encryptionNonce: encryptionNonce.present + ? encryptionNonce.value + : this.encryptionNonce, + storedFileHash: storedFileHash.present + ? storedFileHash.value + : this.storedFileHash, + createdAt: createdAt ?? this.createdAt, + ); + MediaFilesData copyWithCompanion(MediaFilesCompanion data) { + return MediaFilesData( + mediaId: data.mediaId.present ? data.mediaId.value : this.mediaId, + type: data.type.present ? data.type.value : this.type, + uploadState: data.uploadState.present + ? data.uploadState.value + : this.uploadState, + downloadState: data.downloadState.present + ? data.downloadState.value + : this.downloadState, + requiresAuthentication: data.requiresAuthentication.present + ? data.requiresAuthentication.value + : this.requiresAuthentication, + stored: data.stored.present ? data.stored.value : this.stored, + isDraftMedia: data.isDraftMedia.present + ? data.isDraftMedia.value + : this.isDraftMedia, + preProgressingProcess: data.preProgressingProcess.present + ? data.preProgressingProcess.value + : this.preProgressingProcess, + reuploadRequestedBy: data.reuploadRequestedBy.present + ? data.reuploadRequestedBy.value + : this.reuploadRequestedBy, + displayLimitInMilliseconds: data.displayLimitInMilliseconds.present + ? data.displayLimitInMilliseconds.value + : this.displayLimitInMilliseconds, + removeAudio: data.removeAudio.present + ? data.removeAudio.value + : this.removeAudio, + downloadToken: data.downloadToken.present + ? data.downloadToken.value + : this.downloadToken, + encryptionKey: data.encryptionKey.present + ? data.encryptionKey.value + : this.encryptionKey, + encryptionMac: data.encryptionMac.present + ? data.encryptionMac.value + : this.encryptionMac, + encryptionNonce: data.encryptionNonce.present + ? data.encryptionNonce.value + : this.encryptionNonce, + storedFileHash: data.storedFileHash.present + ? data.storedFileHash.value + : this.storedFileHash, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('MediaFilesData(') + ..write('mediaId: $mediaId, ') + ..write('type: $type, ') + ..write('uploadState: $uploadState, ') + ..write('downloadState: $downloadState, ') + ..write('requiresAuthentication: $requiresAuthentication, ') + ..write('stored: $stored, ') + ..write('isDraftMedia: $isDraftMedia, ') + ..write('preProgressingProcess: $preProgressingProcess, ') + ..write('reuploadRequestedBy: $reuploadRequestedBy, ') + ..write('displayLimitInMilliseconds: $displayLimitInMilliseconds, ') + ..write('removeAudio: $removeAudio, ') + ..write('downloadToken: $downloadToken, ') + ..write('encryptionKey: $encryptionKey, ') + ..write('encryptionMac: $encryptionMac, ') + ..write('encryptionNonce: $encryptionNonce, ') + ..write('storedFileHash: $storedFileHash, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + mediaId, + type, + uploadState, + downloadState, + requiresAuthentication, + stored, + isDraftMedia, + preProgressingProcess, + reuploadRequestedBy, + displayLimitInMilliseconds, + removeAudio, + $driftBlobEquality.hash(downloadToken), + $driftBlobEquality.hash(encryptionKey), + $driftBlobEquality.hash(encryptionMac), + $driftBlobEquality.hash(encryptionNonce), + $driftBlobEquality.hash(storedFileHash), + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MediaFilesData && + other.mediaId == this.mediaId && + other.type == this.type && + other.uploadState == this.uploadState && + other.downloadState == this.downloadState && + other.requiresAuthentication == this.requiresAuthentication && + other.stored == this.stored && + other.isDraftMedia == this.isDraftMedia && + other.preProgressingProcess == this.preProgressingProcess && + other.reuploadRequestedBy == this.reuploadRequestedBy && + other.displayLimitInMilliseconds == this.displayLimitInMilliseconds && + other.removeAudio == this.removeAudio && + $driftBlobEquality.equals(other.downloadToken, this.downloadToken) && + $driftBlobEquality.equals(other.encryptionKey, this.encryptionKey) && + $driftBlobEquality.equals(other.encryptionMac, this.encryptionMac) && + $driftBlobEquality.equals( + other.encryptionNonce, + this.encryptionNonce, + ) && + $driftBlobEquality.equals( + other.storedFileHash, + this.storedFileHash, + ) && + other.createdAt == this.createdAt); +} + +class MediaFilesCompanion extends UpdateCompanion { + final Value mediaId; + final Value type; + final Value uploadState; + final Value downloadState; + final Value requiresAuthentication; + final Value stored; + final Value isDraftMedia; + final Value preProgressingProcess; + final Value reuploadRequestedBy; + final Value displayLimitInMilliseconds; + final Value removeAudio; + final Value downloadToken; + final Value encryptionKey; + final Value encryptionMac; + final Value encryptionNonce; + final Value storedFileHash; + final Value createdAt; + final Value rowid; + const MediaFilesCompanion({ + this.mediaId = const Value.absent(), + this.type = const Value.absent(), + this.uploadState = const Value.absent(), + this.downloadState = const Value.absent(), + this.requiresAuthentication = const Value.absent(), + this.stored = const Value.absent(), + this.isDraftMedia = const Value.absent(), + this.preProgressingProcess = const Value.absent(), + this.reuploadRequestedBy = const Value.absent(), + this.displayLimitInMilliseconds = const Value.absent(), + this.removeAudio = const Value.absent(), + this.downloadToken = const Value.absent(), + this.encryptionKey = const Value.absent(), + this.encryptionMac = const Value.absent(), + this.encryptionNonce = const Value.absent(), + this.storedFileHash = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + MediaFilesCompanion.insert({ + required String mediaId, + required String type, + this.uploadState = const Value.absent(), + this.downloadState = const Value.absent(), + this.requiresAuthentication = const Value.absent(), + this.stored = const Value.absent(), + this.isDraftMedia = const Value.absent(), + this.preProgressingProcess = const Value.absent(), + this.reuploadRequestedBy = const Value.absent(), + this.displayLimitInMilliseconds = const Value.absent(), + this.removeAudio = const Value.absent(), + this.downloadToken = const Value.absent(), + this.encryptionKey = const Value.absent(), + this.encryptionMac = const Value.absent(), + this.encryptionNonce = const Value.absent(), + this.storedFileHash = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : mediaId = Value(mediaId), + type = Value(type); + static Insertable custom({ + Expression? mediaId, + Expression? type, + Expression? uploadState, + Expression? downloadState, + Expression? requiresAuthentication, + Expression? stored, + Expression? isDraftMedia, + Expression? preProgressingProcess, + Expression? reuploadRequestedBy, + Expression? displayLimitInMilliseconds, + Expression? removeAudio, + Expression? downloadToken, + Expression? encryptionKey, + Expression? encryptionMac, + Expression? encryptionNonce, + Expression? storedFileHash, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (mediaId != null) 'media_id': mediaId, + if (type != null) 'type': type, + if (uploadState != null) 'upload_state': uploadState, + if (downloadState != null) 'download_state': downloadState, + if (requiresAuthentication != null) + 'requires_authentication': requiresAuthentication, + if (stored != null) 'stored': stored, + if (isDraftMedia != null) 'is_draft_media': isDraftMedia, + if (preProgressingProcess != null) + 'pre_progressing_process': preProgressingProcess, + if (reuploadRequestedBy != null) + 'reupload_requested_by': reuploadRequestedBy, + if (displayLimitInMilliseconds != null) + 'display_limit_in_milliseconds': displayLimitInMilliseconds, + if (removeAudio != null) 'remove_audio': removeAudio, + if (downloadToken != null) 'download_token': downloadToken, + if (encryptionKey != null) 'encryption_key': encryptionKey, + if (encryptionMac != null) 'encryption_mac': encryptionMac, + if (encryptionNonce != null) 'encryption_nonce': encryptionNonce, + if (storedFileHash != null) 'stored_file_hash': storedFileHash, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + MediaFilesCompanion copyWith({ + Value? mediaId, + Value? type, + Value? uploadState, + Value? downloadState, + Value? requiresAuthentication, + Value? stored, + Value? isDraftMedia, + Value? preProgressingProcess, + Value? reuploadRequestedBy, + Value? displayLimitInMilliseconds, + Value? removeAudio, + Value? downloadToken, + Value? encryptionKey, + Value? encryptionMac, + Value? encryptionNonce, + Value? storedFileHash, + Value? createdAt, + Value? rowid, + }) { + return MediaFilesCompanion( + mediaId: mediaId ?? this.mediaId, + type: type ?? this.type, + uploadState: uploadState ?? this.uploadState, + downloadState: downloadState ?? this.downloadState, + requiresAuthentication: + requiresAuthentication ?? this.requiresAuthentication, + stored: stored ?? this.stored, + isDraftMedia: isDraftMedia ?? this.isDraftMedia, + preProgressingProcess: + preProgressingProcess ?? this.preProgressingProcess, + reuploadRequestedBy: reuploadRequestedBy ?? this.reuploadRequestedBy, + displayLimitInMilliseconds: + displayLimitInMilliseconds ?? this.displayLimitInMilliseconds, + removeAudio: removeAudio ?? this.removeAudio, + downloadToken: downloadToken ?? this.downloadToken, + encryptionKey: encryptionKey ?? this.encryptionKey, + encryptionMac: encryptionMac ?? this.encryptionMac, + encryptionNonce: encryptionNonce ?? this.encryptionNonce, + storedFileHash: storedFileHash ?? this.storedFileHash, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (mediaId.present) { + map['media_id'] = Variable(mediaId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (uploadState.present) { + map['upload_state'] = Variable(uploadState.value); + } + if (downloadState.present) { + map['download_state'] = Variable(downloadState.value); + } + if (requiresAuthentication.present) { + map['requires_authentication'] = Variable( + requiresAuthentication.value, + ); + } + if (stored.present) { + map['stored'] = Variable(stored.value); + } + if (isDraftMedia.present) { + map['is_draft_media'] = Variable(isDraftMedia.value); + } + if (preProgressingProcess.present) { + map['pre_progressing_process'] = Variable( + preProgressingProcess.value, + ); + } + if (reuploadRequestedBy.present) { + map['reupload_requested_by'] = Variable( + reuploadRequestedBy.value, + ); + } + if (displayLimitInMilliseconds.present) { + map['display_limit_in_milliseconds'] = Variable( + displayLimitInMilliseconds.value, + ); + } + if (removeAudio.present) { + map['remove_audio'] = Variable(removeAudio.value); + } + if (downloadToken.present) { + map['download_token'] = Variable(downloadToken.value); + } + if (encryptionKey.present) { + map['encryption_key'] = Variable(encryptionKey.value); + } + if (encryptionMac.present) { + map['encryption_mac'] = Variable(encryptionMac.value); + } + if (encryptionNonce.present) { + map['encryption_nonce'] = Variable(encryptionNonce.value); + } + if (storedFileHash.present) { + map['stored_file_hash'] = Variable(storedFileHash.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('MediaFilesCompanion(') + ..write('mediaId: $mediaId, ') + ..write('type: $type, ') + ..write('uploadState: $uploadState, ') + ..write('downloadState: $downloadState, ') + ..write('requiresAuthentication: $requiresAuthentication, ') + ..write('stored: $stored, ') + ..write('isDraftMedia: $isDraftMedia, ') + ..write('preProgressingProcess: $preProgressingProcess, ') + ..write('reuploadRequestedBy: $reuploadRequestedBy, ') + ..write('displayLimitInMilliseconds: $displayLimitInMilliseconds, ') + ..write('removeAudio: $removeAudio, ') + ..write('downloadToken: $downloadToken, ') + ..write('encryptionKey: $encryptionKey, ') + ..write('encryptionMac: $encryptionMac, ') + ..write('encryptionNonce: $encryptionNonce, ') + ..write('storedFileHash: $storedFileHash, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class Messages extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Messages(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderId = GeneratedColumn( + 'sender_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn content = GeneratedColumn( + 'content', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mediaId = GeneratedColumn( + 'media_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: + 'NULL REFERENCES media_files(media_id)ON DELETE SET NULL', + ); + late final GeneratedColumn additionalMessageData = + GeneratedColumn( + 'additional_message_data', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mediaStored = GeneratedColumn( + 'media_stored', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (media_stored IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn mediaReopened = GeneratedColumn( + 'media_reopened', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (media_reopened IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn downloadToken = + GeneratedColumn( + 'download_token', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quotesMessageId = GeneratedColumn( + 'quotes_message_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn isDeletedFromSender = GeneratedColumn( + 'is_deleted_from_sender', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (is_deleted_from_sender IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn openedAt = GeneratedColumn( + 'opened_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn openedByAll = GeneratedColumn( + 'opened_by_all', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn modifiedAt = GeneratedColumn( + 'modified_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByUser = GeneratedColumn( + 'ack_by_user', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByServer = GeneratedColumn( + 'ack_by_server', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + groupId, + messageId, + senderId, + type, + content, + mediaId, + additionalMessageData, + mediaStored, + mediaReopened, + downloadToken, + quotesMessageId, + isDeletedFromSender, + openedAt, + openedByAll, + createdAt, + modifiedAt, + ackByUser, + ackByServer, + ]; + @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( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + senderId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_id'], + ), + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + content: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}content'], + ), + mediaId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}media_id'], + ), + additionalMessageData: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}additional_message_data'], + ), + mediaStored: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_stored'], + )!, + mediaReopened: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_reopened'], + )!, + downloadToken: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}download_token'], + ), + quotesMessageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}quotes_message_id'], + ), + isDeletedFromSender: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_deleted_from_sender'], + )!, + openedAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}opened_at'], + ), + openedByAll: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}opened_by_all'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + modifiedAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}modified_at'], + ), + ackByUser: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_user'], + ), + ackByServer: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_server'], + ), + ); + } + + @override + Messages createAlias(String alias) { + return Messages(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(message_id)']; + @override + bool get dontWriteConstraints => true; +} + +class MessagesData extends DataClass implements Insertable { + final String groupId; + final String messageId; + final int? senderId; + final String type; + final String? content; + final String? mediaId; + final i2.Uint8List? additionalMessageData; + final int mediaStored; + final int mediaReopened; + final i2.Uint8List? downloadToken; + final String? quotesMessageId; + final int isDeletedFromSender; + final int? openedAt; + final int? openedByAll; + final int createdAt; + final int? modifiedAt; + final int? ackByUser; + final int? ackByServer; + const MessagesData({ + required this.groupId, + required this.messageId, + this.senderId, + required this.type, + this.content, + this.mediaId, + this.additionalMessageData, + required this.mediaStored, + required this.mediaReopened, + this.downloadToken, + this.quotesMessageId, + required this.isDeletedFromSender, + this.openedAt, + this.openedByAll, + required this.createdAt, + this.modifiedAt, + this.ackByUser, + this.ackByServer, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['message_id'] = Variable(messageId); + if (!nullToAbsent || senderId != null) { + map['sender_id'] = Variable(senderId); + } + map['type'] = Variable(type); + if (!nullToAbsent || content != null) { + map['content'] = Variable(content); + } + if (!nullToAbsent || mediaId != null) { + map['media_id'] = Variable(mediaId); + } + if (!nullToAbsent || additionalMessageData != null) { + map['additional_message_data'] = Variable( + additionalMessageData, + ); + } + map['media_stored'] = Variable(mediaStored); + map['media_reopened'] = Variable(mediaReopened); + if (!nullToAbsent || downloadToken != null) { + map['download_token'] = Variable(downloadToken); + } + if (!nullToAbsent || quotesMessageId != null) { + map['quotes_message_id'] = Variable(quotesMessageId); + } + map['is_deleted_from_sender'] = Variable(isDeletedFromSender); + if (!nullToAbsent || openedAt != null) { + map['opened_at'] = Variable(openedAt); + } + if (!nullToAbsent || openedByAll != null) { + map['opened_by_all'] = Variable(openedByAll); + } + map['created_at'] = Variable(createdAt); + if (!nullToAbsent || modifiedAt != null) { + map['modified_at'] = Variable(modifiedAt); + } + if (!nullToAbsent || ackByUser != null) { + map['ack_by_user'] = Variable(ackByUser); + } + if (!nullToAbsent || ackByServer != null) { + map['ack_by_server'] = Variable(ackByServer); + } + return map; + } + + MessagesCompanion toCompanion(bool nullToAbsent) { + return MessagesCompanion( + groupId: Value(groupId), + messageId: Value(messageId), + senderId: senderId == null && nullToAbsent + ? const Value.absent() + : Value(senderId), + type: Value(type), + content: content == null && nullToAbsent + ? const Value.absent() + : Value(content), + mediaId: mediaId == null && nullToAbsent + ? const Value.absent() + : Value(mediaId), + additionalMessageData: additionalMessageData == null && nullToAbsent + ? const Value.absent() + : Value(additionalMessageData), + mediaStored: Value(mediaStored), + mediaReopened: Value(mediaReopened), + downloadToken: downloadToken == null && nullToAbsent + ? const Value.absent() + : Value(downloadToken), + quotesMessageId: quotesMessageId == null && nullToAbsent + ? const Value.absent() + : Value(quotesMessageId), + isDeletedFromSender: Value(isDeletedFromSender), + openedAt: openedAt == null && nullToAbsent + ? const Value.absent() + : Value(openedAt), + openedByAll: openedByAll == null && nullToAbsent + ? const Value.absent() + : Value(openedByAll), + createdAt: Value(createdAt), + modifiedAt: modifiedAt == null && nullToAbsent + ? const Value.absent() + : Value(modifiedAt), + ackByUser: ackByUser == null && nullToAbsent + ? const Value.absent() + : Value(ackByUser), + ackByServer: ackByServer == null && nullToAbsent + ? const Value.absent() + : Value(ackByServer), + ); + } + + factory MessagesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessagesData( + groupId: serializer.fromJson(json['groupId']), + messageId: serializer.fromJson(json['messageId']), + senderId: serializer.fromJson(json['senderId']), + type: serializer.fromJson(json['type']), + content: serializer.fromJson(json['content']), + mediaId: serializer.fromJson(json['mediaId']), + additionalMessageData: serializer.fromJson( + json['additionalMessageData'], + ), + mediaStored: serializer.fromJson(json['mediaStored']), + mediaReopened: serializer.fromJson(json['mediaReopened']), + downloadToken: serializer.fromJson(json['downloadToken']), + quotesMessageId: serializer.fromJson(json['quotesMessageId']), + isDeletedFromSender: serializer.fromJson( + json['isDeletedFromSender'], + ), + openedAt: serializer.fromJson(json['openedAt']), + openedByAll: serializer.fromJson(json['openedByAll']), + createdAt: serializer.fromJson(json['createdAt']), + modifiedAt: serializer.fromJson(json['modifiedAt']), + ackByUser: serializer.fromJson(json['ackByUser']), + ackByServer: serializer.fromJson(json['ackByServer']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'messageId': serializer.toJson(messageId), + 'senderId': serializer.toJson(senderId), + 'type': serializer.toJson(type), + 'content': serializer.toJson(content), + 'mediaId': serializer.toJson(mediaId), + 'additionalMessageData': serializer.toJson( + additionalMessageData, + ), + 'mediaStored': serializer.toJson(mediaStored), + 'mediaReopened': serializer.toJson(mediaReopened), + 'downloadToken': serializer.toJson(downloadToken), + 'quotesMessageId': serializer.toJson(quotesMessageId), + 'isDeletedFromSender': serializer.toJson(isDeletedFromSender), + 'openedAt': serializer.toJson(openedAt), + 'openedByAll': serializer.toJson(openedByAll), + 'createdAt': serializer.toJson(createdAt), + 'modifiedAt': serializer.toJson(modifiedAt), + 'ackByUser': serializer.toJson(ackByUser), + 'ackByServer': serializer.toJson(ackByServer), + }; + } + + MessagesData copyWith({ + String? groupId, + String? messageId, + Value senderId = const Value.absent(), + String? type, + Value content = const Value.absent(), + Value mediaId = const Value.absent(), + Value additionalMessageData = const Value.absent(), + int? mediaStored, + int? mediaReopened, + Value downloadToken = const Value.absent(), + Value quotesMessageId = const Value.absent(), + int? isDeletedFromSender, + Value openedAt = const Value.absent(), + Value openedByAll = const Value.absent(), + int? createdAt, + Value modifiedAt = const Value.absent(), + Value ackByUser = const Value.absent(), + Value ackByServer = const Value.absent(), + }) => MessagesData( + groupId: groupId ?? this.groupId, + messageId: messageId ?? this.messageId, + senderId: senderId.present ? senderId.value : this.senderId, + type: type ?? this.type, + content: content.present ? content.value : this.content, + mediaId: mediaId.present ? mediaId.value : this.mediaId, + additionalMessageData: additionalMessageData.present + ? additionalMessageData.value + : this.additionalMessageData, + mediaStored: mediaStored ?? this.mediaStored, + mediaReopened: mediaReopened ?? this.mediaReopened, + downloadToken: downloadToken.present + ? downloadToken.value + : this.downloadToken, + quotesMessageId: quotesMessageId.present + ? quotesMessageId.value + : this.quotesMessageId, + isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, + openedAt: openedAt.present ? openedAt.value : this.openedAt, + openedByAll: openedByAll.present ? openedByAll.value : this.openedByAll, + createdAt: createdAt ?? this.createdAt, + modifiedAt: modifiedAt.present ? modifiedAt.value : this.modifiedAt, + ackByUser: ackByUser.present ? ackByUser.value : this.ackByUser, + ackByServer: ackByServer.present ? ackByServer.value : this.ackByServer, + ); + MessagesData copyWithCompanion(MessagesCompanion data) { + return MessagesData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + senderId: data.senderId.present ? data.senderId.value : this.senderId, + type: data.type.present ? data.type.value : this.type, + content: data.content.present ? data.content.value : this.content, + mediaId: data.mediaId.present ? data.mediaId.value : this.mediaId, + additionalMessageData: data.additionalMessageData.present + ? data.additionalMessageData.value + : this.additionalMessageData, + mediaStored: data.mediaStored.present + ? data.mediaStored.value + : this.mediaStored, + mediaReopened: data.mediaReopened.present + ? data.mediaReopened.value + : this.mediaReopened, + downloadToken: data.downloadToken.present + ? data.downloadToken.value + : this.downloadToken, + quotesMessageId: data.quotesMessageId.present + ? data.quotesMessageId.value + : this.quotesMessageId, + isDeletedFromSender: data.isDeletedFromSender.present + ? data.isDeletedFromSender.value + : this.isDeletedFromSender, + openedAt: data.openedAt.present ? data.openedAt.value : this.openedAt, + openedByAll: data.openedByAll.present + ? data.openedByAll.value + : this.openedByAll, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + modifiedAt: data.modifiedAt.present + ? data.modifiedAt.value + : this.modifiedAt, + ackByUser: data.ackByUser.present ? data.ackByUser.value : this.ackByUser, + ackByServer: data.ackByServer.present + ? data.ackByServer.value + : this.ackByServer, + ); + } + + @override + String toString() { + return (StringBuffer('MessagesData(') + ..write('groupId: $groupId, ') + ..write('messageId: $messageId, ') + ..write('senderId: $senderId, ') + ..write('type: $type, ') + ..write('content: $content, ') + ..write('mediaId: $mediaId, ') + ..write('additionalMessageData: $additionalMessageData, ') + ..write('mediaStored: $mediaStored, ') + ..write('mediaReopened: $mediaReopened, ') + ..write('downloadToken: $downloadToken, ') + ..write('quotesMessageId: $quotesMessageId, ') + ..write('isDeletedFromSender: $isDeletedFromSender, ') + ..write('openedAt: $openedAt, ') + ..write('openedByAll: $openedByAll, ') + ..write('createdAt: $createdAt, ') + ..write('modifiedAt: $modifiedAt, ') + ..write('ackByUser: $ackByUser, ') + ..write('ackByServer: $ackByServer') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupId, + messageId, + senderId, + type, + content, + mediaId, + $driftBlobEquality.hash(additionalMessageData), + mediaStored, + mediaReopened, + $driftBlobEquality.hash(downloadToken), + quotesMessageId, + isDeletedFromSender, + openedAt, + openedByAll, + createdAt, + modifiedAt, + ackByUser, + ackByServer, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessagesData && + other.groupId == this.groupId && + other.messageId == this.messageId && + other.senderId == this.senderId && + other.type == this.type && + other.content == this.content && + other.mediaId == this.mediaId && + $driftBlobEquality.equals( + other.additionalMessageData, + this.additionalMessageData, + ) && + other.mediaStored == this.mediaStored && + other.mediaReopened == this.mediaReopened && + $driftBlobEquality.equals(other.downloadToken, this.downloadToken) && + other.quotesMessageId == this.quotesMessageId && + other.isDeletedFromSender == this.isDeletedFromSender && + other.openedAt == this.openedAt && + other.openedByAll == this.openedByAll && + other.createdAt == this.createdAt && + other.modifiedAt == this.modifiedAt && + other.ackByUser == this.ackByUser && + other.ackByServer == this.ackByServer); +} + +class MessagesCompanion extends UpdateCompanion { + final Value groupId; + final Value messageId; + final Value senderId; + final Value type; + final Value content; + final Value mediaId; + final Value additionalMessageData; + final Value mediaStored; + final Value mediaReopened; + final Value downloadToken; + final Value quotesMessageId; + final Value isDeletedFromSender; + final Value openedAt; + final Value openedByAll; + final Value createdAt; + final Value modifiedAt; + final Value ackByUser; + final Value ackByServer; + final Value rowid; + const MessagesCompanion({ + this.groupId = const Value.absent(), + this.messageId = const Value.absent(), + this.senderId = const Value.absent(), + this.type = const Value.absent(), + this.content = const Value.absent(), + this.mediaId = const Value.absent(), + this.additionalMessageData = const Value.absent(), + this.mediaStored = const Value.absent(), + this.mediaReopened = const Value.absent(), + this.downloadToken = const Value.absent(), + this.quotesMessageId = const Value.absent(), + this.isDeletedFromSender = const Value.absent(), + this.openedAt = const Value.absent(), + this.openedByAll = const Value.absent(), + this.createdAt = const Value.absent(), + this.modifiedAt = const Value.absent(), + this.ackByUser = const Value.absent(), + this.ackByServer = const Value.absent(), + this.rowid = const Value.absent(), + }); + MessagesCompanion.insert({ + required String groupId, + required String messageId, + this.senderId = const Value.absent(), + required String type, + this.content = const Value.absent(), + this.mediaId = const Value.absent(), + this.additionalMessageData = const Value.absent(), + this.mediaStored = const Value.absent(), + this.mediaReopened = const Value.absent(), + this.downloadToken = const Value.absent(), + this.quotesMessageId = const Value.absent(), + this.isDeletedFromSender = const Value.absent(), + this.openedAt = const Value.absent(), + this.openedByAll = const Value.absent(), + this.createdAt = const Value.absent(), + this.modifiedAt = const Value.absent(), + this.ackByUser = const Value.absent(), + this.ackByServer = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + messageId = Value(messageId), + type = Value(type); + static Insertable custom({ + Expression? groupId, + Expression? messageId, + Expression? senderId, + Expression? type, + Expression? content, + Expression? mediaId, + Expression? additionalMessageData, + Expression? mediaStored, + Expression? mediaReopened, + Expression? downloadToken, + Expression? quotesMessageId, + Expression? isDeletedFromSender, + Expression? openedAt, + Expression? openedByAll, + Expression? createdAt, + Expression? modifiedAt, + Expression? ackByUser, + Expression? ackByServer, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (messageId != null) 'message_id': messageId, + if (senderId != null) 'sender_id': senderId, + if (type != null) 'type': type, + if (content != null) 'content': content, + if (mediaId != null) 'media_id': mediaId, + if (additionalMessageData != null) + 'additional_message_data': additionalMessageData, + if (mediaStored != null) 'media_stored': mediaStored, + if (mediaReopened != null) 'media_reopened': mediaReopened, + if (downloadToken != null) 'download_token': downloadToken, + if (quotesMessageId != null) 'quotes_message_id': quotesMessageId, + if (isDeletedFromSender != null) + 'is_deleted_from_sender': isDeletedFromSender, + if (openedAt != null) 'opened_at': openedAt, + if (openedByAll != null) 'opened_by_all': openedByAll, + if (createdAt != null) 'created_at': createdAt, + if (modifiedAt != null) 'modified_at': modifiedAt, + if (ackByUser != null) 'ack_by_user': ackByUser, + if (ackByServer != null) 'ack_by_server': ackByServer, + if (rowid != null) 'rowid': rowid, + }); + } + + MessagesCompanion copyWith({ + Value? groupId, + Value? messageId, + Value? senderId, + Value? type, + Value? content, + Value? mediaId, + Value? additionalMessageData, + Value? mediaStored, + Value? mediaReopened, + Value? downloadToken, + Value? quotesMessageId, + Value? isDeletedFromSender, + Value? openedAt, + Value? openedByAll, + Value? createdAt, + Value? modifiedAt, + Value? ackByUser, + Value? ackByServer, + Value? rowid, + }) { + return MessagesCompanion( + groupId: groupId ?? this.groupId, + messageId: messageId ?? this.messageId, + senderId: senderId ?? this.senderId, + type: type ?? this.type, + content: content ?? this.content, + mediaId: mediaId ?? this.mediaId, + additionalMessageData: + additionalMessageData ?? this.additionalMessageData, + mediaStored: mediaStored ?? this.mediaStored, + mediaReopened: mediaReopened ?? this.mediaReopened, + downloadToken: downloadToken ?? this.downloadToken, + quotesMessageId: quotesMessageId ?? this.quotesMessageId, + isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, + openedAt: openedAt ?? this.openedAt, + openedByAll: openedByAll ?? this.openedByAll, + createdAt: createdAt ?? this.createdAt, + modifiedAt: modifiedAt ?? this.modifiedAt, + ackByUser: ackByUser ?? this.ackByUser, + ackByServer: ackByServer ?? this.ackByServer, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (senderId.present) { + map['sender_id'] = Variable(senderId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (mediaId.present) { + map['media_id'] = Variable(mediaId.value); + } + if (additionalMessageData.present) { + map['additional_message_data'] = Variable( + additionalMessageData.value, + ); + } + if (mediaStored.present) { + map['media_stored'] = Variable(mediaStored.value); + } + if (mediaReopened.present) { + map['media_reopened'] = Variable(mediaReopened.value); + } + if (downloadToken.present) { + map['download_token'] = Variable(downloadToken.value); + } + if (quotesMessageId.present) { + map['quotes_message_id'] = Variable(quotesMessageId.value); + } + if (isDeletedFromSender.present) { + map['is_deleted_from_sender'] = Variable(isDeletedFromSender.value); + } + if (openedAt.present) { + map['opened_at'] = Variable(openedAt.value); + } + if (openedByAll.present) { + map['opened_by_all'] = Variable(openedByAll.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (modifiedAt.present) { + map['modified_at'] = Variable(modifiedAt.value); + } + if (ackByUser.present) { + map['ack_by_user'] = Variable(ackByUser.value); + } + if (ackByServer.present) { + map['ack_by_server'] = Variable(ackByServer.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessagesCompanion(') + ..write('groupId: $groupId, ') + ..write('messageId: $messageId, ') + ..write('senderId: $senderId, ') + ..write('type: $type, ') + ..write('content: $content, ') + ..write('mediaId: $mediaId, ') + ..write('additionalMessageData: $additionalMessageData, ') + ..write('mediaStored: $mediaStored, ') + ..write('mediaReopened: $mediaReopened, ') + ..write('downloadToken: $downloadToken, ') + ..write('quotesMessageId: $quotesMessageId, ') + ..write('isDeletedFromSender: $isDeletedFromSender, ') + ..write('openedAt: $openedAt, ') + ..write('openedByAll: $openedByAll, ') + ..write('createdAt: $createdAt, ') + ..write('modifiedAt: $modifiedAt, ') + ..write('ackByUser: $ackByUser, ') + ..write('ackByServer: $ackByServer, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class MessageHistories extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MessageHistories(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn content = GeneratedColumn( + 'content', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + id, + messageId, + contactId, + content, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'message_histories'; + @override + Set get $primaryKey => {id}; + @override + MessageHistoriesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MessageHistoriesData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + content: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}content'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + MessageHistories createAlias(String alias) { + return MessageHistories(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class MessageHistoriesData extends DataClass + implements Insertable { + final int id; + final String messageId; + final int? contactId; + final String? content; + final int createdAt; + const MessageHistoriesData({ + required this.id, + required this.messageId, + this.contactId, + this.content, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['message_id'] = Variable(messageId); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + if (!nullToAbsent || content != null) { + map['content'] = Variable(content); + } + map['created_at'] = Variable(createdAt); + return map; + } + + MessageHistoriesCompanion toCompanion(bool nullToAbsent) { + return MessageHistoriesCompanion( + id: Value(id), + messageId: Value(messageId), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + content: content == null && nullToAbsent + ? const Value.absent() + : Value(content), + createdAt: Value(createdAt), + ); + } + + factory MessageHistoriesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessageHistoriesData( + id: serializer.fromJson(json['id']), + messageId: serializer.fromJson(json['messageId']), + contactId: serializer.fromJson(json['contactId']), + content: serializer.fromJson(json['content']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'messageId': serializer.toJson(messageId), + 'contactId': serializer.toJson(contactId), + 'content': serializer.toJson(content), + 'createdAt': serializer.toJson(createdAt), + }; + } + + MessageHistoriesData copyWith({ + int? id, + String? messageId, + Value contactId = const Value.absent(), + Value content = const Value.absent(), + int? createdAt, + }) => MessageHistoriesData( + id: id ?? this.id, + messageId: messageId ?? this.messageId, + contactId: contactId.present ? contactId.value : this.contactId, + content: content.present ? content.value : this.content, + createdAt: createdAt ?? this.createdAt, + ); + MessageHistoriesData copyWithCompanion(MessageHistoriesCompanion data) { + return MessageHistoriesData( + id: data.id.present ? data.id.value : this.id, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + content: data.content.present ? data.content.value : this.content, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('MessageHistoriesData(') + ..write('id: $id, ') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('content: $content, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, messageId, contactId, content, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessageHistoriesData && + other.id == this.id && + other.messageId == this.messageId && + other.contactId == this.contactId && + other.content == this.content && + other.createdAt == this.createdAt); +} + +class MessageHistoriesCompanion extends UpdateCompanion { + final Value id; + final Value messageId; + final Value contactId; + final Value content; + final Value createdAt; + const MessageHistoriesCompanion({ + this.id = const Value.absent(), + this.messageId = const Value.absent(), + this.contactId = const Value.absent(), + this.content = const Value.absent(), + this.createdAt = const Value.absent(), + }); + MessageHistoriesCompanion.insert({ + this.id = const Value.absent(), + required String messageId, + this.contactId = const Value.absent(), + this.content = const Value.absent(), + this.createdAt = const Value.absent(), + }) : messageId = Value(messageId); + static Insertable custom({ + Expression? id, + Expression? messageId, + Expression? contactId, + Expression? content, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (messageId != null) 'message_id': messageId, + if (contactId != null) 'contact_id': contactId, + if (content != null) 'content': content, + if (createdAt != null) 'created_at': createdAt, + }); + } + + MessageHistoriesCompanion copyWith({ + Value? id, + Value? messageId, + Value? contactId, + Value? content, + Value? createdAt, + }) { + return MessageHistoriesCompanion( + id: id ?? this.id, + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + content: content ?? this.content, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessageHistoriesCompanion(') + ..write('id: $id, ') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('content: $content, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class Reactions extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Reactions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn emoji = GeneratedColumn( + 'emoji', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderId = GeneratedColumn( + 'sender_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [messageId, emoji, senderId, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'reactions'; + @override + Set get $primaryKey => {messageId, senderId, emoji}; + @override + ReactionsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReactionsData( + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + emoji: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}emoji'], + )!, + senderId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_id'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + Reactions createAlias(String alias) { + return Reactions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(message_id, sender_id, emoji)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class ReactionsData extends DataClass implements Insertable { + final String messageId; + final String emoji; + final int? senderId; + final int createdAt; + const ReactionsData({ + required this.messageId, + required this.emoji, + this.senderId, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['message_id'] = Variable(messageId); + map['emoji'] = Variable(emoji); + if (!nullToAbsent || senderId != null) { + map['sender_id'] = Variable(senderId); + } + map['created_at'] = Variable(createdAt); + return map; + } + + ReactionsCompanion toCompanion(bool nullToAbsent) { + return ReactionsCompanion( + messageId: Value(messageId), + emoji: Value(emoji), + senderId: senderId == null && nullToAbsent + ? const Value.absent() + : Value(senderId), + createdAt: Value(createdAt), + ); + } + + factory ReactionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReactionsData( + messageId: serializer.fromJson(json['messageId']), + emoji: serializer.fromJson(json['emoji']), + senderId: serializer.fromJson(json['senderId']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'messageId': serializer.toJson(messageId), + 'emoji': serializer.toJson(emoji), + 'senderId': serializer.toJson(senderId), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReactionsData copyWith({ + String? messageId, + String? emoji, + Value senderId = const Value.absent(), + int? createdAt, + }) => ReactionsData( + messageId: messageId ?? this.messageId, + emoji: emoji ?? this.emoji, + senderId: senderId.present ? senderId.value : this.senderId, + createdAt: createdAt ?? this.createdAt, + ); + ReactionsData copyWithCompanion(ReactionsCompanion data) { + return ReactionsData( + messageId: data.messageId.present ? data.messageId.value : this.messageId, + emoji: data.emoji.present ? data.emoji.value : this.emoji, + senderId: data.senderId.present ? data.senderId.value : this.senderId, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReactionsData(') + ..write('messageId: $messageId, ') + ..write('emoji: $emoji, ') + ..write('senderId: $senderId, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(messageId, emoji, senderId, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReactionsData && + other.messageId == this.messageId && + other.emoji == this.emoji && + other.senderId == this.senderId && + other.createdAt == this.createdAt); +} + +class ReactionsCompanion extends UpdateCompanion { + final Value messageId; + final Value emoji; + final Value senderId; + final Value createdAt; + final Value rowid; + const ReactionsCompanion({ + this.messageId = const Value.absent(), + this.emoji = const Value.absent(), + this.senderId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReactionsCompanion.insert({ + required String messageId, + required String emoji, + this.senderId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : messageId = Value(messageId), + emoji = Value(emoji); + static Insertable custom({ + Expression? messageId, + Expression? emoji, + Expression? senderId, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (messageId != null) 'message_id': messageId, + if (emoji != null) 'emoji': emoji, + if (senderId != null) 'sender_id': senderId, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReactionsCompanion copyWith({ + Value? messageId, + Value? emoji, + Value? senderId, + Value? createdAt, + Value? rowid, + }) { + return ReactionsCompanion( + messageId: messageId ?? this.messageId, + emoji: emoji ?? this.emoji, + senderId: senderId ?? this.senderId, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (emoji.present) { + map['emoji'] = Variable(emoji.value); + } + if (senderId.present) { + map['sender_id'] = Variable(senderId.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('ReactionsCompanion(') + ..write('messageId: $messageId, ') + ..write('emoji: $emoji, ') + ..write('senderId: $senderId, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class GroupMembers extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + GroupMembers(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn memberState = GeneratedColumn( + 'member_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn groupPublicKey = + GeneratedColumn( + 'group_public_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastChatOpened = GeneratedColumn( + 'last_chat_opened', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastTypeIndicator = GeneratedColumn( + 'last_type_indicator', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessage = GeneratedColumn( + 'last_message', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupId, + contactId, + memberState, + groupPublicKey, + lastChatOpened, + lastTypeIndicator, + lastMessage, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'group_members'; + @override + Set get $primaryKey => {groupId, contactId}; + @override + GroupMembersData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupMembersData( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + memberState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}member_state'], + ), + groupPublicKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}group_public_key'], + ), + lastChatOpened: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_chat_opened'], + ), + lastTypeIndicator: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_type_indicator'], + ), + lastMessage: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + GroupMembers createAlias(String alias) { + return GroupMembers(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(group_id, contact_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class GroupMembersData extends DataClass + implements Insertable { + final String groupId; + final int contactId; + final String? memberState; + final i2.Uint8List? groupPublicKey; + final int? lastChatOpened; + final int? lastTypeIndicator; + final int? lastMessage; + final int createdAt; + const GroupMembersData({ + required this.groupId, + required this.contactId, + this.memberState, + this.groupPublicKey, + this.lastChatOpened, + this.lastTypeIndicator, + this.lastMessage, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['contact_id'] = Variable(contactId); + if (!nullToAbsent || memberState != null) { + map['member_state'] = Variable(memberState); + } + if (!nullToAbsent || groupPublicKey != null) { + map['group_public_key'] = Variable(groupPublicKey); + } + if (!nullToAbsent || lastChatOpened != null) { + map['last_chat_opened'] = Variable(lastChatOpened); + } + if (!nullToAbsent || lastTypeIndicator != null) { + map['last_type_indicator'] = Variable(lastTypeIndicator); + } + if (!nullToAbsent || lastMessage != null) { + map['last_message'] = Variable(lastMessage); + } + map['created_at'] = Variable(createdAt); + return map; + } + + GroupMembersCompanion toCompanion(bool nullToAbsent) { + return GroupMembersCompanion( + groupId: Value(groupId), + contactId: Value(contactId), + memberState: memberState == null && nullToAbsent + ? const Value.absent() + : Value(memberState), + groupPublicKey: groupPublicKey == null && nullToAbsent + ? const Value.absent() + : Value(groupPublicKey), + lastChatOpened: lastChatOpened == null && nullToAbsent + ? const Value.absent() + : Value(lastChatOpened), + lastTypeIndicator: lastTypeIndicator == null && nullToAbsent + ? const Value.absent() + : Value(lastTypeIndicator), + lastMessage: lastMessage == null && nullToAbsent + ? const Value.absent() + : Value(lastMessage), + createdAt: Value(createdAt), + ); + } + + factory GroupMembersData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupMembersData( + groupId: serializer.fromJson(json['groupId']), + contactId: serializer.fromJson(json['contactId']), + memberState: serializer.fromJson(json['memberState']), + groupPublicKey: serializer.fromJson( + json['groupPublicKey'], + ), + lastChatOpened: serializer.fromJson(json['lastChatOpened']), + lastTypeIndicator: serializer.fromJson(json['lastTypeIndicator']), + lastMessage: serializer.fromJson(json['lastMessage']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'contactId': serializer.toJson(contactId), + 'memberState': serializer.toJson(memberState), + 'groupPublicKey': serializer.toJson(groupPublicKey), + 'lastChatOpened': serializer.toJson(lastChatOpened), + 'lastTypeIndicator': serializer.toJson(lastTypeIndicator), + 'lastMessage': serializer.toJson(lastMessage), + 'createdAt': serializer.toJson(createdAt), + }; + } + + GroupMembersData copyWith({ + String? groupId, + int? contactId, + Value memberState = const Value.absent(), + Value groupPublicKey = const Value.absent(), + Value lastChatOpened = const Value.absent(), + Value lastTypeIndicator = const Value.absent(), + Value lastMessage = const Value.absent(), + int? createdAt, + }) => GroupMembersData( + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + memberState: memberState.present ? memberState.value : this.memberState, + groupPublicKey: groupPublicKey.present + ? groupPublicKey.value + : this.groupPublicKey, + lastChatOpened: lastChatOpened.present + ? lastChatOpened.value + : this.lastChatOpened, + lastTypeIndicator: lastTypeIndicator.present + ? lastTypeIndicator.value + : this.lastTypeIndicator, + lastMessage: lastMessage.present ? lastMessage.value : this.lastMessage, + createdAt: createdAt ?? this.createdAt, + ); + GroupMembersData copyWithCompanion(GroupMembersCompanion data) { + return GroupMembersData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + memberState: data.memberState.present + ? data.memberState.value + : this.memberState, + groupPublicKey: data.groupPublicKey.present + ? data.groupPublicKey.value + : this.groupPublicKey, + lastChatOpened: data.lastChatOpened.present + ? data.lastChatOpened.value + : this.lastChatOpened, + lastTypeIndicator: data.lastTypeIndicator.present + ? data.lastTypeIndicator.value + : this.lastTypeIndicator, + lastMessage: data.lastMessage.present + ? data.lastMessage.value + : this.lastMessage, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('GroupMembersData(') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('memberState: $memberState, ') + ..write('groupPublicKey: $groupPublicKey, ') + ..write('lastChatOpened: $lastChatOpened, ') + ..write('lastTypeIndicator: $lastTypeIndicator, ') + ..write('lastMessage: $lastMessage, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupId, + contactId, + memberState, + $driftBlobEquality.hash(groupPublicKey), + lastChatOpened, + lastTypeIndicator, + lastMessage, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupMembersData && + other.groupId == this.groupId && + other.contactId == this.contactId && + other.memberState == this.memberState && + $driftBlobEquality.equals( + other.groupPublicKey, + this.groupPublicKey, + ) && + other.lastChatOpened == this.lastChatOpened && + other.lastTypeIndicator == this.lastTypeIndicator && + other.lastMessage == this.lastMessage && + other.createdAt == this.createdAt); +} + +class GroupMembersCompanion extends UpdateCompanion { + final Value groupId; + final Value contactId; + final Value memberState; + final Value groupPublicKey; + final Value lastChatOpened; + final Value lastTypeIndicator; + final Value lastMessage; + final Value createdAt; + final Value rowid; + const GroupMembersCompanion({ + this.groupId = const Value.absent(), + this.contactId = const Value.absent(), + this.memberState = const Value.absent(), + this.groupPublicKey = const Value.absent(), + this.lastChatOpened = const Value.absent(), + this.lastTypeIndicator = const Value.absent(), + this.lastMessage = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupMembersCompanion.insert({ + required String groupId, + required int contactId, + this.memberState = const Value.absent(), + this.groupPublicKey = const Value.absent(), + this.lastChatOpened = const Value.absent(), + this.lastTypeIndicator = const Value.absent(), + this.lastMessage = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + contactId = Value(contactId); + static Insertable custom({ + Expression? groupId, + Expression? contactId, + Expression? memberState, + Expression? groupPublicKey, + Expression? lastChatOpened, + Expression? lastTypeIndicator, + Expression? lastMessage, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (contactId != null) 'contact_id': contactId, + if (memberState != null) 'member_state': memberState, + if (groupPublicKey != null) 'group_public_key': groupPublicKey, + if (lastChatOpened != null) 'last_chat_opened': lastChatOpened, + if (lastTypeIndicator != null) 'last_type_indicator': lastTypeIndicator, + if (lastMessage != null) 'last_message': lastMessage, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupMembersCompanion copyWith({ + Value? groupId, + Value? contactId, + Value? memberState, + Value? groupPublicKey, + Value? lastChatOpened, + Value? lastTypeIndicator, + Value? lastMessage, + Value? createdAt, + Value? rowid, + }) { + return GroupMembersCompanion( + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + memberState: memberState ?? this.memberState, + groupPublicKey: groupPublicKey ?? this.groupPublicKey, + lastChatOpened: lastChatOpened ?? this.lastChatOpened, + lastTypeIndicator: lastTypeIndicator ?? this.lastTypeIndicator, + lastMessage: lastMessage ?? this.lastMessage, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (memberState.present) { + map['member_state'] = Variable(memberState.value); + } + if (groupPublicKey.present) { + map['group_public_key'] = Variable(groupPublicKey.value); + } + if (lastChatOpened.present) { + map['last_chat_opened'] = Variable(lastChatOpened.value); + } + if (lastTypeIndicator.present) { + map['last_type_indicator'] = Variable(lastTypeIndicator.value); + } + if (lastMessage.present) { + map['last_message'] = Variable(lastMessage.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('GroupMembersCompanion(') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('memberState: $memberState, ') + ..write('groupPublicKey: $groupPublicKey, ') + ..write('lastChatOpened: $lastChatOpened, ') + ..write('lastTypeIndicator: $lastTypeIndicator, ') + ..write('lastMessage: $lastMessage, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class Receipts extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Receipts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn receiptId = GeneratedColumn( + 'receipt_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn message = + GeneratedColumn( + 'message', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactWillSendsReceipt = + GeneratedColumn( + 'contact_will_sends_receipt', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 1 CHECK (contact_will_sends_receipt IN (0, 1))', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn + willBeRetriedByMediaUpload = GeneratedColumn( + 'will_be_retried_by_media_upload', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (will_be_retried_by_media_upload IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn markForRetry = GeneratedColumn( + 'mark_for_retry', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn markForRetryAfterAccepted = + GeneratedColumn( + 'mark_for_retry_after_accepted', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByServerAt = GeneratedColumn( + 'ack_by_server_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn retryCount = GeneratedColumn( + 'retry_count', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn lastRetry = GeneratedColumn( + 'last_retry', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + receiptId, + contactId, + messageId, + message, + contactWillSendsReceipt, + willBeRetriedByMediaUpload, + markForRetry, + markForRetryAfterAccepted, + ackByServerAt, + retryCount, + lastRetry, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'receipts'; + @override + Set get $primaryKey => {receiptId}; + @override + ReceiptsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReceiptsData( + receiptId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}receipt_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + ), + message: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}message'], + )!, + contactWillSendsReceipt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_will_sends_receipt'], + )!, + willBeRetriedByMediaUpload: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}will_be_retried_by_media_upload'], + )!, + markForRetry: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}mark_for_retry'], + ), + markForRetryAfterAccepted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}mark_for_retry_after_accepted'], + ), + ackByServerAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_server_at'], + ), + retryCount: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}retry_count'], + )!, + lastRetry: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_retry'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + Receipts createAlias(String alias) { + return Receipts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(receipt_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ReceiptsData extends DataClass implements Insertable { + final String receiptId; + final int contactId; + final String? messageId; + final i2.Uint8List message; + final int contactWillSendsReceipt; + final int willBeRetriedByMediaUpload; + final int? markForRetry; + final int? markForRetryAfterAccepted; + final int? ackByServerAt; + final int retryCount; + final int? lastRetry; + final int createdAt; + const ReceiptsData({ + required this.receiptId, + required this.contactId, + this.messageId, + required this.message, + required this.contactWillSendsReceipt, + required this.willBeRetriedByMediaUpload, + this.markForRetry, + this.markForRetryAfterAccepted, + this.ackByServerAt, + required this.retryCount, + this.lastRetry, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['receipt_id'] = Variable(receiptId); + map['contact_id'] = Variable(contactId); + if (!nullToAbsent || messageId != null) { + map['message_id'] = Variable(messageId); + } + map['message'] = Variable(message); + map['contact_will_sends_receipt'] = Variable(contactWillSendsReceipt); + map['will_be_retried_by_media_upload'] = Variable( + willBeRetriedByMediaUpload, + ); + if (!nullToAbsent || markForRetry != null) { + map['mark_for_retry'] = Variable(markForRetry); + } + if (!nullToAbsent || markForRetryAfterAccepted != null) { + map['mark_for_retry_after_accepted'] = Variable( + markForRetryAfterAccepted, + ); + } + if (!nullToAbsent || ackByServerAt != null) { + map['ack_by_server_at'] = Variable(ackByServerAt); + } + map['retry_count'] = Variable(retryCount); + if (!nullToAbsent || lastRetry != null) { + map['last_retry'] = Variable(lastRetry); + } + map['created_at'] = Variable(createdAt); + return map; + } + + ReceiptsCompanion toCompanion(bool nullToAbsent) { + return ReceiptsCompanion( + receiptId: Value(receiptId), + contactId: Value(contactId), + messageId: messageId == null && nullToAbsent + ? const Value.absent() + : Value(messageId), + message: Value(message), + contactWillSendsReceipt: Value(contactWillSendsReceipt), + willBeRetriedByMediaUpload: Value(willBeRetriedByMediaUpload), + markForRetry: markForRetry == null && nullToAbsent + ? const Value.absent() + : Value(markForRetry), + markForRetryAfterAccepted: + markForRetryAfterAccepted == null && nullToAbsent + ? const Value.absent() + : Value(markForRetryAfterAccepted), + ackByServerAt: ackByServerAt == null && nullToAbsent + ? const Value.absent() + : Value(ackByServerAt), + retryCount: Value(retryCount), + lastRetry: lastRetry == null && nullToAbsent + ? const Value.absent() + : Value(lastRetry), + createdAt: Value(createdAt), + ); + } + + factory ReceiptsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReceiptsData( + receiptId: serializer.fromJson(json['receiptId']), + contactId: serializer.fromJson(json['contactId']), + messageId: serializer.fromJson(json['messageId']), + message: serializer.fromJson(json['message']), + contactWillSendsReceipt: serializer.fromJson( + json['contactWillSendsReceipt'], + ), + willBeRetriedByMediaUpload: serializer.fromJson( + json['willBeRetriedByMediaUpload'], + ), + markForRetry: serializer.fromJson(json['markForRetry']), + markForRetryAfterAccepted: serializer.fromJson( + json['markForRetryAfterAccepted'], + ), + ackByServerAt: serializer.fromJson(json['ackByServerAt']), + retryCount: serializer.fromJson(json['retryCount']), + lastRetry: serializer.fromJson(json['lastRetry']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'receiptId': serializer.toJson(receiptId), + 'contactId': serializer.toJson(contactId), + 'messageId': serializer.toJson(messageId), + 'message': serializer.toJson(message), + 'contactWillSendsReceipt': serializer.toJson( + contactWillSendsReceipt, + ), + 'willBeRetriedByMediaUpload': serializer.toJson( + willBeRetriedByMediaUpload, + ), + 'markForRetry': serializer.toJson(markForRetry), + 'markForRetryAfterAccepted': serializer.toJson( + markForRetryAfterAccepted, + ), + 'ackByServerAt': serializer.toJson(ackByServerAt), + 'retryCount': serializer.toJson(retryCount), + 'lastRetry': serializer.toJson(lastRetry), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReceiptsData copyWith({ + String? receiptId, + int? contactId, + Value messageId = const Value.absent(), + i2.Uint8List? message, + int? contactWillSendsReceipt, + int? willBeRetriedByMediaUpload, + Value markForRetry = const Value.absent(), + Value markForRetryAfterAccepted = const Value.absent(), + Value ackByServerAt = const Value.absent(), + int? retryCount, + Value lastRetry = const Value.absent(), + int? createdAt, + }) => ReceiptsData( + receiptId: receiptId ?? this.receiptId, + contactId: contactId ?? this.contactId, + messageId: messageId.present ? messageId.value : this.messageId, + message: message ?? this.message, + contactWillSendsReceipt: + contactWillSendsReceipt ?? this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: + willBeRetriedByMediaUpload ?? this.willBeRetriedByMediaUpload, + markForRetry: markForRetry.present ? markForRetry.value : this.markForRetry, + markForRetryAfterAccepted: markForRetryAfterAccepted.present + ? markForRetryAfterAccepted.value + : this.markForRetryAfterAccepted, + ackByServerAt: ackByServerAt.present + ? ackByServerAt.value + : this.ackByServerAt, + retryCount: retryCount ?? this.retryCount, + lastRetry: lastRetry.present ? lastRetry.value : this.lastRetry, + createdAt: createdAt ?? this.createdAt, + ); + ReceiptsData copyWithCompanion(ReceiptsCompanion data) { + return ReceiptsData( + receiptId: data.receiptId.present ? data.receiptId.value : this.receiptId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + message: data.message.present ? data.message.value : this.message, + contactWillSendsReceipt: data.contactWillSendsReceipt.present + ? data.contactWillSendsReceipt.value + : this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: data.willBeRetriedByMediaUpload.present + ? data.willBeRetriedByMediaUpload.value + : this.willBeRetriedByMediaUpload, + markForRetry: data.markForRetry.present + ? data.markForRetry.value + : this.markForRetry, + markForRetryAfterAccepted: data.markForRetryAfterAccepted.present + ? data.markForRetryAfterAccepted.value + : this.markForRetryAfterAccepted, + ackByServerAt: data.ackByServerAt.present + ? data.ackByServerAt.value + : this.ackByServerAt, + retryCount: data.retryCount.present + ? data.retryCount.value + : this.retryCount, + lastRetry: data.lastRetry.present ? data.lastRetry.value : this.lastRetry, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReceiptsData(') + ..write('receiptId: $receiptId, ') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('message: $message, ') + ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') + ..write('willBeRetriedByMediaUpload: $willBeRetriedByMediaUpload, ') + ..write('markForRetry: $markForRetry, ') + ..write('markForRetryAfterAccepted: $markForRetryAfterAccepted, ') + ..write('ackByServerAt: $ackByServerAt, ') + ..write('retryCount: $retryCount, ') + ..write('lastRetry: $lastRetry, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + receiptId, + contactId, + messageId, + $driftBlobEquality.hash(message), + contactWillSendsReceipt, + willBeRetriedByMediaUpload, + markForRetry, + markForRetryAfterAccepted, + ackByServerAt, + retryCount, + lastRetry, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReceiptsData && + other.receiptId == this.receiptId && + other.contactId == this.contactId && + other.messageId == this.messageId && + $driftBlobEquality.equals(other.message, this.message) && + other.contactWillSendsReceipt == this.contactWillSendsReceipt && + other.willBeRetriedByMediaUpload == this.willBeRetriedByMediaUpload && + other.markForRetry == this.markForRetry && + other.markForRetryAfterAccepted == this.markForRetryAfterAccepted && + other.ackByServerAt == this.ackByServerAt && + other.retryCount == this.retryCount && + other.lastRetry == this.lastRetry && + other.createdAt == this.createdAt); +} + +class ReceiptsCompanion extends UpdateCompanion { + final Value receiptId; + final Value contactId; + final Value messageId; + final Value message; + final Value contactWillSendsReceipt; + final Value willBeRetriedByMediaUpload; + final Value markForRetry; + final Value markForRetryAfterAccepted; + final Value ackByServerAt; + final Value retryCount; + final Value lastRetry; + final Value createdAt; + final Value rowid; + const ReceiptsCompanion({ + this.receiptId = const Value.absent(), + this.contactId = const Value.absent(), + this.messageId = const Value.absent(), + this.message = const Value.absent(), + this.contactWillSendsReceipt = const Value.absent(), + this.willBeRetriedByMediaUpload = const Value.absent(), + this.markForRetry = const Value.absent(), + this.markForRetryAfterAccepted = const Value.absent(), + this.ackByServerAt = const Value.absent(), + this.retryCount = const Value.absent(), + this.lastRetry = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReceiptsCompanion.insert({ + required String receiptId, + required int contactId, + this.messageId = const Value.absent(), + required i2.Uint8List message, + this.contactWillSendsReceipt = const Value.absent(), + this.willBeRetriedByMediaUpload = const Value.absent(), + this.markForRetry = const Value.absent(), + this.markForRetryAfterAccepted = const Value.absent(), + this.ackByServerAt = const Value.absent(), + this.retryCount = const Value.absent(), + this.lastRetry = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : receiptId = Value(receiptId), + contactId = Value(contactId), + message = Value(message); + static Insertable custom({ + Expression? receiptId, + Expression? contactId, + Expression? messageId, + Expression? message, + Expression? contactWillSendsReceipt, + Expression? willBeRetriedByMediaUpload, + Expression? markForRetry, + Expression? markForRetryAfterAccepted, + Expression? ackByServerAt, + Expression? retryCount, + Expression? lastRetry, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (receiptId != null) 'receipt_id': receiptId, + if (contactId != null) 'contact_id': contactId, + if (messageId != null) 'message_id': messageId, + if (message != null) 'message': message, + if (contactWillSendsReceipt != null) + 'contact_will_sends_receipt': contactWillSendsReceipt, + if (willBeRetriedByMediaUpload != null) + 'will_be_retried_by_media_upload': willBeRetriedByMediaUpload, + if (markForRetry != null) 'mark_for_retry': markForRetry, + if (markForRetryAfterAccepted != null) + 'mark_for_retry_after_accepted': markForRetryAfterAccepted, + if (ackByServerAt != null) 'ack_by_server_at': ackByServerAt, + if (retryCount != null) 'retry_count': retryCount, + if (lastRetry != null) 'last_retry': lastRetry, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReceiptsCompanion copyWith({ + Value? receiptId, + Value? contactId, + Value? messageId, + Value? message, + Value? contactWillSendsReceipt, + Value? willBeRetriedByMediaUpload, + Value? markForRetry, + Value? markForRetryAfterAccepted, + Value? ackByServerAt, + Value? retryCount, + Value? lastRetry, + Value? createdAt, + Value? rowid, + }) { + return ReceiptsCompanion( + receiptId: receiptId ?? this.receiptId, + contactId: contactId ?? this.contactId, + messageId: messageId ?? this.messageId, + message: message ?? this.message, + contactWillSendsReceipt: + contactWillSendsReceipt ?? this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: + willBeRetriedByMediaUpload ?? this.willBeRetriedByMediaUpload, + markForRetry: markForRetry ?? this.markForRetry, + markForRetryAfterAccepted: + markForRetryAfterAccepted ?? this.markForRetryAfterAccepted, + ackByServerAt: ackByServerAt ?? this.ackByServerAt, + retryCount: retryCount ?? this.retryCount, + lastRetry: lastRetry ?? this.lastRetry, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (receiptId.present) { + map['receipt_id'] = Variable(receiptId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (message.present) { + map['message'] = Variable(message.value); + } + if (contactWillSendsReceipt.present) { + map['contact_will_sends_receipt'] = Variable( + contactWillSendsReceipt.value, + ); + } + if (willBeRetriedByMediaUpload.present) { + map['will_be_retried_by_media_upload'] = Variable( + willBeRetriedByMediaUpload.value, + ); + } + if (markForRetry.present) { + map['mark_for_retry'] = Variable(markForRetry.value); + } + if (markForRetryAfterAccepted.present) { + map['mark_for_retry_after_accepted'] = Variable( + markForRetryAfterAccepted.value, + ); + } + if (ackByServerAt.present) { + map['ack_by_server_at'] = Variable(ackByServerAt.value); + } + if (retryCount.present) { + map['retry_count'] = Variable(retryCount.value); + } + if (lastRetry.present) { + map['last_retry'] = Variable(lastRetry.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('ReceiptsCompanion(') + ..write('receiptId: $receiptId, ') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('message: $message, ') + ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') + ..write('willBeRetriedByMediaUpload: $willBeRetriedByMediaUpload, ') + ..write('markForRetry: $markForRetry, ') + ..write('markForRetryAfterAccepted: $markForRetryAfterAccepted, ') + ..write('ackByServerAt: $ackByServerAt, ') + ..write('retryCount: $retryCount, ') + ..write('lastRetry: $lastRetry, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class ReceivedReceipts extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + ReceivedReceipts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn receiptId = GeneratedColumn( + 'receipt_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [receiptId, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'received_receipts'; + @override + Set get $primaryKey => {receiptId}; + @override + ReceivedReceiptsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReceivedReceiptsData( + receiptId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}receipt_id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + ReceivedReceipts createAlias(String alias) { + return ReceivedReceipts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(receipt_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ReceivedReceiptsData extends DataClass + implements Insertable { + final String receiptId; + final int createdAt; + const ReceivedReceiptsData({ + required this.receiptId, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['receipt_id'] = Variable(receiptId); + map['created_at'] = Variable(createdAt); + return map; + } + + ReceivedReceiptsCompanion toCompanion(bool nullToAbsent) { + return ReceivedReceiptsCompanion( + receiptId: Value(receiptId), + createdAt: Value(createdAt), + ); + } + + factory ReceivedReceiptsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReceivedReceiptsData( + receiptId: serializer.fromJson(json['receiptId']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'receiptId': serializer.toJson(receiptId), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReceivedReceiptsData copyWith({String? receiptId, int? createdAt}) => + ReceivedReceiptsData( + receiptId: receiptId ?? this.receiptId, + createdAt: createdAt ?? this.createdAt, + ); + ReceivedReceiptsData copyWithCompanion(ReceivedReceiptsCompanion data) { + return ReceivedReceiptsData( + receiptId: data.receiptId.present ? data.receiptId.value : this.receiptId, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReceivedReceiptsData(') + ..write('receiptId: $receiptId, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(receiptId, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReceivedReceiptsData && + other.receiptId == this.receiptId && + other.createdAt == this.createdAt); +} + +class ReceivedReceiptsCompanion extends UpdateCompanion { + final Value receiptId; + final Value createdAt; + final Value rowid; + const ReceivedReceiptsCompanion({ + this.receiptId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReceivedReceiptsCompanion.insert({ + required String receiptId, + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : receiptId = Value(receiptId); + static Insertable custom({ + Expression? receiptId, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (receiptId != null) 'receipt_id': receiptId, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReceivedReceiptsCompanion copyWith({ + Value? receiptId, + Value? createdAt, + Value? rowid, + }) { + return ReceivedReceiptsCompanion( + receiptId: receiptId ?? this.receiptId, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (receiptId.present) { + map['receipt_id'] = Variable(receiptId.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('ReceivedReceiptsCompanion(') + ..write('receiptId: $receiptId, ') + ..write('createdAt: $createdAt, ') + ..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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn identityKey = + GeneratedColumn( + 'identity_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalIdentityKeyStores createAlias(String alias) { + return SignalIdentityKeyStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(device_id, name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalIdentityKeyStoresData extends DataClass + implements Insertable { + final int deviceId; + final String name; + final i2.Uint8List identityKey; + final int 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, + i2.Uint8List? identityKey, + int? 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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn preKey = + GeneratedColumn( + 'pre_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalPreKeyStores createAlias(String alias) { + return SignalPreKeyStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(pre_key_id)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalPreKeyStoresData extends DataClass + implements Insertable { + final int preKeyId; + final i2.Uint8List preKey; + final int 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, + i2.Uint8List? preKey, + int? 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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderKey = + GeneratedColumn( + 'sender_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + @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); + } + + @override + List get customConstraints => const ['PRIMARY KEY(sender_key_name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalSenderKeyStoresData extends DataClass + implements Insertable { + final String senderKeyName; + final i2.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, + i2.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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn sessionRecord = + GeneratedColumn( + 'session_record', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalSessionStores createAlias(String alias) { + return SignalSessionStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(device_id, name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalSessionStoresData extends DataClass + implements Insertable { + final int deviceId; + final String name; + final i2.Uint8List sessionRecord; + final int 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, + i2.Uint8List? sessionRecord, + int? 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 i2.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 MessageActions extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MessageActions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn actionAt = GeneratedColumn( + 'action_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [messageId, contactId, type, actionAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'message_actions'; + @override + Set get $primaryKey => {messageId, contactId, type}; + @override + MessageActionsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MessageActionsData( + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + actionAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}action_at'], + )!, + ); + } + + @override + MessageActions createAlias(String alias) { + return MessageActions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(message_id, contact_id, type)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class MessageActionsData extends DataClass + implements Insertable { + final String messageId; + final int contactId; + final String type; + final int actionAt; + const MessageActionsData({ + required this.messageId, + required this.contactId, + required this.type, + required this.actionAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['message_id'] = Variable(messageId); + map['contact_id'] = Variable(contactId); + map['type'] = Variable(type); + map['action_at'] = Variable(actionAt); + return map; + } + + MessageActionsCompanion toCompanion(bool nullToAbsent) { + return MessageActionsCompanion( + messageId: Value(messageId), + contactId: Value(contactId), + type: Value(type), + actionAt: Value(actionAt), + ); + } + + factory MessageActionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessageActionsData( + messageId: serializer.fromJson(json['messageId']), + contactId: serializer.fromJson(json['contactId']), + type: serializer.fromJson(json['type']), + actionAt: serializer.fromJson(json['actionAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'messageId': serializer.toJson(messageId), + 'contactId': serializer.toJson(contactId), + 'type': serializer.toJson(type), + 'actionAt': serializer.toJson(actionAt), + }; + } + + MessageActionsData copyWith({ + String? messageId, + int? contactId, + String? type, + int? actionAt, + }) => MessageActionsData( + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + ); + MessageActionsData copyWithCompanion(MessageActionsCompanion data) { + return MessageActionsData( + messageId: data.messageId.present ? data.messageId.value : this.messageId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + type: data.type.present ? data.type.value : this.type, + actionAt: data.actionAt.present ? data.actionAt.value : this.actionAt, + ); + } + + @override + String toString() { + return (StringBuffer('MessageActionsData(') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('actionAt: $actionAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(messageId, contactId, type, actionAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessageActionsData && + other.messageId == this.messageId && + other.contactId == this.contactId && + other.type == this.type && + other.actionAt == this.actionAt); +} + +class MessageActionsCompanion extends UpdateCompanion { + final Value messageId; + final Value contactId; + final Value type; + final Value actionAt; + final Value rowid; + const MessageActionsCompanion({ + this.messageId = const Value.absent(), + this.contactId = const Value.absent(), + this.type = const Value.absent(), + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + MessageActionsCompanion.insert({ + required String messageId, + required int contactId, + required String type, + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : messageId = Value(messageId), + contactId = Value(contactId), + type = Value(type); + static Insertable custom({ + Expression? messageId, + Expression? contactId, + Expression? type, + Expression? actionAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (messageId != null) 'message_id': messageId, + if (contactId != null) 'contact_id': contactId, + if (type != null) 'type': type, + if (actionAt != null) 'action_at': actionAt, + if (rowid != null) 'rowid': rowid, + }); + } + + MessageActionsCompanion copyWith({ + Value? messageId, + Value? contactId, + Value? type, + Value? actionAt, + Value? rowid, + }) { + return MessageActionsCompanion( + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (actionAt.present) { + map['action_at'] = Variable(actionAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessageActionsCompanion(') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('actionAt: $actionAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class GroupHistories extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + GroupHistories(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupHistoryId = GeneratedColumn( + 'group_history_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn affectedContactId = GeneratedColumn( + 'affected_contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn oldGroupName = GeneratedColumn( + 'old_group_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn newGroupName = GeneratedColumn( + 'new_group_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn newDeleteMessagesAfterMilliseconds = + GeneratedColumn( + 'new_delete_messages_after_milliseconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn actionAt = GeneratedColumn( + 'action_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupHistoryId, + groupId, + contactId, + affectedContactId, + oldGroupName, + newGroupName, + newDeleteMessagesAfterMilliseconds, + type, + actionAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'group_histories'; + @override + Set get $primaryKey => {groupHistoryId}; + @override + GroupHistoriesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupHistoriesData( + groupHistoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_history_id'], + )!, + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + affectedContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}affected_contact_id'], + ), + oldGroupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}old_group_name'], + ), + newGroupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}new_group_name'], + ), + newDeleteMessagesAfterMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}new_delete_messages_after_milliseconds'], + ), + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + actionAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}action_at'], + )!, + ); + } + + @override + GroupHistories createAlias(String alias) { + return GroupHistories(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(group_history_id)']; + @override + bool get dontWriteConstraints => true; +} + +class GroupHistoriesData extends DataClass + implements Insertable { + final String groupHistoryId; + final String groupId; + final int? contactId; + final int? affectedContactId; + final String? oldGroupName; + final String? newGroupName; + final int? newDeleteMessagesAfterMilliseconds; + final String type; + final int actionAt; + const GroupHistoriesData({ + required this.groupHistoryId, + required this.groupId, + this.contactId, + this.affectedContactId, + this.oldGroupName, + this.newGroupName, + this.newDeleteMessagesAfterMilliseconds, + required this.type, + required this.actionAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_history_id'] = Variable(groupHistoryId); + map['group_id'] = Variable(groupId); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + if (!nullToAbsent || affectedContactId != null) { + map['affected_contact_id'] = Variable(affectedContactId); + } + if (!nullToAbsent || oldGroupName != null) { + map['old_group_name'] = Variable(oldGroupName); + } + if (!nullToAbsent || newGroupName != null) { + map['new_group_name'] = Variable(newGroupName); + } + if (!nullToAbsent || newDeleteMessagesAfterMilliseconds != null) { + map['new_delete_messages_after_milliseconds'] = Variable( + newDeleteMessagesAfterMilliseconds, + ); + } + map['type'] = Variable(type); + map['action_at'] = Variable(actionAt); + return map; + } + + GroupHistoriesCompanion toCompanion(bool nullToAbsent) { + return GroupHistoriesCompanion( + groupHistoryId: Value(groupHistoryId), + groupId: Value(groupId), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + affectedContactId: affectedContactId == null && nullToAbsent + ? const Value.absent() + : Value(affectedContactId), + oldGroupName: oldGroupName == null && nullToAbsent + ? const Value.absent() + : Value(oldGroupName), + newGroupName: newGroupName == null && nullToAbsent + ? const Value.absent() + : Value(newGroupName), + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds == null && nullToAbsent + ? const Value.absent() + : Value(newDeleteMessagesAfterMilliseconds), + type: Value(type), + actionAt: Value(actionAt), + ); + } + + factory GroupHistoriesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupHistoriesData( + groupHistoryId: serializer.fromJson(json['groupHistoryId']), + groupId: serializer.fromJson(json['groupId']), + contactId: serializer.fromJson(json['contactId']), + affectedContactId: serializer.fromJson(json['affectedContactId']), + oldGroupName: serializer.fromJson(json['oldGroupName']), + newGroupName: serializer.fromJson(json['newGroupName']), + newDeleteMessagesAfterMilliseconds: serializer.fromJson( + json['newDeleteMessagesAfterMilliseconds'], + ), + type: serializer.fromJson(json['type']), + actionAt: serializer.fromJson(json['actionAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupHistoryId': serializer.toJson(groupHistoryId), + 'groupId': serializer.toJson(groupId), + 'contactId': serializer.toJson(contactId), + 'affectedContactId': serializer.toJson(affectedContactId), + 'oldGroupName': serializer.toJson(oldGroupName), + 'newGroupName': serializer.toJson(newGroupName), + 'newDeleteMessagesAfterMilliseconds': serializer.toJson( + newDeleteMessagesAfterMilliseconds, + ), + 'type': serializer.toJson(type), + 'actionAt': serializer.toJson(actionAt), + }; + } + + GroupHistoriesData copyWith({ + String? groupHistoryId, + String? groupId, + Value contactId = const Value.absent(), + Value affectedContactId = const Value.absent(), + Value oldGroupName = const Value.absent(), + Value newGroupName = const Value.absent(), + Value newDeleteMessagesAfterMilliseconds = const Value.absent(), + String? type, + int? actionAt, + }) => GroupHistoriesData( + groupHistoryId: groupHistoryId ?? this.groupHistoryId, + groupId: groupId ?? this.groupId, + contactId: contactId.present ? contactId.value : this.contactId, + affectedContactId: affectedContactId.present + ? affectedContactId.value + : this.affectedContactId, + oldGroupName: oldGroupName.present ? oldGroupName.value : this.oldGroupName, + newGroupName: newGroupName.present ? newGroupName.value : this.newGroupName, + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds.present + ? newDeleteMessagesAfterMilliseconds.value + : this.newDeleteMessagesAfterMilliseconds, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + ); + GroupHistoriesData copyWithCompanion(GroupHistoriesCompanion data) { + return GroupHistoriesData( + groupHistoryId: data.groupHistoryId.present + ? data.groupHistoryId.value + : this.groupHistoryId, + groupId: data.groupId.present ? data.groupId.value : this.groupId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + affectedContactId: data.affectedContactId.present + ? data.affectedContactId.value + : this.affectedContactId, + oldGroupName: data.oldGroupName.present + ? data.oldGroupName.value + : this.oldGroupName, + newGroupName: data.newGroupName.present + ? data.newGroupName.value + : this.newGroupName, + newDeleteMessagesAfterMilliseconds: + data.newDeleteMessagesAfterMilliseconds.present + ? data.newDeleteMessagesAfterMilliseconds.value + : this.newDeleteMessagesAfterMilliseconds, + type: data.type.present ? data.type.value : this.type, + actionAt: data.actionAt.present ? data.actionAt.value : this.actionAt, + ); + } + + @override + String toString() { + return (StringBuffer('GroupHistoriesData(') + ..write('groupHistoryId: $groupHistoryId, ') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('affectedContactId: $affectedContactId, ') + ..write('oldGroupName: $oldGroupName, ') + ..write('newGroupName: $newGroupName, ') + ..write( + 'newDeleteMessagesAfterMilliseconds: $newDeleteMessagesAfterMilliseconds, ', + ) + ..write('type: $type, ') + ..write('actionAt: $actionAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupHistoryId, + groupId, + contactId, + affectedContactId, + oldGroupName, + newGroupName, + newDeleteMessagesAfterMilliseconds, + type, + actionAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupHistoriesData && + other.groupHistoryId == this.groupHistoryId && + other.groupId == this.groupId && + other.contactId == this.contactId && + other.affectedContactId == this.affectedContactId && + other.oldGroupName == this.oldGroupName && + other.newGroupName == this.newGroupName && + other.newDeleteMessagesAfterMilliseconds == + this.newDeleteMessagesAfterMilliseconds && + other.type == this.type && + other.actionAt == this.actionAt); +} + +class GroupHistoriesCompanion extends UpdateCompanion { + final Value groupHistoryId; + final Value groupId; + final Value contactId; + final Value affectedContactId; + final Value oldGroupName; + final Value newGroupName; + final Value newDeleteMessagesAfterMilliseconds; + final Value type; + final Value actionAt; + final Value rowid; + const GroupHistoriesCompanion({ + this.groupHistoryId = const Value.absent(), + this.groupId = const Value.absent(), + this.contactId = const Value.absent(), + this.affectedContactId = const Value.absent(), + this.oldGroupName = const Value.absent(), + this.newGroupName = const Value.absent(), + this.newDeleteMessagesAfterMilliseconds = const Value.absent(), + this.type = const Value.absent(), + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupHistoriesCompanion.insert({ + required String groupHistoryId, + required String groupId, + this.contactId = const Value.absent(), + this.affectedContactId = const Value.absent(), + this.oldGroupName = const Value.absent(), + this.newGroupName = const Value.absent(), + this.newDeleteMessagesAfterMilliseconds = const Value.absent(), + required String type, + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupHistoryId = Value(groupHistoryId), + groupId = Value(groupId), + type = Value(type); + static Insertable custom({ + Expression? groupHistoryId, + Expression? groupId, + Expression? contactId, + Expression? affectedContactId, + Expression? oldGroupName, + Expression? newGroupName, + Expression? newDeleteMessagesAfterMilliseconds, + Expression? type, + Expression? actionAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupHistoryId != null) 'group_history_id': groupHistoryId, + if (groupId != null) 'group_id': groupId, + if (contactId != null) 'contact_id': contactId, + if (affectedContactId != null) 'affected_contact_id': affectedContactId, + if (oldGroupName != null) 'old_group_name': oldGroupName, + if (newGroupName != null) 'new_group_name': newGroupName, + if (newDeleteMessagesAfterMilliseconds != null) + 'new_delete_messages_after_milliseconds': + newDeleteMessagesAfterMilliseconds, + if (type != null) 'type': type, + if (actionAt != null) 'action_at': actionAt, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupHistoriesCompanion copyWith({ + Value? groupHistoryId, + Value? groupId, + Value? contactId, + Value? affectedContactId, + Value? oldGroupName, + Value? newGroupName, + Value? newDeleteMessagesAfterMilliseconds, + Value? type, + Value? actionAt, + Value? rowid, + }) { + return GroupHistoriesCompanion( + groupHistoryId: groupHistoryId ?? this.groupHistoryId, + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + affectedContactId: affectedContactId ?? this.affectedContactId, + oldGroupName: oldGroupName ?? this.oldGroupName, + newGroupName: newGroupName ?? this.newGroupName, + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds ?? + this.newDeleteMessagesAfterMilliseconds, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupHistoryId.present) { + map['group_history_id'] = Variable(groupHistoryId.value); + } + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (affectedContactId.present) { + map['affected_contact_id'] = Variable(affectedContactId.value); + } + if (oldGroupName.present) { + map['old_group_name'] = Variable(oldGroupName.value); + } + if (newGroupName.present) { + map['new_group_name'] = Variable(newGroupName.value); + } + if (newDeleteMessagesAfterMilliseconds.present) { + map['new_delete_messages_after_milliseconds'] = Variable( + newDeleteMessagesAfterMilliseconds.value, + ); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (actionAt.present) { + map['action_at'] = Variable(actionAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GroupHistoriesCompanion(') + ..write('groupHistoryId: $groupHistoryId, ') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('affectedContactId: $affectedContactId, ') + ..write('oldGroupName: $oldGroupName, ') + ..write('newGroupName: $newGroupName, ') + ..write( + 'newDeleteMessagesAfterMilliseconds: $newDeleteMessagesAfterMilliseconds, ', + ) + ..write('type: $type, ') + ..write('actionAt: $actionAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class KeyVerifications extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + KeyVerifications(this.attachedDatabase, [this._alias]); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [contactId, type, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'key_verifications'; + @override + Set get $primaryKey => {contactId}; + @override + KeyVerificationsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return KeyVerificationsData( + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + KeyVerifications createAlias(String alias) { + return KeyVerifications(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(contact_id)']; + @override + bool get dontWriteConstraints => true; +} + +class KeyVerificationsData extends DataClass + implements Insertable { + final int contactId; + final String type; + final int createdAt; + const KeyVerificationsData({ + required this.contactId, + required this.type, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['contact_id'] = Variable(contactId); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + return map; + } + + KeyVerificationsCompanion toCompanion(bool nullToAbsent) { + return KeyVerificationsCompanion( + contactId: Value(contactId), + type: Value(type), + createdAt: Value(createdAt), + ); + } + + factory KeyVerificationsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return KeyVerificationsData( + contactId: serializer.fromJson(json['contactId']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'contactId': serializer.toJson(contactId), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + }; + } + + KeyVerificationsData copyWith({ + int? contactId, + String? type, + int? createdAt, + }) => KeyVerificationsData( + contactId: contactId ?? this.contactId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + KeyVerificationsData copyWithCompanion(KeyVerificationsCompanion data) { + return KeyVerificationsData( + contactId: data.contactId.present ? data.contactId.value : this.contactId, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('KeyVerificationsData(') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(contactId, type, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is KeyVerificationsData && + other.contactId == this.contactId && + other.type == this.type && + other.createdAt == this.createdAt); +} + +class KeyVerificationsCompanion extends UpdateCompanion { + final Value contactId; + final Value type; + final Value createdAt; + const KeyVerificationsCompanion({ + this.contactId = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + }); + KeyVerificationsCompanion.insert({ + this.contactId = const Value.absent(), + required String type, + this.createdAt = const Value.absent(), + }) : type = Value(type); + static Insertable custom({ + Expression? contactId, + Expression? type, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (contactId != null) 'contact_id': contactId, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + }); + } + + KeyVerificationsCompanion copyWith({ + Value? contactId, + Value? type, + Value? createdAt, + }) { + return KeyVerificationsCompanion( + contactId: contactId ?? this.contactId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('KeyVerificationsCompanion(') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class VerificationTokens extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + VerificationTokens(this.attachedDatabase, [this._alias]); + late final GeneratedColumn tokenId = GeneratedColumn( + 'token_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn token = + GeneratedColumn( + 'token', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [tokenId, token, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'verification_tokens'; + @override + Set get $primaryKey => {tokenId}; + @override + VerificationTokensData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return VerificationTokensData( + tokenId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}token_id'], + )!, + token: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}token'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + VerificationTokens createAlias(String alias) { + return VerificationTokens(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class VerificationTokensData extends DataClass + implements Insertable { + final int tokenId; + final i2.Uint8List token; + final int createdAt; + const VerificationTokensData({ + required this.tokenId, + required this.token, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['token_id'] = Variable(tokenId); + map['token'] = Variable(token); + map['created_at'] = Variable(createdAt); + return map; + } + + VerificationTokensCompanion toCompanion(bool nullToAbsent) { + return VerificationTokensCompanion( + tokenId: Value(tokenId), + token: Value(token), + createdAt: Value(createdAt), + ); + } + + factory VerificationTokensData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return VerificationTokensData( + tokenId: serializer.fromJson(json['tokenId']), + token: serializer.fromJson(json['token']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'tokenId': serializer.toJson(tokenId), + 'token': serializer.toJson(token), + 'createdAt': serializer.toJson(createdAt), + }; + } + + VerificationTokensData copyWith({ + int? tokenId, + i2.Uint8List? token, + int? createdAt, + }) => VerificationTokensData( + tokenId: tokenId ?? this.tokenId, + token: token ?? this.token, + createdAt: createdAt ?? this.createdAt, + ); + VerificationTokensData copyWithCompanion(VerificationTokensCompanion data) { + return VerificationTokensData( + tokenId: data.tokenId.present ? data.tokenId.value : this.tokenId, + token: data.token.present ? data.token.value : this.token, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('VerificationTokensData(') + ..write('tokenId: $tokenId, ') + ..write('token: $token, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(tokenId, $driftBlobEquality.hash(token), createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is VerificationTokensData && + other.tokenId == this.tokenId && + $driftBlobEquality.equals(other.token, this.token) && + other.createdAt == this.createdAt); +} + +class VerificationTokensCompanion + extends UpdateCompanion { + final Value tokenId; + final Value token; + final Value createdAt; + const VerificationTokensCompanion({ + this.tokenId = const Value.absent(), + this.token = const Value.absent(), + this.createdAt = const Value.absent(), + }); + VerificationTokensCompanion.insert({ + this.tokenId = const Value.absent(), + required i2.Uint8List token, + this.createdAt = const Value.absent(), + }) : token = Value(token); + static Insertable custom({ + Expression? tokenId, + Expression? token, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (tokenId != null) 'token_id': tokenId, + if (token != null) 'token': token, + if (createdAt != null) 'created_at': createdAt, + }); + } + + VerificationTokensCompanion copyWith({ + Value? tokenId, + Value? token, + Value? createdAt, + }) { + return VerificationTokensCompanion( + tokenId: tokenId ?? this.tokenId, + token: token ?? this.token, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (tokenId.present) { + map['token_id'] = Variable(tokenId.value); + } + if (token.present) { + map['token'] = Variable(token.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('VerificationTokensCompanion(') + ..write('tokenId: $tokenId, ') + ..write('token: $token, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryAnnouncedUsers extends Table + with + TableInfo< + UserDiscoveryAnnouncedUsers, + UserDiscoveryAnnouncedUsersData + > { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryAnnouncedUsers(this.attachedDatabase, [this._alias]); + late final GeneratedColumn announcedUserId = GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn announcedPublicKey = + GeneratedColumn( + 'announced_public_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicId = GeneratedColumn( + 'public_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL UNIQUE', + ); + late final GeneratedColumn username = GeneratedColumn( + 'username', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn wasShownToTheUser = GeneratedColumn( + 'was_shown_to_the_user', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (was_shown_to_the_user IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn isHidden = GeneratedColumn( + 'is_hidden', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_hidden IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [ + announcedUserId, + announcedPublicKey, + publicId, + username, + wasShownToTheUser, + isHidden, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_announced_users'; + @override + Set get $primaryKey => {announcedUserId}; + @override + UserDiscoveryAnnouncedUsersData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryAnnouncedUsersData( + announcedUserId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}announced_user_id'], + )!, + announcedPublicKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}announced_public_key'], + )!, + publicId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_id'], + )!, + username: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}username'], + ), + wasShownToTheUser: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}was_shown_to_the_user'], + )!, + isHidden: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_hidden'], + )!, + ); + } + + @override + UserDiscoveryAnnouncedUsers createAlias(String alias) { + return UserDiscoveryAnnouncedUsers(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(announced_user_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryAnnouncedUsersData extends DataClass + implements Insertable { + final int announcedUserId; + final i2.Uint8List announcedPublicKey; + final int publicId; + final String? username; + final int wasShownToTheUser; + final int isHidden; + const UserDiscoveryAnnouncedUsersData({ + required this.announcedUserId, + required this.announcedPublicKey, + required this.publicId, + this.username, + required this.wasShownToTheUser, + required this.isHidden, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['announced_user_id'] = Variable(announcedUserId); + map['announced_public_key'] = Variable(announcedPublicKey); + map['public_id'] = Variable(publicId); + if (!nullToAbsent || username != null) { + map['username'] = Variable(username); + } + map['was_shown_to_the_user'] = Variable(wasShownToTheUser); + map['is_hidden'] = Variable(isHidden); + return map; + } + + UserDiscoveryAnnouncedUsersCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: Value(announcedUserId), + announcedPublicKey: Value(announcedPublicKey), + publicId: Value(publicId), + username: username == null && nullToAbsent + ? const Value.absent() + : Value(username), + wasShownToTheUser: Value(wasShownToTheUser), + isHidden: Value(isHidden), + ); + } + + factory UserDiscoveryAnnouncedUsersData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryAnnouncedUsersData( + announcedUserId: serializer.fromJson(json['announcedUserId']), + announcedPublicKey: serializer.fromJson( + json['announcedPublicKey'], + ), + publicId: serializer.fromJson(json['publicId']), + username: serializer.fromJson(json['username']), + wasShownToTheUser: serializer.fromJson(json['wasShownToTheUser']), + isHidden: serializer.fromJson(json['isHidden']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'announcedUserId': serializer.toJson(announcedUserId), + 'announcedPublicKey': serializer.toJson(announcedPublicKey), + 'publicId': serializer.toJson(publicId), + 'username': serializer.toJson(username), + 'wasShownToTheUser': serializer.toJson(wasShownToTheUser), + 'isHidden': serializer.toJson(isHidden), + }; + } + + UserDiscoveryAnnouncedUsersData copyWith({ + int? announcedUserId, + i2.Uint8List? announcedPublicKey, + int? publicId, + Value username = const Value.absent(), + int? wasShownToTheUser, + int? isHidden, + }) => UserDiscoveryAnnouncedUsersData( + announcedUserId: announcedUserId ?? this.announcedUserId, + announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, + publicId: publicId ?? this.publicId, + username: username.present ? username.value : this.username, + wasShownToTheUser: wasShownToTheUser ?? this.wasShownToTheUser, + isHidden: isHidden ?? this.isHidden, + ); + UserDiscoveryAnnouncedUsersData copyWithCompanion( + UserDiscoveryAnnouncedUsersCompanion data, + ) { + return UserDiscoveryAnnouncedUsersData( + announcedUserId: data.announcedUserId.present + ? data.announcedUserId.value + : this.announcedUserId, + announcedPublicKey: data.announcedPublicKey.present + ? data.announcedPublicKey.value + : this.announcedPublicKey, + publicId: data.publicId.present ? data.publicId.value : this.publicId, + username: data.username.present ? data.username.value : this.username, + wasShownToTheUser: data.wasShownToTheUser.present + ? data.wasShownToTheUser.value + : this.wasShownToTheUser, + isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryAnnouncedUsersData(') + ..write('announcedUserId: $announcedUserId, ') + ..write('announcedPublicKey: $announcedPublicKey, ') + ..write('publicId: $publicId, ') + ..write('username: $username, ') + ..write('wasShownToTheUser: $wasShownToTheUser, ') + ..write('isHidden: $isHidden') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + announcedUserId, + $driftBlobEquality.hash(announcedPublicKey), + publicId, + username, + wasShownToTheUser, + isHidden, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryAnnouncedUsersData && + other.announcedUserId == this.announcedUserId && + $driftBlobEquality.equals( + other.announcedPublicKey, + this.announcedPublicKey, + ) && + other.publicId == this.publicId && + other.username == this.username && + other.wasShownToTheUser == this.wasShownToTheUser && + other.isHidden == this.isHidden); +} + +class UserDiscoveryAnnouncedUsersCompanion + extends UpdateCompanion { + final Value announcedUserId; + final Value announcedPublicKey; + final Value publicId; + final Value username; + final Value wasShownToTheUser; + final Value isHidden; + const UserDiscoveryAnnouncedUsersCompanion({ + this.announcedUserId = const Value.absent(), + this.announcedPublicKey = const Value.absent(), + this.publicId = const Value.absent(), + this.username = const Value.absent(), + this.wasShownToTheUser = const Value.absent(), + this.isHidden = const Value.absent(), + }); + UserDiscoveryAnnouncedUsersCompanion.insert({ + this.announcedUserId = const Value.absent(), + required i2.Uint8List announcedPublicKey, + required int publicId, + this.username = const Value.absent(), + this.wasShownToTheUser = const Value.absent(), + this.isHidden = const Value.absent(), + }) : announcedPublicKey = Value(announcedPublicKey), + publicId = Value(publicId); + static Insertable custom({ + Expression? announcedUserId, + Expression? announcedPublicKey, + Expression? publicId, + Expression? username, + Expression? wasShownToTheUser, + Expression? isHidden, + }) { + return RawValuesInsertable({ + if (announcedUserId != null) 'announced_user_id': announcedUserId, + if (announcedPublicKey != null) + 'announced_public_key': announcedPublicKey, + if (publicId != null) 'public_id': publicId, + if (username != null) 'username': username, + if (wasShownToTheUser != null) 'was_shown_to_the_user': wasShownToTheUser, + if (isHidden != null) 'is_hidden': isHidden, + }); + } + + UserDiscoveryAnnouncedUsersCompanion copyWith({ + Value? announcedUserId, + Value? announcedPublicKey, + Value? publicId, + Value? username, + Value? wasShownToTheUser, + Value? isHidden, + }) { + return UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: announcedUserId ?? this.announcedUserId, + announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, + publicId: publicId ?? this.publicId, + username: username ?? this.username, + wasShownToTheUser: wasShownToTheUser ?? this.wasShownToTheUser, + isHidden: isHidden ?? this.isHidden, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (announcedUserId.present) { + map['announced_user_id'] = Variable(announcedUserId.value); + } + if (announcedPublicKey.present) { + map['announced_public_key'] = Variable( + announcedPublicKey.value, + ); + } + if (publicId.present) { + map['public_id'] = Variable(publicId.value); + } + if (username.present) { + map['username'] = Variable(username.value); + } + if (wasShownToTheUser.present) { + map['was_shown_to_the_user'] = Variable(wasShownToTheUser.value); + } + if (isHidden.present) { + map['is_hidden'] = Variable(isHidden.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryAnnouncedUsersCompanion(') + ..write('announcedUserId: $announcedUserId, ') + ..write('announcedPublicKey: $announcedPublicKey, ') + ..write('publicId: $publicId, ') + ..write('username: $username, ') + ..write('wasShownToTheUser: $wasShownToTheUser, ') + ..write('isHidden: $isHidden') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryUserRelations extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryUserRelations(this.attachedDatabase, [this._alias]); + late final GeneratedColumn announcedUserId = GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES user_discovery_announced_users(announced_user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn fromContactId = GeneratedColumn( + 'from_contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn publicKeyVerifiedTimestamp = + GeneratedColumn( + 'public_key_verified_timestamp', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + announcedUserId, + fromContactId, + publicKeyVerifiedTimestamp, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_user_relations'; + @override + Set get $primaryKey => {announcedUserId, fromContactId}; + @override + UserDiscoveryUserRelationsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryUserRelationsData( + announcedUserId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}announced_user_id'], + )!, + fromContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}from_contact_id'], + )!, + publicKeyVerifiedTimestamp: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_key_verified_timestamp'], + ), + ); + } + + @override + UserDiscoveryUserRelations createAlias(String alias) { + return UserDiscoveryUserRelations(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(announced_user_id, from_contact_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryUserRelationsData extends DataClass + implements Insertable { + final int announcedUserId; + final int fromContactId; + final int? publicKeyVerifiedTimestamp; + const UserDiscoveryUserRelationsData({ + required this.announcedUserId, + required this.fromContactId, + this.publicKeyVerifiedTimestamp, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['announced_user_id'] = Variable(announcedUserId); + map['from_contact_id'] = Variable(fromContactId); + if (!nullToAbsent || publicKeyVerifiedTimestamp != null) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp, + ); + } + return map; + } + + UserDiscoveryUserRelationsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryUserRelationsCompanion( + announcedUserId: Value(announcedUserId), + fromContactId: Value(fromContactId), + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp == null && nullToAbsent + ? const Value.absent() + : Value(publicKeyVerifiedTimestamp), + ); + } + + factory UserDiscoveryUserRelationsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryUserRelationsData( + announcedUserId: serializer.fromJson(json['announcedUserId']), + fromContactId: serializer.fromJson(json['fromContactId']), + publicKeyVerifiedTimestamp: serializer.fromJson( + json['publicKeyVerifiedTimestamp'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'announcedUserId': serializer.toJson(announcedUserId), + 'fromContactId': serializer.toJson(fromContactId), + 'publicKeyVerifiedTimestamp': serializer.toJson( + publicKeyVerifiedTimestamp, + ), + }; + } + + UserDiscoveryUserRelationsData copyWith({ + int? announcedUserId, + int? fromContactId, + Value publicKeyVerifiedTimestamp = const Value.absent(), + }) => UserDiscoveryUserRelationsData( + announcedUserId: announcedUserId ?? this.announcedUserId, + fromContactId: fromContactId ?? this.fromContactId, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp.present + ? publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + UserDiscoveryUserRelationsData copyWithCompanion( + UserDiscoveryUserRelationsCompanion data, + ) { + return UserDiscoveryUserRelationsData( + announcedUserId: data.announcedUserId.present + ? data.announcedUserId.value + : this.announcedUserId, + fromContactId: data.fromContactId.present + ? data.fromContactId.value + : this.fromContactId, + publicKeyVerifiedTimestamp: data.publicKeyVerifiedTimestamp.present + ? data.publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryUserRelationsData(') + ..write('announcedUserId: $announcedUserId, ') + ..write('fromContactId: $fromContactId, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(announcedUserId, fromContactId, publicKeyVerifiedTimestamp); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryUserRelationsData && + other.announcedUserId == this.announcedUserId && + other.fromContactId == this.fromContactId && + other.publicKeyVerifiedTimestamp == this.publicKeyVerifiedTimestamp); +} + +class UserDiscoveryUserRelationsCompanion + extends UpdateCompanion { + final Value announcedUserId; + final Value fromContactId; + final Value publicKeyVerifiedTimestamp; + final Value rowid; + const UserDiscoveryUserRelationsCompanion({ + this.announcedUserId = const Value.absent(), + this.fromContactId = const Value.absent(), + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }); + UserDiscoveryUserRelationsCompanion.insert({ + required int announcedUserId, + required int fromContactId, + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }) : announcedUserId = Value(announcedUserId), + fromContactId = Value(fromContactId); + static Insertable custom({ + Expression? announcedUserId, + Expression? fromContactId, + Expression? publicKeyVerifiedTimestamp, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (announcedUserId != null) 'announced_user_id': announcedUserId, + if (fromContactId != null) 'from_contact_id': fromContactId, + if (publicKeyVerifiedTimestamp != null) + 'public_key_verified_timestamp': publicKeyVerifiedTimestamp, + if (rowid != null) 'rowid': rowid, + }); + } + + UserDiscoveryUserRelationsCompanion copyWith({ + Value? announcedUserId, + Value? fromContactId, + Value? publicKeyVerifiedTimestamp, + Value? rowid, + }) { + return UserDiscoveryUserRelationsCompanion( + announcedUserId: announcedUserId ?? this.announcedUserId, + fromContactId: fromContactId ?? this.fromContactId, + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp ?? this.publicKeyVerifiedTimestamp, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (announcedUserId.present) { + map['announced_user_id'] = Variable(announcedUserId.value); + } + if (fromContactId.present) { + map['from_contact_id'] = Variable(fromContactId.value); + } + if (publicKeyVerifiedTimestamp.present) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp.value, + ); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryUserRelationsCompanion(') + ..write('announcedUserId: $announcedUserId, ') + ..write('fromContactId: $fromContactId, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryOtherPromotions extends Table + with + TableInfo< + UserDiscoveryOtherPromotions, + UserDiscoveryOtherPromotionsData + > { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryOtherPromotions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn fromContactId = GeneratedColumn( + 'from_contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn promotionId = GeneratedColumn( + 'promotion_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicId = GeneratedColumn( + 'public_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn threshold = GeneratedColumn( + 'threshold', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn announcementShare = + GeneratedColumn( + 'announcement_share', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicKeyVerifiedTimestamp = + GeneratedColumn( + 'public_key_verified_timestamp', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + fromContactId, + promotionId, + publicId, + threshold, + announcementShare, + publicKeyVerifiedTimestamp, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_other_promotions'; + @override + Set get $primaryKey => {fromContactId, promotionId}; + @override + UserDiscoveryOtherPromotionsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryOtherPromotionsData( + fromContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}from_contact_id'], + )!, + promotionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}promotion_id'], + )!, + publicId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_id'], + )!, + threshold: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}threshold'], + )!, + announcementShare: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}announcement_share'], + )!, + publicKeyVerifiedTimestamp: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_key_verified_timestamp'], + ), + ); + } + + @override + UserDiscoveryOtherPromotions createAlias(String alias) { + return UserDiscoveryOtherPromotions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(from_contact_id, promotion_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryOtherPromotionsData extends DataClass + implements Insertable { + final int fromContactId; + final int promotionId; + final int publicId; + final int threshold; + final i2.Uint8List announcementShare; + final int? publicKeyVerifiedTimestamp; + const UserDiscoveryOtherPromotionsData({ + required this.fromContactId, + required this.promotionId, + required this.publicId, + required this.threshold, + required this.announcementShare, + this.publicKeyVerifiedTimestamp, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['from_contact_id'] = Variable(fromContactId); + map['promotion_id'] = Variable(promotionId); + map['public_id'] = Variable(publicId); + map['threshold'] = Variable(threshold); + map['announcement_share'] = Variable(announcementShare); + if (!nullToAbsent || publicKeyVerifiedTimestamp != null) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp, + ); + } + return map; + } + + UserDiscoveryOtherPromotionsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryOtherPromotionsCompanion( + fromContactId: Value(fromContactId), + promotionId: Value(promotionId), + publicId: Value(publicId), + threshold: Value(threshold), + announcementShare: Value(announcementShare), + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp == null && nullToAbsent + ? const Value.absent() + : Value(publicKeyVerifiedTimestamp), + ); + } + + factory UserDiscoveryOtherPromotionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryOtherPromotionsData( + fromContactId: serializer.fromJson(json['fromContactId']), + promotionId: serializer.fromJson(json['promotionId']), + publicId: serializer.fromJson(json['publicId']), + threshold: serializer.fromJson(json['threshold']), + announcementShare: serializer.fromJson( + json['announcementShare'], + ), + publicKeyVerifiedTimestamp: serializer.fromJson( + json['publicKeyVerifiedTimestamp'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'fromContactId': serializer.toJson(fromContactId), + 'promotionId': serializer.toJson(promotionId), + 'publicId': serializer.toJson(publicId), + 'threshold': serializer.toJson(threshold), + 'announcementShare': serializer.toJson(announcementShare), + 'publicKeyVerifiedTimestamp': serializer.toJson( + publicKeyVerifiedTimestamp, + ), + }; + } + + UserDiscoveryOtherPromotionsData copyWith({ + int? fromContactId, + int? promotionId, + int? publicId, + int? threshold, + i2.Uint8List? announcementShare, + Value publicKeyVerifiedTimestamp = const Value.absent(), + }) => UserDiscoveryOtherPromotionsData( + fromContactId: fromContactId ?? this.fromContactId, + promotionId: promotionId ?? this.promotionId, + publicId: publicId ?? this.publicId, + threshold: threshold ?? this.threshold, + announcementShare: announcementShare ?? this.announcementShare, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp.present + ? publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + UserDiscoveryOtherPromotionsData copyWithCompanion( + UserDiscoveryOtherPromotionsCompanion data, + ) { + return UserDiscoveryOtherPromotionsData( + fromContactId: data.fromContactId.present + ? data.fromContactId.value + : this.fromContactId, + promotionId: data.promotionId.present + ? data.promotionId.value + : this.promotionId, + publicId: data.publicId.present ? data.publicId.value : this.publicId, + threshold: data.threshold.present ? data.threshold.value : this.threshold, + announcementShare: data.announcementShare.present + ? data.announcementShare.value + : this.announcementShare, + publicKeyVerifiedTimestamp: data.publicKeyVerifiedTimestamp.present + ? data.publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOtherPromotionsData(') + ..write('fromContactId: $fromContactId, ') + ..write('promotionId: $promotionId, ') + ..write('publicId: $publicId, ') + ..write('threshold: $threshold, ') + ..write('announcementShare: $announcementShare, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + fromContactId, + promotionId, + publicId, + threshold, + $driftBlobEquality.hash(announcementShare), + publicKeyVerifiedTimestamp, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryOtherPromotionsData && + other.fromContactId == this.fromContactId && + other.promotionId == this.promotionId && + other.publicId == this.publicId && + other.threshold == this.threshold && + $driftBlobEquality.equals( + other.announcementShare, + this.announcementShare, + ) && + other.publicKeyVerifiedTimestamp == this.publicKeyVerifiedTimestamp); +} + +class UserDiscoveryOtherPromotionsCompanion + extends UpdateCompanion { + final Value fromContactId; + final Value promotionId; + final Value publicId; + final Value threshold; + final Value announcementShare; + final Value publicKeyVerifiedTimestamp; + final Value rowid; + const UserDiscoveryOtherPromotionsCompanion({ + this.fromContactId = const Value.absent(), + this.promotionId = const Value.absent(), + this.publicId = const Value.absent(), + this.threshold = const Value.absent(), + this.announcementShare = const Value.absent(), + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }); + UserDiscoveryOtherPromotionsCompanion.insert({ + required int fromContactId, + required int promotionId, + required int publicId, + required int threshold, + required i2.Uint8List announcementShare, + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }) : fromContactId = Value(fromContactId), + promotionId = Value(promotionId), + publicId = Value(publicId), + threshold = Value(threshold), + announcementShare = Value(announcementShare); + static Insertable custom({ + Expression? fromContactId, + Expression? promotionId, + Expression? publicId, + Expression? threshold, + Expression? announcementShare, + Expression? publicKeyVerifiedTimestamp, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (fromContactId != null) 'from_contact_id': fromContactId, + if (promotionId != null) 'promotion_id': promotionId, + if (publicId != null) 'public_id': publicId, + if (threshold != null) 'threshold': threshold, + if (announcementShare != null) 'announcement_share': announcementShare, + if (publicKeyVerifiedTimestamp != null) + 'public_key_verified_timestamp': publicKeyVerifiedTimestamp, + if (rowid != null) 'rowid': rowid, + }); + } + + UserDiscoveryOtherPromotionsCompanion copyWith({ + Value? fromContactId, + Value? promotionId, + Value? publicId, + Value? threshold, + Value? announcementShare, + Value? publicKeyVerifiedTimestamp, + Value? rowid, + }) { + return UserDiscoveryOtherPromotionsCompanion( + fromContactId: fromContactId ?? this.fromContactId, + promotionId: promotionId ?? this.promotionId, + publicId: publicId ?? this.publicId, + threshold: threshold ?? this.threshold, + announcementShare: announcementShare ?? this.announcementShare, + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp ?? this.publicKeyVerifiedTimestamp, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (fromContactId.present) { + map['from_contact_id'] = Variable(fromContactId.value); + } + if (promotionId.present) { + map['promotion_id'] = Variable(promotionId.value); + } + if (publicId.present) { + map['public_id'] = Variable(publicId.value); + } + if (threshold.present) { + map['threshold'] = Variable(threshold.value); + } + if (announcementShare.present) { + map['announcement_share'] = Variable( + announcementShare.value, + ); + } + if (publicKeyVerifiedTimestamp.present) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp.value, + ); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOtherPromotionsCompanion(') + ..write('fromContactId: $fromContactId, ') + ..write('promotionId: $promotionId, ') + ..write('publicId: $publicId, ') + ..write('threshold: $threshold, ') + ..write('announcementShare: $announcementShare, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryOwnPromotions extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryOwnPromotions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn versionId = GeneratedColumn( + 'version_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn promotion = + GeneratedColumn( + 'promotion', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + @override + List get $columns => [versionId, contactId, promotion]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_own_promotions'; + @override + Set get $primaryKey => {versionId}; + @override + UserDiscoveryOwnPromotionsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryOwnPromotionsData( + versionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}version_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + promotion: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}promotion'], + )!, + ); + } + + @override + UserDiscoveryOwnPromotions createAlias(String alias) { + return UserDiscoveryOwnPromotions(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryOwnPromotionsData extends DataClass + implements Insertable { + final int versionId; + final int contactId; + final i2.Uint8List promotion; + const UserDiscoveryOwnPromotionsData({ + required this.versionId, + required this.contactId, + required this.promotion, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['version_id'] = Variable(versionId); + map['contact_id'] = Variable(contactId); + map['promotion'] = Variable(promotion); + return map; + } + + UserDiscoveryOwnPromotionsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryOwnPromotionsCompanion( + versionId: Value(versionId), + contactId: Value(contactId), + promotion: Value(promotion), + ); + } + + factory UserDiscoveryOwnPromotionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryOwnPromotionsData( + versionId: serializer.fromJson(json['versionId']), + contactId: serializer.fromJson(json['contactId']), + promotion: serializer.fromJson(json['promotion']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'versionId': serializer.toJson(versionId), + 'contactId': serializer.toJson(contactId), + 'promotion': serializer.toJson(promotion), + }; + } + + UserDiscoveryOwnPromotionsData copyWith({ + int? versionId, + int? contactId, + i2.Uint8List? promotion, + }) => UserDiscoveryOwnPromotionsData( + versionId: versionId ?? this.versionId, + contactId: contactId ?? this.contactId, + promotion: promotion ?? this.promotion, + ); + UserDiscoveryOwnPromotionsData copyWithCompanion( + UserDiscoveryOwnPromotionsCompanion data, + ) { + return UserDiscoveryOwnPromotionsData( + versionId: data.versionId.present ? data.versionId.value : this.versionId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + promotion: data.promotion.present ? data.promotion.value : this.promotion, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOwnPromotionsData(') + ..write('versionId: $versionId, ') + ..write('contactId: $contactId, ') + ..write('promotion: $promotion') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(versionId, contactId, $driftBlobEquality.hash(promotion)); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryOwnPromotionsData && + other.versionId == this.versionId && + other.contactId == this.contactId && + $driftBlobEquality.equals(other.promotion, this.promotion)); +} + +class UserDiscoveryOwnPromotionsCompanion + extends UpdateCompanion { + final Value versionId; + final Value contactId; + final Value promotion; + const UserDiscoveryOwnPromotionsCompanion({ + this.versionId = const Value.absent(), + this.contactId = const Value.absent(), + this.promotion = const Value.absent(), + }); + UserDiscoveryOwnPromotionsCompanion.insert({ + this.versionId = const Value.absent(), + required int contactId, + required i2.Uint8List promotion, + }) : contactId = Value(contactId), + promotion = Value(promotion); + static Insertable custom({ + Expression? versionId, + Expression? contactId, + Expression? promotion, + }) { + return RawValuesInsertable({ + if (versionId != null) 'version_id': versionId, + if (contactId != null) 'contact_id': contactId, + if (promotion != null) 'promotion': promotion, + }); + } + + UserDiscoveryOwnPromotionsCompanion copyWith({ + Value? versionId, + Value? contactId, + Value? promotion, + }) { + return UserDiscoveryOwnPromotionsCompanion( + versionId: versionId ?? this.versionId, + contactId: contactId ?? this.contactId, + promotion: promotion ?? this.promotion, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (versionId.present) { + map['version_id'] = Variable(versionId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (promotion.present) { + map['promotion'] = Variable(promotion.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOwnPromotionsCompanion(') + ..write('versionId: $versionId, ') + ..write('contactId: $contactId, ') + ..write('promotion: $promotion') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryShares extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryShares(this.attachedDatabase, [this._alias]); + late final GeneratedColumn shareId = GeneratedColumn( + 'share_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn share = + GeneratedColumn( + 'share', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + @override + List get $columns => [shareId, share, contactId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_shares'; + @override + Set get $primaryKey => {shareId}; + @override + UserDiscoverySharesData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoverySharesData( + shareId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}share_id'], + )!, + share: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}share'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + ); + } + + @override + UserDiscoveryShares createAlias(String alias) { + return UserDiscoveryShares(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoverySharesData extends DataClass + implements Insertable { + final int shareId; + final i2.Uint8List share; + final int? contactId; + const UserDiscoverySharesData({ + required this.shareId, + required this.share, + this.contactId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['share_id'] = Variable(shareId); + map['share'] = Variable(share); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + return map; + } + + UserDiscoverySharesCompanion toCompanion(bool nullToAbsent) { + return UserDiscoverySharesCompanion( + shareId: Value(shareId), + share: Value(share), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + ); + } + + factory UserDiscoverySharesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoverySharesData( + shareId: serializer.fromJson(json['shareId']), + share: serializer.fromJson(json['share']), + contactId: serializer.fromJson(json['contactId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'shareId': serializer.toJson(shareId), + 'share': serializer.toJson(share), + 'contactId': serializer.toJson(contactId), + }; + } + + UserDiscoverySharesData copyWith({ + int? shareId, + i2.Uint8List? share, + Value contactId = const Value.absent(), + }) => UserDiscoverySharesData( + shareId: shareId ?? this.shareId, + share: share ?? this.share, + contactId: contactId.present ? contactId.value : this.contactId, + ); + UserDiscoverySharesData copyWithCompanion(UserDiscoverySharesCompanion data) { + return UserDiscoverySharesData( + shareId: data.shareId.present ? data.shareId.value : this.shareId, + share: data.share.present ? data.share.value : this.share, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoverySharesData(') + ..write('shareId: $shareId, ') + ..write('share: $share, ') + ..write('contactId: $contactId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(shareId, $driftBlobEquality.hash(share), contactId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoverySharesData && + other.shareId == this.shareId && + $driftBlobEquality.equals(other.share, this.share) && + other.contactId == this.contactId); +} + +class UserDiscoverySharesCompanion + extends UpdateCompanion { + final Value shareId; + final Value share; + final Value contactId; + const UserDiscoverySharesCompanion({ + this.shareId = const Value.absent(), + this.share = const Value.absent(), + this.contactId = const Value.absent(), + }); + UserDiscoverySharesCompanion.insert({ + this.shareId = const Value.absent(), + required i2.Uint8List share, + this.contactId = const Value.absent(), + }) : share = Value(share); + static Insertable custom({ + Expression? shareId, + Expression? share, + Expression? contactId, + }) { + return RawValuesInsertable({ + if (shareId != null) 'share_id': shareId, + if (share != null) 'share': share, + if (contactId != null) 'contact_id': contactId, + }); + } + + UserDiscoverySharesCompanion copyWith({ + Value? shareId, + Value? share, + Value? contactId, + }) { + return UserDiscoverySharesCompanion( + shareId: shareId ?? this.shareId, + share: share ?? this.share, + contactId: contactId ?? this.contactId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (shareId.present) { + map['share_id'] = Variable(shareId.value); + } + if (share.present) { + map['share'] = Variable(share.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoverySharesCompanion(') + ..write('shareId: $shareId, ') + ..write('share: $share, ') + ..write('contactId: $contactId') + ..write(')')) + .toString(); + } +} + +class DatabaseAtV14 extends GeneratedDatabase { + DatabaseAtV14(QueryExecutor e) : super(e); + late final Contacts contacts = Contacts(this); + late final Groups groups = Groups(this); + late final MediaFiles mediaFiles = MediaFiles(this); + late final Messages messages = Messages(this); + late final MessageHistories messageHistories = MessageHistories(this); + late final Reactions reactions = Reactions(this); + late final GroupMembers groupMembers = GroupMembers(this); + late final Receipts receipts = Receipts(this); + late final ReceivedReceipts receivedReceipts = ReceivedReceipts(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 MessageActions messageActions = MessageActions(this); + late final GroupHistories groupHistories = GroupHistories(this); + late final KeyVerifications keyVerifications = KeyVerifications(this); + late final VerificationTokens verificationTokens = VerificationTokens(this); + late final UserDiscoveryAnnouncedUsers userDiscoveryAnnouncedUsers = + UserDiscoveryAnnouncedUsers(this); + late final UserDiscoveryUserRelations userDiscoveryUserRelations = + UserDiscoveryUserRelations(this); + late final UserDiscoveryOtherPromotions userDiscoveryOtherPromotions = + UserDiscoveryOtherPromotions(this); + late final UserDiscoveryOwnPromotions userDiscoveryOwnPromotions = + UserDiscoveryOwnPromotions(this); + late final UserDiscoveryShares userDiscoveryShares = UserDiscoveryShares( + this, + ); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + contacts, + groups, + mediaFiles, + messages, + messageHistories, + reactions, + groupMembers, + receipts, + receivedReceipts, + signalIdentityKeyStores, + signalPreKeyStores, + signalSenderKeyStores, + signalSessionStores, + messageActions, + groupHistories, + keyVerifications, + verificationTokens, + userDiscoveryAnnouncedUsers, + userDiscoveryUserRelations, + userDiscoveryOtherPromotions, + userDiscoveryOwnPromotions, + userDiscoveryShares, + ]; + @override + StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules([ + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('messages', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'media_files', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('messages', kind: UpdateKind.update)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('reactions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('reactions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_members', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('receipts', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('receipts', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_actions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_actions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('key_verifications', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'user_discovery_announced_users', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_user_relations', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_user_relations', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_other_promotions', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_own_promotions', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('user_discovery_shares', kind: UpdateKind.delete)], + ), + ]); + @override + int get schemaVersion => 14; +} From edf9e24f8af492243a8d094b17df98ed3dd2c0c8 Mon Sep 17 00:00:00 2001 From: otsmr Date: Mon, 20 Apr 2026 01:13:26 +0200 Subject: [PATCH 16/86] update strings --- lib/src/localization/translations | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/localization/translations b/lib/src/localization/translations index 93f2b3da..0029f698 160000 --- a/lib/src/localization/translations +++ b/lib/src/localization/translations @@ -1 +1 @@ -Subproject commit 93f2b3daddd98dbb022c34e7c5976a76c3143236 +Subproject commit 0029f698ea3deb47dedc4ee1f37e5688d1f83f9b From d5449800d71ac6dec5bb65fa74d346526b0d6e98 Mon Sep 17 00:00:00 2001 From: otsmr Date: Mon, 20 Apr 2026 13:30:40 +0200 Subject: [PATCH 17/86] merge dev --- lib/src/localization/translations | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/localization/translations b/lib/src/localization/translations index 0029f698..93f2b3da 160000 --- a/lib/src/localization/translations +++ b/lib/src/localization/translations @@ -1 +1 @@ -Subproject commit 0029f698ea3deb47dedc4ee1f37e5688d1f83f9b +Subproject commit 93f2b3daddd98dbb022c34e7c5976a76c3143236 From 16cc30393cb6f9bc70aa5f490325ce09e69232e0 Mon Sep 17 00:00:00 2001 From: otsmr Date: Mon, 20 Apr 2026 14:25:49 +0200 Subject: [PATCH 18/86] Fix: stored messages are not shown --- lib/src/database/daos/messages.dao.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/database/daos/messages.dao.dart b/lib/src/database/daos/messages.dao.dart index 64b91b4f..b056ff4b 100644 --- a/lib/src/database/daos/messages.dao.dart +++ b/lib/src/database/daos/messages.dao.dart @@ -78,7 +78,8 @@ class MessagesDao extends DatabaseAccessor with _$MessagesDaoMixin { // messages in groups will only be removed in case all members have received it... // so ensuring that this message is not shown in the messages anymore (t.openedAt.isBiggerThanValue(deletionTime) | - t.openedAt.isNull()), + t.openedAt.isNull() | + t.mediaStored.equals(true)), ) ..orderBy([(t) => OrderingTerm.desc(t.createdAt)]) ..limit(1)) @@ -98,7 +99,8 @@ class MessagesDao extends DatabaseAccessor with _$MessagesDaoMixin { // messages in groups will only be removed in case all members have received it... // so ensuring that this message is not shown in the messages anymore (t.openedAt.isBiggerThanValue(deletionTime) | - t.openedAt.isNull()) & + t.openedAt.isNull() | + t.mediaStored.equals(true)) & (t.isDeletedFromSender.equals(true) | (t.type.equals(MessageType.text.name).not() | t.type.equals(MessageType.media.name).not()) | From a7f1457d72fe3ca41f5a2977a946266766cffb1b Mon Sep 17 00:00:00 2001 From: otsmr Date: Mon, 20 Apr 2026 14:26:54 +0200 Subject: [PATCH 19/86] add target --- .gitignore | 3 +- lib/src/localization/translations | 2 +- rust_dependencies/Cargo.lock | 1639 +++++++++++++++++++++++++++++ 3 files changed, 1642 insertions(+), 2 deletions(-) create mode 100644 rust_dependencies/Cargo.lock diff --git a/.gitignore b/.gitignore index 22e61b6f..9d085fd2 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,5 @@ app.*.map.json /android/app/.cxx/ android/.kotlin/ devtools_options.yaml -rust/target \ No newline at end of file +rust/target +rust_dependencies/target \ No newline at end of file diff --git a/lib/src/localization/translations b/lib/src/localization/translations index 93f2b3da..0029f698 160000 --- a/lib/src/localization/translations +++ b/lib/src/localization/translations @@ -1 +1 @@ -Subproject commit 93f2b3daddd98dbb022c34e7c5976a76c3143236 +Subproject commit 0029f698ea3deb47dedc4ee1f37e5688d1f83f9b diff --git a/rust_dependencies/Cargo.lock b/rust_dependencies/Cargo.lock new file mode 100644 index 00000000..2a1c057b --- /dev/null +++ b/rust_dependencies/Cargo.lock @@ -0,0 +1,1639 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "blahaj" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5106bf2680d585dc5f29711b8aa5dde353180b8e14af89b7f0424f760c84e7ce" +dependencies = [ + "hashbrown 0.15.5", + "rand 0.8.6", + "zeroize", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + +[[package]] +name = "cmov" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "block-buffer 0.12.0", + "const-oid", + "crypto-common 0.2.1", + "ctutils", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core 0.10.1", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.2", +] + +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "hybrid-array" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214" +dependencies = [ + "typenum", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", + "serde", + "serde_core", +] + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" +dependencies = [ + "heck", + "itertools", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +dependencies = [ + "prost", +] + +[[package]] +name = "protocols" +version = "0.1.0" +dependencies = [ + "base64", + "blahaj", + "hmac", + "pretty_env_logger", + "prost", + "prost-build", + "rand 0.10.1", + "serde", + "serde_json", + "sha2 0.11.0", + "sqlx", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.2", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "sqlx" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "decccfa5f2f3eac95eb68085cfe69a0172fa9711666c3a634cfc806d4fb74a47" +dependencies = [ + "sqlx-core", + "sqlx-macros", +] + +[[package]] +name = "sqlx-core" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86854e8c6aba0dafcf1c04b4836b0b7fa3a20c560e3554567afefe1258fa4e60" +dependencies = [ + "base64", + "bytes", + "cfg-if", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.16.1", + "hashlink", + "indexmap", + "log", + "memchr", + "percent-encoding", + "serde", + "sha2 0.10.9", + "smallvec", + "thiserror", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7aab9442ed1568e3aed6c368737226ee4e0e8d1deb0e0887fa6bf15282ace44" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34eb4976b8f02ac57ee98d4ce40cd1aad7ab31d9792977bc3171f787ba6ba2fb" +dependencies = [ + "cfg-if", + "dotenvy", + "either", + "heck", + "hex", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "sqlx-core", + "syn", + "url", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.52.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" From 93d5f682fce6c15c63449f7e2e433e8154e90dae Mon Sep 17 00:00:00 2001 From: otsmr Date: Mon, 20 Apr 2026 15:27:31 +0200 Subject: [PATCH 20/86] fix: click on image notification causes wrong routing --- lib/app.dart | 7 +------ lib/src/views/home.view.dart | 10 ++++++++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index 7166d224..0576e6fd 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -136,13 +136,11 @@ class _AppMainWidgetState extends State { bool _isLoaded = false; bool _skipBackup = false; bool _isTwonlyLocked = true; - int _initialPage = 0; (Future?, bool) _proofOfWork = (null, false); @override void initState() { - _initialPage = widget.initialPage; initAsync(); super.initState(); } @@ -158,9 +156,6 @@ class _AppMainWidgetState extends State { if (gUser.appVersion < 62) { _showDatabaseMigration = true; } - if (!gUser.startWithCameraOpen) { - _initialPage = 0; - } } if (!_isUserCreated && !_showDatabaseMigration) { @@ -210,7 +205,7 @@ class _AppMainWidgetState extends State { ); } else { child = HomeView( - initialPage: _initialPage, + initialPage: widget.initialPage, ); } } else if (_showOnboarding) { diff --git a/lib/src/views/home.view.dart b/lib/src/views/home.view.dart index f208d90e..8d5b889c 100644 --- a/lib/src/views/home.view.dart +++ b/lib/src/views/home.view.dart @@ -135,7 +135,8 @@ class HomeViewState extends State { _mainCameraController.setSharedLinkForPreview, ); WidgetsBinding.instance.addPostFrameCallback((_) { - if (widget.initialPage == 0) { + if (widget.initialPage == 1 && !gUser.startWithCameraOpen || + widget.initialPage == 0) { globalUpdateOfHomeViewPageIndex(0); } }); @@ -161,10 +162,15 @@ class HomeViewState extends State { if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) { final payload = notificationAppLaunchDetails?.notificationResponse?.payload; - if (payload != null && payload.startsWith(Routes.chats)) { + if (payload != null && + payload.startsWith(Routes.chats) && + payload != Routes.chats) { await routerProvider.push(payload); globalUpdateOfHomeViewPageIndex(0); } + if (payload == Routes.chats) { + globalUpdateOfHomeViewPageIndex(0); + } } } From 693c74df464c3b37cdc9d1d64b1595fffb041778 Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 21 Apr 2026 01:31:50 +0200 Subject: [PATCH 21/86] first working state --- analysis_options.yaml | 4 +- integration_test/api_service.test.dart | 27 +- .../callbacks/user_discovery.callbacks.dart | 3 +- lib/src/database/daos/contacts.dao.dart | 1 + lib/src/database/daos/groups.dao.dart | 15 + lib/src/database/daos/user_discovery.dao.dart | 115 +- .../schemas/twonly_db/drift_schema_v15.json | 2727 +++++ lib/src/database/tables/contacts.table.dart | 3 + lib/src/database/twonly.db.dart | 11 +- lib/src/database/twonly.db.g.dart | 81 + lib/src/database/twonly.db.steps.dart | 463 + .../generated/app_localizations.dart | 214 +- .../generated/app_localizations_de.dart | 134 +- .../generated/app_localizations_en.dart | 133 +- .../generated/app_localizations_sv.dart | 133 +- .../api/client2client/contact.c2c.dart | 12 +- .../api/client2client/user_discovery.c2c.dart | 10 +- lib/src/services/api/messages.dart | 5 +- lib/src/services/api/server_messages.dart | 5 +- lib/src/services/user_discovery.service.dart | 27 +- lib/src/utils/misc.dart | 26 +- lib/src/views/chats/add_new_user.view.dart | 244 +- .../friend_suggestions.dart | 162 + .../open_requests_list.dart | 189 + lib/src/views/chats/chat_list.view.dart | 14 +- .../typing_indicator.dart | 9 +- .../views/components/notification_badge.dart | 10 +- lib/src/views/contact/contact.view.dart | 47 +- .../user_discovery_disabled.component.dart | 28 +- .../user_discovery_enabled.component.dart | 89 +- .../user_discovery_settings.view.dart | 19 +- rust_builder/pubspec.yaml | 2 +- test/drift/twonly_db/generated/schema.dart | 21 +- .../drift/twonly_db/generated/schema_v15.dart | 9602 +++++++++++++++++ 34 files changed, 14259 insertions(+), 326 deletions(-) create mode 100644 lib/src/database/schemas/twonly_db/drift_schema_v15.json create mode 100644 lib/src/views/chats/add_new_user_components/friend_suggestions.dart create mode 100644 lib/src/views/chats/add_new_user_components/open_requests_list.dart create mode 100644 test/drift/twonly_db/generated/schema_v15.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index 4328836f..ecfa2298 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -16,9 +16,11 @@ analyzer: - "lib/src/model/protobuf/**" - "lib/src/model/protobuf/api/websocket/**" - "lib/generated/**" + - "lib/core/**" + - "lib/src/localization/**" - "dependencies/**" - "pubspec.yaml" - - "*.arb" + - "**.arb" - "test/drift/**" - "**.g.dart" diff --git a/integration_test/api_service.test.dart b/integration_test/api_service.test.dart index 91f780ed..58c3cfde 100644 --- a/integration_test/api_service.test.dart +++ b/integration_test/api_service.test.dart @@ -1,12 +1,31 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:twonly/core/frb_generated.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/services/background/callback_dispatcher.background.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); setUpAll(() async => RustLib.init()); - // testWidgets('Can call rust function', (tester) async { - // await tester.pumpWidget(const MyApp()); - // expect(find.textContaining('Result: `Hello, Tom!`'), findsOneWidget); - // }); + + test('Can initialize twonlyDB and connect to api server', () async { + // Initialize global variables + await initBackgroundExecution(); + + // Try to connect to the API server + final connected = await apiService.connect(); + + // Print out the result or test it + expect(connected, isA()); + + // We can also check if it's connected + // Depending on your test environment, this might be true or false + // if the server is unreachable without further setup + // expect(apiService.isConnected, isA()); + + // Close the connection after the test + if (apiService.isConnected) { + await apiService.close(() {}); + } + }); } diff --git a/lib/src/callbacks/user_discovery.callbacks.dart b/lib/src/callbacks/user_discovery.callbacks.dart index 73af1d1c..bab169d2 100644 --- a/lib/src/callbacks/user_discovery.callbacks.dart +++ b/lib/src/callbacks/user_discovery.callbacks.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:drift/drift.dart'; import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart' show Curve, IdentityKey; @@ -45,7 +46,7 @@ class UserDiscoveryCallbacks { ) async { final storedPublicKey = await getPublicKeyFromContact(contactId); if (storedPublicKey != null) { - return storedPublicKey == pubKey; + return storedPublicKey.equals(pubKey); } else { return false; } diff --git a/lib/src/database/daos/contacts.dao.dart b/lib/src/database/daos/contacts.dao.dart index 272b8ce4..2a37990e 100644 --- a/lib/src/database/daos/contacts.dao.dart +++ b/lib/src/database/daos/contacts.dao.dart @@ -138,6 +138,7 @@ class ContactsDao extends DatabaseAccessor with _$ContactsDaoMixin { return (select(contacts)..where( (t) => t.userDiscoveryVersion.isNotNull() & + t.userDiscoveryExcluded.equals(false) & t.mediaSendCounter.isBiggerOrEqualValue( gUser.minimumRequiredImagesExchanged, ), diff --git a/lib/src/database/daos/groups.dao.dart b/lib/src/database/daos/groups.dao.dart index 144e21cb..7f408d2d 100644 --- a/lib/src/database/daos/groups.dao.dart +++ b/lib/src/database/daos/groups.dao.dart @@ -311,4 +311,19 @@ class GroupsDao extends DatabaseAccessor with _$GroupsDaoMixin { )) .write(GroupsCompanion(lastMessageExchange: Value(newLastMessage))); } + + Stream> watchNonDirectGroupsForMember(int contactId) { + final query = + select(groups).join([ + innerJoin( + groupMembers, + groupMembers.groupId.equalsExp(groups.groupId), + ), + ])..where( + groups.isDirectChat.equals(false) & + groupMembers.contactId.equals(contactId), + ); + + return query.map((row) => row.readTable(groups)).watch(); + } } diff --git a/lib/src/database/daos/user_discovery.dao.dart b/lib/src/database/daos/user_discovery.dao.dart index 2710663c..b602dc80 100644 --- a/lib/src/database/daos/user_discovery.dao.dart +++ b/lib/src/database/daos/user_discovery.dao.dart @@ -1,15 +1,20 @@ import 'package:drift/drift.dart'; +import 'package:twonly/src/database/tables/contacts.table.dart'; import 'package:twonly/src/database/tables/user_discovery.table.dart'; import 'package:twonly/src/database/twonly.db.dart'; part 'user_discovery.dao.g.dart'; +typedef AnnouncedUsersWithRelations = + Map>; + @DriftAccessor( tables: [ UserDiscoveryAnnouncedUsers, UserDiscoveryUserRelations, UserDiscoveryOwnPromotions, UserDiscoveryShares, + Contacts, ], ) class UserDiscoveryDao extends DatabaseAccessor @@ -46,8 +51,7 @@ class UserDiscoveryDao extends DatabaseAccessor .toList(); } - Future>> - getAnnouncedUsersWithRelations() async { + Stream watchAllAnnouncedUsersWithRelations() { final query = select(userDiscoveryAnnouncedUsers).join([ innerJoin( userDiscoveryUserRelations, @@ -55,28 +59,89 @@ class UserDiscoveryDao extends DatabaseAccessor userDiscoveryAnnouncedUsers.announcedUserId, ), ), - ]); + innerJoin( + contacts, + contacts.userId.equalsExp( + userDiscoveryUserRelations.fromContactId, + ), + ), + ])..where(userDiscoveryAnnouncedUsers.username.isNotNull()); - final rows = await query.get(); + return query.watch().map((rows) { + // ignore: omit_local_variable_types + final AnnouncedUsersWithRelations results = {}; - final results = >{}; + for (final row in rows) { + final user = row.readTable(userDiscoveryAnnouncedUsers); + final relation = row.readTable(userDiscoveryUserRelations); + final contact = row.readTable(contacts); - for (final row in rows) { - final user = row.readTable(userDiscoveryAnnouncedUsers); - final relation = row.readTable(userDiscoveryUserRelations); + final relationData = ( + contact, + relation.publicKeyVerifiedTimestamp, + ); - final relationData = ( - relation.fromContactId, - relation.publicKeyVerifiedTimestamp, - ); - - if (!results.containsKey(user)) { - results[user] = []; + if (!results.containsKey(user)) { + results[user] = []; + } + results[user]!.add(relationData); } - results[user]!.add(relationData); - } - return results; + return results; + }); + } + + Stream watchNewAnnouncedUsersWithRelations() { + final announcedContact = alias(contacts, 'announcedContact'); + final query = + select(userDiscoveryAnnouncedUsers).join([ + innerJoin( + userDiscoveryUserRelations, + userDiscoveryUserRelations.announcedUserId.equalsExp( + userDiscoveryAnnouncedUsers.announcedUserId, + ), + ), + innerJoin( + contacts, + contacts.userId.equalsExp( + userDiscoveryUserRelations.fromContactId, + ), + ), + leftOuterJoin( + announcedContact, + announcedContact.userId.equalsExp( + userDiscoveryAnnouncedUsers.announcedUserId, + ), + ), + ])..where( + userDiscoveryAnnouncedUsers.username.isNotNull() & + userDiscoveryAnnouncedUsers.isHidden.equals(false) & + (announcedContact.userId.isNull() | + announcedContact.deletedByUser.equals(true)), + ); + + return query.watch().map((rows) { + // ignore: omit_local_variable_types + final AnnouncedUsersWithRelations results = {}; + + for (final row in rows) { + final user = row.readTable(userDiscoveryAnnouncedUsers); + final relation = row.readTable(userDiscoveryUserRelations); + final contact = row.readTable(contacts); + + final relationData = ( + contact, + relation.publicKeyVerifiedTimestamp, + ); + + if (!results.containsKey(user)) { + results[user] = []; + } + results[user]!.add(relationData); + } + + return results; + }); } Stream watchNewAnnouncementsWithDataCount() { @@ -94,6 +159,20 @@ class UserDiscoveryDao extends DatabaseAccessor return query.watchSingle().map((row) => row.read(countExp) ?? 0); } + Future markAllValidAnnouncedUsersAsShown() async { + await (update(userDiscoveryAnnouncedUsers)..where( + (t) => + t.username.isNotNull() & + t.wasShownToTheUser.equals(false) & + t.isHidden.equals(false), + )) + .write( + const UserDiscoveryAnnouncedUsersCompanion( + wasShownToTheUser: Value(true), + ), + ); + } + Future updateAnnouncedUser( int announcedUserId, UserDiscoveryAnnouncedUsersCompanion updatedValues, diff --git a/lib/src/database/schemas/twonly_db/drift_schema_v15.json b/lib/src/database/schemas/twonly_db/drift_schema_v15.json new file mode 100644 index 00000000..d83a2a44 --- /dev/null +++ b/lib/src/database/schemas/twonly_db/drift_schema_v15.json @@ -0,0 +1,2727 @@ +{ + "_meta": { + "description": "This file contains a serialized version of schema entities for drift.", + "version": "1.3.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, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "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_compressed", + "getter_name": "avatarSvgCompressed", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_profile_counter", + "getter_name": "senderProfileCounter", + "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": "deleted_by_user", + "getter_name": "deletedByUser", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"deleted_by_user\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"deleted_by_user\" 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": "account_deleted", + "getter_name": "accountDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"account_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"account_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "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": "user_discovery_version", + "getter_name": "userDiscoveryVersion", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "user_discovery_excluded", + "getter_name": "userDiscoveryExcluded", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"user_discovery_excluded\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"user_discovery_excluded\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "media_send_counter", + "getter_name": "mediaSendCounter", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "media_received_counter", + "getter_name": "mediaReceivedCounter", + "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": [], + "type": "table", + "data": { + "name": "groups", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_group_admin", + "getter_name": "isGroupAdmin", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_group_admin\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_group_admin\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_direct_chat", + "getter_name": "isDirectChat", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_direct_chat\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_direct_chat\" 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": "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": "joined_group", + "getter_name": "joinedGroup", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"joined_group\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"joined_group\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "left_group", + "getter_name": "leftGroup", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"left_group\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"left_group\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "deleted_content", + "getter_name": "deletedContent", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"deleted_content\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"deleted_content\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "state_version_id", + "getter_name": "stateVersionId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "state_encryption_key", + "getter_name": "stateEncryptionKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "my_group_private_key", + "getter_name": "myGroupPrivateKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "group_name", + "getter_name": "groupName", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "draft_message", + "getter_name": "draftMessage", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "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": "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_milliseconds", + "getter_name": "deleteMessagesAfterMilliseconds", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('86400000')", + "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": "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": "flame_counter", + "getter_name": "flameCounter", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "max_flame_counter", + "getter_name": "maxFlameCounter", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "max_flame_counter_from", + "getter_name": "maxFlameCounterFrom", + "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": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "group_id" + ] + } + }, + { + "id": 2, + "references": [], + "type": "table", + "data": { + "name": "media_files", + "was_declared_in_moor": false, + "columns": [ + { + "name": "media_id", + "getter_name": "mediaId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MediaType.values)", + "dart_type_name": "MediaType" + } + }, + { + "name": "upload_state", + "getter_name": "uploadState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(UploadState.values)", + "dart_type_name": "UploadState" + } + }, + { + "name": "download_state", + "getter_name": "downloadState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(DownloadState.values)", + "dart_type_name": "DownloadState" + } + }, + { + "name": "requires_authentication", + "getter_name": "requiresAuthentication", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"requires_authentication\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"requires_authentication\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "stored", + "getter_name": "stored", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"stored\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"stored\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_draft_media", + "getter_name": "isDraftMedia", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_draft_media\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_draft_media\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pre_progressing_process", + "getter_name": "preProgressingProcess", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "reupload_requested_by", + "getter_name": "reuploadRequestedBy", + "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": "display_limit_in_milliseconds", + "getter_name": "displayLimitInMilliseconds", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "remove_audio", + "getter_name": "removeAudio", + "moor_type": "bool", + "nullable": true, + "customConstraints": null, + "defaultConstraints": "CHECK (\"remove_audio\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"remove_audio\" IN (0, 1))" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "download_token", + "getter_name": "downloadToken", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_key", + "getter_name": "encryptionKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_mac", + "getter_name": "encryptionMac", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "encryption_nonce", + "getter_name": "encryptionNonce", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "stored_file_hash", + "getter_name": "storedFileHash", + "moor_type": "blob", + "nullable": true, + "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": [ + "media_id" + ] + } + }, + { + "id": 3, + "references": [ + 1, + 0, + 2 + ], + "type": "table", + "data": { + "name": "messages", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_id", + "getter_name": "senderId", + "moor_type": "int", + "nullable": true, + "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "content", + "getter_name": "content", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "media_id", + "getter_name": "mediaId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "defaultConstraints": "REFERENCES media_files (media_id) ON DELETE SET NULL", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES media_files (media_id) ON DELETE SET NULL" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "media_files", + "column": "media_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "setNull" + } + } + ] + }, + { + "name": "additional_message_data", + "getter_name": "additionalMessageData", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "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": "media_reopened", + "getter_name": "mediaReopened", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"media_reopened\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"media_reopened\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "download_token", + "getter_name": "downloadToken", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quotes_message_id", + "getter_name": "quotesMessageId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted_from_sender", + "getter_name": "isDeletedFromSender", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted_from_sender\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted_from_sender\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "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": "opened_by_all", + "getter_name": "openedByAll", + "moor_type": "dateTime", + "nullable": true, + "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": [] + }, + { + "name": "modified_at", + "getter_name": "modifiedAt", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_user", + "getter_name": "ackByUser", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_server", + "getter_name": "ackByServer", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "message_id" + ] + } + }, + { + "id": 4, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "message_histories", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "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_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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": "content", + "getter_name": "content", + "moor_type": "string", + "nullable": true, + "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": [] + } + }, + { + "id": 5, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "reactions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "emoji", + "getter_name": "emoji", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sender_id", + "getter_name": "senderId", + "moor_type": "int", + "nullable": true, + "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": "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": [ + "message_id", + "sender_id", + "emoji" + ] + } + }, + { + "id": 6, + "references": [ + 1, + 0 + ], + "type": "table", + "data": { + "name": "group_members", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "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": "member_state", + "getter_name": "memberState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MemberState.values)", + "dart_type_name": "MemberState" + } + }, + { + "name": "group_public_key", + "getter_name": "groupPublicKey", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_chat_opened", + "getter_name": "lastChatOpened", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_type_indicator", + "getter_name": "lastTypeIndicator", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_message", + "getter_name": "lastMessage", + "moor_type": "dateTime", + "nullable": true, + "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": [ + "group_id", + "contact_id" + ] + } + }, + { + "id": 7, + "references": [ + 0, + 3 + ], + "type": "table", + "data": { + "name": "receipts", + "was_declared_in_moor": false, + "columns": [ + { + "name": "receipt_id", + "getter_name": "receiptId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "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": "string", + "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": "message", + "getter_name": "message", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "contact_will_sends_receipt", + "getter_name": "contactWillSendsReceipt", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"contact_will_sends_receipt\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"contact_will_sends_receipt\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "will_be_retried_by_media_upload", + "getter_name": "willBeRetriedByMediaUpload", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"will_be_retried_by_media_upload\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"will_be_retried_by_media_upload\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mark_for_retry", + "getter_name": "markForRetry", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mark_for_retry_after_accepted", + "getter_name": "markForRetryAfterAccepted", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "ack_by_server_at", + "getter_name": "ackByServerAt", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "retry_count", + "getter_name": "retryCount", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_retry", + "getter_name": "lastRetry", + "moor_type": "dateTime", + "nullable": true, + "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": [ + "receipt_id" + ] + } + }, + { + "id": 8, + "references": [], + "type": "table", + "data": { + "name": "received_receipts", + "was_declared_in_moor": false, + "columns": [ + { + "name": "receipt_id", + "getter_name": "receiptId", + "moor_type": "string", + "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": [ + "receipt_id" + ] + } + }, + { + "id": 9, + "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": 10, + "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": 11, + "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": 12, + "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": 13, + "references": [ + 3, + 0 + ], + "type": "table", + "data": { + "name": "message_actions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "message_id", + "getter_name": "messageId", + "moor_type": "string", + "nullable": false, + "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": "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MessageActionType.values)", + "dart_type_name": "MessageActionType" + } + }, + { + "name": "action_at", + "getter_name": "actionAt", + "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": [ + "message_id", + "contact_id", + "type" + ] + } + }, + { + "id": 14, + "references": [ + 1, + 0 + ], + "type": "table", + "data": { + "name": "group_histories", + "was_declared_in_moor": false, + "columns": [ + { + "name": "group_history_id", + "getter_name": "groupHistoryId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "group_id", + "getter_name": "groupId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES \"groups\" (group_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "groups", + "column": "group_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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": "affected_contact_id", + "getter_name": "affectedContactId", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "old_group_name", + "getter_name": "oldGroupName", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "new_group_name", + "getter_name": "newGroupName", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "new_delete_messages_after_milliseconds", + "getter_name": "newDeleteMessagesAfterMilliseconds", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(GroupActionType.values)", + "dart_type_name": "GroupActionType" + } + }, + { + "name": "action_at", + "getter_name": "actionAt", + "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": [ + "group_history_id" + ] + } + }, + { + "id": 15, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "key_verifications", + "was_declared_in_moor": false, + "columns": [ + { + "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": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(VerificationType.values)", + "dart_type_name": "VerificationType" + } + }, + { + "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": 16, + "references": [], + "type": "table", + "data": { + "name": "verification_tokens", + "was_declared_in_moor": false, + "columns": [ + { + "name": "token_id", + "getter_name": "tokenId", + "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": "token", + "getter_name": "token", + "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": [] + } + }, + { + "id": 17, + "references": [], + "type": "table", + "data": { + "name": "user_discovery_announced_users", + "was_declared_in_moor": false, + "columns": [ + { + "name": "announced_user_id", + "getter_name": "announcedUserId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "announced_public_key", + "getter_name": "announcedPublicKey", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_id", + "getter_name": "publicId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "UNIQUE", + "dialectAwareDefaultConstraints": { + "sqlite": "UNIQUE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + "unique" + ] + }, + { + "name": "username", + "getter_name": "username", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "was_shown_to_the_user", + "getter_name": "wasShownToTheUser", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"was_shown_to_the_user\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"was_shown_to_the_user\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_hidden", + "getter_name": "isHidden", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_hidden\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_hidden\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "announced_user_id" + ] + } + }, + { + "id": 18, + "references": [ + 17, + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_user_relations", + "was_declared_in_moor": false, + "columns": [ + { + "name": "announced_user_id", + "getter_name": "announcedUserId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE", + "dialectAwareDefaultConstraints": { + "sqlite": "REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE" + }, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [ + { + "foreign_key": { + "to": { + "table": "user_discovery_announced_users", + "column": "announced_user_id" + }, + "initially_deferred": false, + "on_update": null, + "on_delete": "cascade" + } + } + ] + }, + { + "name": "from_contact_id", + "getter_name": "fromContactId", + "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": "public_key_verified_timestamp", + "getter_name": "publicKeyVerifiedTimestamp", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "announced_user_id", + "from_contact_id" + ] + } + }, + { + "id": 19, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_other_promotions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "from_contact_id", + "getter_name": "fromContactId", + "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": "promotion_id", + "getter_name": "promotionId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_id", + "getter_name": "publicId", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "threshold", + "getter_name": "threshold", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "announcement_share", + "getter_name": "announcementShare", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_key_verified_timestamp", + "getter_name": "publicKeyVerifiedTimestamp", + "moor_type": "dateTime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "from_contact_id", + "promotion_id" + ] + } + }, + { + "id": 20, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_own_promotions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "version_id", + "getter_name": "versionId", + "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": "promotion", + "getter_name": "promotion", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [] + } + }, + { + "id": 21, + "references": [ + 0 + ], + "type": "table", + "data": { + "name": "user_discovery_shares", + "was_declared_in_moor": false, + "columns": [ + { + "name": "share_id", + "getter_name": "shareId", + "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": "share", + "getter_name": "share", + "moor_type": "blob", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "contact_id", + "getter_name": "contactId", + "moor_type": "int", + "nullable": true, + "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" + } + } + ] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [] + } + } + ], + "fixed_sql": [ + { + "name": "contacts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"contacts\" (\"user_id\" INTEGER NOT NULL, \"username\" TEXT NOT NULL, \"display_name\" TEXT NULL, \"nick_name\" TEXT NULL, \"avatar_svg_compressed\" BLOB NULL, \"sender_profile_counter\" INTEGER NOT NULL DEFAULT 0, \"accepted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"accepted\" IN (0, 1)), \"deleted_by_user\" INTEGER NOT NULL DEFAULT 0 CHECK (\"deleted_by_user\" IN (0, 1)), \"requested\" INTEGER NOT NULL DEFAULT 0 CHECK (\"requested\" IN (0, 1)), \"blocked\" INTEGER NOT NULL DEFAULT 0 CHECK (\"blocked\" IN (0, 1)), \"verified\" INTEGER NOT NULL DEFAULT 0 CHECK (\"verified\" IN (0, 1)), \"account_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"account_deleted\" IN (0, 1)), \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"user_discovery_version\" BLOB NULL, \"user_discovery_excluded\" INTEGER NOT NULL DEFAULT 0 CHECK (\"user_discovery_excluded\" IN (0, 1)), \"media_send_counter\" INTEGER NOT NULL DEFAULT 0, \"media_received_counter\" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (\"user_id\"));" + } + ] + }, + { + "name": "groups", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"groups\" (\"group_id\" TEXT NOT NULL, \"is_group_admin\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_group_admin\" IN (0, 1)), \"is_direct_chat\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_direct_chat\" IN (0, 1)), \"pinned\" INTEGER NOT NULL DEFAULT 0 CHECK (\"pinned\" IN (0, 1)), \"archived\" INTEGER NOT NULL DEFAULT 0 CHECK (\"archived\" IN (0, 1)), \"joined_group\" INTEGER NOT NULL DEFAULT 0 CHECK (\"joined_group\" IN (0, 1)), \"left_group\" INTEGER NOT NULL DEFAULT 0 CHECK (\"left_group\" IN (0, 1)), \"deleted_content\" INTEGER NOT NULL DEFAULT 0 CHECK (\"deleted_content\" IN (0, 1)), \"state_version_id\" INTEGER NOT NULL DEFAULT 0, \"state_encryption_key\" BLOB NULL, \"my_group_private_key\" BLOB NULL, \"group_name\" TEXT NOT NULL, \"draft_message\" TEXT NULL, \"total_media_counter\" INTEGER NOT NULL DEFAULT 0, \"also_best_friend\" INTEGER NOT NULL DEFAULT 0 CHECK (\"also_best_friend\" IN (0, 1)), \"delete_messages_after_milliseconds\" INTEGER NOT NULL DEFAULT 86400000, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"last_message_send\" INTEGER NULL, \"last_message_received\" INTEGER NULL, \"last_flame_counter_change\" INTEGER NULL, \"last_flame_sync\" INTEGER NULL, \"flame_counter\" INTEGER NOT NULL DEFAULT 0, \"max_flame_counter\" INTEGER NOT NULL DEFAULT 0, \"max_flame_counter_from\" INTEGER NULL, \"last_message_exchange\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_id\"));" + } + ] + }, + { + "name": "media_files", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"media_files\" (\"media_id\" TEXT NOT NULL, \"type\" TEXT NOT NULL, \"upload_state\" TEXT NULL, \"download_state\" TEXT NULL, \"requires_authentication\" INTEGER NOT NULL DEFAULT 0 CHECK (\"requires_authentication\" IN (0, 1)), \"stored\" INTEGER NOT NULL DEFAULT 0 CHECK (\"stored\" IN (0, 1)), \"is_draft_media\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_draft_media\" IN (0, 1)), \"pre_progressing_process\" INTEGER NULL, \"reupload_requested_by\" TEXT NULL, \"display_limit_in_milliseconds\" INTEGER NULL, \"remove_audio\" INTEGER NULL CHECK (\"remove_audio\" IN (0, 1)), \"download_token\" BLOB NULL, \"encryption_key\" BLOB NULL, \"encryption_mac\" BLOB NULL, \"encryption_nonce\" BLOB NULL, \"stored_file_hash\" BLOB NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"media_id\"));" + } + ] + }, + { + "name": "messages", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"messages\" (\"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"message_id\" TEXT NOT NULL, \"sender_id\" INTEGER NULL REFERENCES contacts (user_id), \"type\" TEXT NOT NULL, \"content\" TEXT NULL, \"media_id\" TEXT NULL REFERENCES media_files (media_id) ON DELETE SET NULL, \"additional_message_data\" BLOB NULL, \"media_stored\" INTEGER NOT NULL DEFAULT 0 CHECK (\"media_stored\" IN (0, 1)), \"media_reopened\" INTEGER NOT NULL DEFAULT 0 CHECK (\"media_reopened\" IN (0, 1)), \"download_token\" BLOB NULL, \"quotes_message_id\" TEXT NULL, \"is_deleted_from_sender\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted_from_sender\" IN (0, 1)), \"opened_at\" INTEGER NULL, \"opened_by_all\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), \"modified_at\" INTEGER NULL, \"ack_by_user\" INTEGER NULL, \"ack_by_server\" INTEGER NULL, PRIMARY KEY (\"message_id\"));" + } + ] + }, + { + "name": "message_histories", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"message_histories\" (\"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"content\" TEXT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)));" + } + ] + }, + { + "name": "reactions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"reactions\" (\"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"emoji\" TEXT NOT NULL, \"sender_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"message_id\", \"sender_id\", \"emoji\"));" + } + ] + }, + { + "name": "group_members", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"group_members\" (\"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id), \"member_state\" TEXT NULL, \"group_public_key\" BLOB NULL, \"last_chat_opened\" INTEGER NULL, \"last_type_indicator\" INTEGER NULL, \"last_message\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_id\", \"contact_id\"));" + } + ] + }, + { + "name": "receipts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"receipts\" (\"receipt_id\" TEXT NOT NULL, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"message_id\" TEXT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"message\" BLOB NOT NULL, \"contact_will_sends_receipt\" INTEGER NOT NULL DEFAULT 1 CHECK (\"contact_will_sends_receipt\" IN (0, 1)), \"will_be_retried_by_media_upload\" INTEGER NOT NULL DEFAULT 0 CHECK (\"will_be_retried_by_media_upload\" IN (0, 1)), \"mark_for_retry\" INTEGER NULL, \"mark_for_retry_after_accepted\" INTEGER NULL, \"ack_by_server_at\" INTEGER NULL, \"retry_count\" INTEGER NOT NULL DEFAULT 0, \"last_retry\" INTEGER NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"receipt_id\"));" + } + ] + }, + { + "name": "received_receipts", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"received_receipts\" (\"receipt_id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"receipt_id\"));" + } + ] + }, + { + "name": "signal_identity_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_identity_key_stores\" (\"device_id\" INTEGER NOT NULL, \"name\" TEXT NOT NULL, \"identity_key\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"device_id\", \"name\"));" + } + ] + }, + { + "name": "signal_pre_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_pre_key_stores\" (\"pre_key_id\" INTEGER NOT NULL, \"pre_key\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"pre_key_id\"));" + } + ] + }, + { + "name": "signal_sender_key_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_sender_key_stores\" (\"sender_key_name\" TEXT NOT NULL, \"sender_key\" BLOB NOT NULL, PRIMARY KEY (\"sender_key_name\"));" + } + ] + }, + { + "name": "signal_session_stores", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"signal_session_stores\" (\"device_id\" INTEGER NOT NULL, \"name\" TEXT NOT NULL, \"session_record\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"device_id\", \"name\"));" + } + ] + }, + { + "name": "message_actions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"message_actions\" (\"message_id\" TEXT NOT NULL REFERENCES messages (message_id) ON DELETE CASCADE, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"type\" TEXT NOT NULL, \"action_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"message_id\", \"contact_id\", \"type\"));" + } + ] + }, + { + "name": "group_histories", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"group_histories\" (\"group_history_id\" TEXT NOT NULL, \"group_id\" TEXT NOT NULL REFERENCES \"groups\" (group_id) ON DELETE CASCADE, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id), \"affected_contact_id\" INTEGER NULL, \"old_group_name\" TEXT NULL, \"new_group_name\" TEXT NULL, \"new_delete_messages_after_milliseconds\" INTEGER NULL, \"type\" TEXT NOT NULL, \"action_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"group_history_id\"));" + } + ] + }, + { + "name": "key_verifications", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"key_verifications\" (\"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"type\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)), PRIMARY KEY (\"contact_id\"));" + } + ] + }, + { + "name": "verification_tokens", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"verification_tokens\" (\"token_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"token\" BLOB NOT NULL, \"created_at\" INTEGER NOT NULL DEFAULT (CAST(strftime('%s', CURRENT_TIMESTAMP) AS INTEGER)));" + } + ] + }, + { + "name": "user_discovery_announced_users", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_announced_users\" (\"announced_user_id\" INTEGER NOT NULL, \"announced_public_key\" BLOB NOT NULL, \"public_id\" INTEGER NOT NULL UNIQUE, \"username\" TEXT NULL, \"was_shown_to_the_user\" INTEGER NOT NULL DEFAULT 0 CHECK (\"was_shown_to_the_user\" IN (0, 1)), \"is_hidden\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_hidden\" IN (0, 1)), PRIMARY KEY (\"announced_user_id\"));" + } + ] + }, + { + "name": "user_discovery_user_relations", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_user_relations\" (\"announced_user_id\" INTEGER NOT NULL REFERENCES user_discovery_announced_users (announced_user_id) ON DELETE CASCADE, \"from_contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"public_key_verified_timestamp\" INTEGER NULL, PRIMARY KEY (\"announced_user_id\", \"from_contact_id\"));" + } + ] + }, + { + "name": "user_discovery_other_promotions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_other_promotions\" (\"from_contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"promotion_id\" INTEGER NOT NULL, \"public_id\" INTEGER NOT NULL, \"threshold\" INTEGER NOT NULL, \"announcement_share\" BLOB NOT NULL, \"public_key_verified_timestamp\" INTEGER NULL, PRIMARY KEY (\"from_contact_id\", \"promotion_id\"));" + } + ] + }, + { + "name": "user_discovery_own_promotions", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_own_promotions\" (\"version_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"contact_id\" INTEGER NOT NULL REFERENCES contacts (user_id) ON DELETE CASCADE, \"promotion\" BLOB NOT NULL);" + } + ] + }, + { + "name": "user_discovery_shares", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"user_discovery_shares\" (\"share_id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"share\" BLOB NOT NULL, \"contact_id\" INTEGER NULL REFERENCES contacts (user_id) ON DELETE CASCADE);" + } + ] + } + ] +} \ No newline at end of file diff --git a/lib/src/database/tables/contacts.table.dart b/lib/src/database/tables/contacts.table.dart index 3d321c45..b510dce8 100644 --- a/lib/src/database/tables/contacts.table.dart +++ b/lib/src/database/tables/contacts.table.dart @@ -26,6 +26,9 @@ class Contacts extends Table { // contact_versions: HashMap>, BlobColumn get userDiscoveryVersion => blob().nullable()(); + BoolColumn get userDiscoveryExcluded => + boolean().withDefault(const Constant(false))(); + IntColumn get mediaSendCounter => integer().withDefault(const Constant(0))(); IntColumn get mediaReceivedCounter => integer().withDefault(const Constant(0))(); diff --git a/lib/src/database/twonly.db.dart b/lib/src/database/twonly.db.dart index 2df1d81d..0637da65 100644 --- a/lib/src/database/twonly.db.dart +++ b/lib/src/database/twonly.db.dart @@ -72,7 +72,7 @@ class TwonlyDB extends _$TwonlyDB { TwonlyDB.forTesting(DatabaseConnection super.connection); @override - int get schemaVersion => 14; + int get schemaVersion => 15; static QueryExecutor _openConnection() { return driftDatabase( @@ -108,7 +108,6 @@ class TwonlyDB extends _$TwonlyDB { }, from3To4: (m, schema) async { await m.alterTable( - // ignore: experimental_member_use TableMigration( schema.groupHistories, columnTransformer: { @@ -141,9 +140,7 @@ class TwonlyDB extends _$TwonlyDB { await m.deleteTable('signal_contact_pre_keys'); await m.deleteTable('signal_contact_signed_pre_keys'); // For message_actions - // ignore: experimental_member_use await m.alterTable(TableMigration(schema.messageHistories)); - // ignore: experimental_member_use await m.alterTable(TableMigration(schema.messageActions)); }, from8To9: (m, schema) async { @@ -205,6 +202,12 @@ class TwonlyDB extends _$TwonlyDB { schema.userDiscoveryAnnouncedUsers.username, ); }, + from14To15: (m, schema) async { + await m.addColumn( + schema.contacts, + schema.contacts.userDiscoveryExcluded, + ); + }, )(m, from, to); }, ); diff --git a/lib/src/database/twonly.db.g.dart b/lib/src/database/twonly.db.g.dart index 57649abd..b96d34b3 100644 --- a/lib/src/database/twonly.db.g.dart +++ b/lib/src/database/twonly.db.g.dart @@ -185,6 +185,21 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { type: DriftSqlType.blob, requiredDuringInsert: false, ); + static const VerificationMeta _userDiscoveryExcludedMeta = + const VerificationMeta('userDiscoveryExcluded'); + @override + late final GeneratedColumn userDiscoveryExcluded = + GeneratedColumn( + 'user_discovery_excluded', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("user_discovery_excluded" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); static const VerificationMeta _mediaSendCounterMeta = const VerificationMeta( 'mediaSendCounter', ); @@ -224,6 +239,7 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { accountDeleted, createdAt, userDiscoveryVersion, + userDiscoveryExcluded, mediaSendCounter, mediaReceivedCounter, ]; @@ -343,6 +359,15 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { ), ); } + if (data.containsKey('user_discovery_excluded')) { + context.handle( + _userDiscoveryExcludedMeta, + userDiscoveryExcluded.isAcceptableOrUnknown( + data['user_discovery_excluded']!, + _userDiscoveryExcludedMeta, + ), + ); + } if (data.containsKey('media_send_counter')) { context.handle( _mediaSendCounterMeta, @@ -426,6 +451,10 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { DriftSqlType.blob, data['${effectivePrefix}user_discovery_version'], ), + userDiscoveryExcluded: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}user_discovery_excluded'], + )!, mediaSendCounter: attachedDatabase.typeMapping.read( DriftSqlType.int, data['${effectivePrefix}media_send_counter'], @@ -458,6 +487,7 @@ class Contact extends DataClass implements Insertable { final bool accountDeleted; final DateTime createdAt; final Uint8List? userDiscoveryVersion; + final bool userDiscoveryExcluded; final int mediaSendCounter; final int mediaReceivedCounter; const Contact({ @@ -475,6 +505,7 @@ class Contact extends DataClass implements Insertable { required this.accountDeleted, required this.createdAt, this.userDiscoveryVersion, + required this.userDiscoveryExcluded, required this.mediaSendCounter, required this.mediaReceivedCounter, }); @@ -503,6 +534,7 @@ class Contact extends DataClass implements Insertable { if (!nullToAbsent || userDiscoveryVersion != null) { map['user_discovery_version'] = Variable(userDiscoveryVersion); } + map['user_discovery_excluded'] = Variable(userDiscoveryExcluded); map['media_send_counter'] = Variable(mediaSendCounter); map['media_received_counter'] = Variable(mediaReceivedCounter); return map; @@ -532,6 +564,7 @@ class Contact extends DataClass implements Insertable { userDiscoveryVersion: userDiscoveryVersion == null && nullToAbsent ? const Value.absent() : Value(userDiscoveryVersion), + userDiscoveryExcluded: Value(userDiscoveryExcluded), mediaSendCounter: Value(mediaSendCounter), mediaReceivedCounter: Value(mediaReceivedCounter), ); @@ -563,6 +596,9 @@ class Contact extends DataClass implements Insertable { userDiscoveryVersion: serializer.fromJson( json['userDiscoveryVersion'], ), + userDiscoveryExcluded: serializer.fromJson( + json['userDiscoveryExcluded'], + ), mediaSendCounter: serializer.fromJson(json['mediaSendCounter']), mediaReceivedCounter: serializer.fromJson( json['mediaReceivedCounter'], @@ -589,6 +625,7 @@ class Contact extends DataClass implements Insertable { 'userDiscoveryVersion': serializer.toJson( userDiscoveryVersion, ), + 'userDiscoveryExcluded': serializer.toJson(userDiscoveryExcluded), 'mediaSendCounter': serializer.toJson(mediaSendCounter), 'mediaReceivedCounter': serializer.toJson(mediaReceivedCounter), }; @@ -609,6 +646,7 @@ class Contact extends DataClass implements Insertable { bool? accountDeleted, DateTime? createdAt, Value userDiscoveryVersion = const Value.absent(), + bool? userDiscoveryExcluded, int? mediaSendCounter, int? mediaReceivedCounter, }) => Contact( @@ -630,6 +668,7 @@ class Contact extends DataClass implements Insertable { userDiscoveryVersion: userDiscoveryVersion.present ? userDiscoveryVersion.value : this.userDiscoveryVersion, + userDiscoveryExcluded: userDiscoveryExcluded ?? this.userDiscoveryExcluded, mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter, mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter, ); @@ -661,6 +700,9 @@ class Contact extends DataClass implements Insertable { userDiscoveryVersion: data.userDiscoveryVersion.present ? data.userDiscoveryVersion.value : this.userDiscoveryVersion, + userDiscoveryExcluded: data.userDiscoveryExcluded.present + ? data.userDiscoveryExcluded.value + : this.userDiscoveryExcluded, mediaSendCounter: data.mediaSendCounter.present ? data.mediaSendCounter.value : this.mediaSendCounter, @@ -687,6 +729,7 @@ class Contact extends DataClass implements Insertable { ..write('accountDeleted: $accountDeleted, ') ..write('createdAt: $createdAt, ') ..write('userDiscoveryVersion: $userDiscoveryVersion, ') + ..write('userDiscoveryExcluded: $userDiscoveryExcluded, ') ..write('mediaSendCounter: $mediaSendCounter, ') ..write('mediaReceivedCounter: $mediaReceivedCounter') ..write(')')) @@ -709,6 +752,7 @@ class Contact extends DataClass implements Insertable { accountDeleted, createdAt, $driftBlobEquality.hash(userDiscoveryVersion), + userDiscoveryExcluded, mediaSendCounter, mediaReceivedCounter, ); @@ -736,6 +780,7 @@ class Contact extends DataClass implements Insertable { other.userDiscoveryVersion, this.userDiscoveryVersion, ) && + other.userDiscoveryExcluded == this.userDiscoveryExcluded && other.mediaSendCounter == this.mediaSendCounter && other.mediaReceivedCounter == this.mediaReceivedCounter); } @@ -755,6 +800,7 @@ class ContactsCompanion extends UpdateCompanion { final Value accountDeleted; final Value createdAt; final Value userDiscoveryVersion; + final Value userDiscoveryExcluded; final Value mediaSendCounter; final Value mediaReceivedCounter; const ContactsCompanion({ @@ -772,6 +818,7 @@ class ContactsCompanion extends UpdateCompanion { this.accountDeleted = const Value.absent(), this.createdAt = const Value.absent(), this.userDiscoveryVersion = const Value.absent(), + this.userDiscoveryExcluded = const Value.absent(), this.mediaSendCounter = const Value.absent(), this.mediaReceivedCounter = const Value.absent(), }); @@ -790,6 +837,7 @@ class ContactsCompanion extends UpdateCompanion { this.accountDeleted = const Value.absent(), this.createdAt = const Value.absent(), this.userDiscoveryVersion = const Value.absent(), + this.userDiscoveryExcluded = const Value.absent(), this.mediaSendCounter = const Value.absent(), this.mediaReceivedCounter = const Value.absent(), }) : username = Value(username); @@ -808,6 +856,7 @@ class ContactsCompanion extends UpdateCompanion { Expression? accountDeleted, Expression? createdAt, Expression? userDiscoveryVersion, + Expression? userDiscoveryExcluded, Expression? mediaSendCounter, Expression? mediaReceivedCounter, }) { @@ -829,6 +878,8 @@ class ContactsCompanion extends UpdateCompanion { if (createdAt != null) 'created_at': createdAt, if (userDiscoveryVersion != null) 'user_discovery_version': userDiscoveryVersion, + if (userDiscoveryExcluded != null) + 'user_discovery_excluded': userDiscoveryExcluded, if (mediaSendCounter != null) 'media_send_counter': mediaSendCounter, if (mediaReceivedCounter != null) 'media_received_counter': mediaReceivedCounter, @@ -850,6 +901,7 @@ class ContactsCompanion extends UpdateCompanion { Value? accountDeleted, Value? createdAt, Value? userDiscoveryVersion, + Value? userDiscoveryExcluded, Value? mediaSendCounter, Value? mediaReceivedCounter, }) { @@ -868,6 +920,8 @@ class ContactsCompanion extends UpdateCompanion { accountDeleted: accountDeleted ?? this.accountDeleted, createdAt: createdAt ?? this.createdAt, userDiscoveryVersion: userDiscoveryVersion ?? this.userDiscoveryVersion, + userDiscoveryExcluded: + userDiscoveryExcluded ?? this.userDiscoveryExcluded, mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter, mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter, ); @@ -922,6 +976,11 @@ class ContactsCompanion extends UpdateCompanion { userDiscoveryVersion.value, ); } + if (userDiscoveryExcluded.present) { + map['user_discovery_excluded'] = Variable( + userDiscoveryExcluded.value, + ); + } if (mediaSendCounter.present) { map['media_send_counter'] = Variable(mediaSendCounter.value); } @@ -948,6 +1007,7 @@ class ContactsCompanion extends UpdateCompanion { ..write('accountDeleted: $accountDeleted, ') ..write('createdAt: $createdAt, ') ..write('userDiscoveryVersion: $userDiscoveryVersion, ') + ..write('userDiscoveryExcluded: $userDiscoveryExcluded, ') ..write('mediaSendCounter: $mediaSendCounter, ') ..write('mediaReceivedCounter: $mediaReceivedCounter') ..write(')')) @@ -11497,6 +11557,7 @@ typedef $$ContactsTableCreateCompanionBuilder = Value accountDeleted, Value createdAt, Value userDiscoveryVersion, + Value userDiscoveryExcluded, Value mediaSendCounter, Value mediaReceivedCounter, }); @@ -11516,6 +11577,7 @@ typedef $$ContactsTableUpdateCompanionBuilder = Value accountDeleted, Value createdAt, Value userDiscoveryVersion, + Value userDiscoveryExcluded, Value mediaSendCounter, Value mediaReceivedCounter, }); @@ -11892,6 +11954,11 @@ class $$ContactsTableFilterComposer builder: (column) => ColumnFilters(column), ); + ColumnFilters get userDiscoveryExcluded => $composableBuilder( + column: $table.userDiscoveryExcluded, + builder: (column) => ColumnFilters(column), + ); + ColumnFilters get mediaSendCounter => $composableBuilder( column: $table.mediaSendCounter, builder: (column) => ColumnFilters(column), @@ -12290,6 +12357,11 @@ class $$ContactsTableOrderingComposer builder: (column) => ColumnOrderings(column), ); + ColumnOrderings get userDiscoveryExcluded => $composableBuilder( + column: $table.userDiscoveryExcluded, + builder: (column) => ColumnOrderings(column), + ); + ColumnOrderings get mediaSendCounter => $composableBuilder( column: $table.mediaSendCounter, builder: (column) => ColumnOrderings(column), @@ -12364,6 +12436,11 @@ class $$ContactsTableAnnotationComposer builder: (column) => column, ); + GeneratedColumn get userDiscoveryExcluded => $composableBuilder( + column: $table.userDiscoveryExcluded, + builder: (column) => column, + ); + GeneratedColumn get mediaSendCounter => $composableBuilder( column: $table.mediaSendCounter, builder: (column) => column, @@ -12743,6 +12820,7 @@ class $$ContactsTableTableManager Value accountDeleted = const Value.absent(), Value createdAt = const Value.absent(), Value userDiscoveryVersion = const Value.absent(), + Value userDiscoveryExcluded = const Value.absent(), Value mediaSendCounter = const Value.absent(), Value mediaReceivedCounter = const Value.absent(), }) => ContactsCompanion( @@ -12760,6 +12838,7 @@ class $$ContactsTableTableManager accountDeleted: accountDeleted, createdAt: createdAt, userDiscoveryVersion: userDiscoveryVersion, + userDiscoveryExcluded: userDiscoveryExcluded, mediaSendCounter: mediaSendCounter, mediaReceivedCounter: mediaReceivedCounter, ), @@ -12779,6 +12858,7 @@ class $$ContactsTableTableManager Value accountDeleted = const Value.absent(), Value createdAt = const Value.absent(), Value userDiscoveryVersion = const Value.absent(), + Value userDiscoveryExcluded = const Value.absent(), Value mediaSendCounter = const Value.absent(), Value mediaReceivedCounter = const Value.absent(), }) => ContactsCompanion.insert( @@ -12796,6 +12876,7 @@ class $$ContactsTableTableManager accountDeleted: accountDeleted, createdAt: createdAt, userDiscoveryVersion: userDiscoveryVersion, + userDiscoveryExcluded: userDiscoveryExcluded, mediaSendCounter: mediaSendCounter, mediaReceivedCounter: mediaReceivedCounter, ), diff --git a/lib/src/database/twonly.db.steps.dart b/lib/src/database/twonly.db.steps.dart index 3cb3366c..2e3cd646 100644 --- a/lib/src/database/twonly.db.steps.dart +++ b/lib/src/database/twonly.db.steps.dart @@ -7380,6 +7380,461 @@ i1.GeneratedColumn _column_232(String aliasedName) => $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_hidden IN (0, 1))', defaultValue: const i1.CustomExpression('0'), ); + +final class Schema15 extends i0.VersionedSchema { + Schema15({required super.database}) : super(version: 15); + @override + late final List entities = [ + contacts, + groups, + mediaFiles, + messages, + messageHistories, + reactions, + groupMembers, + receipts, + receivedReceipts, + signalIdentityKeyStores, + signalPreKeyStores, + signalSenderKeyStores, + signalSessionStores, + messageActions, + groupHistories, + keyVerifications, + verificationTokens, + userDiscoveryAnnouncedUsers, + userDiscoveryUserRelations, + userDiscoveryOtherPromotions, + userDiscoveryOwnPromotions, + userDiscoveryShares, + ]; + late final Shape49 contacts = Shape49( + source: i0.VersionedTable( + entityName: 'contacts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(user_id)'], + columns: [ + _column_106, + _column_107, + _column_108, + _column_109, + _column_110, + _column_111, + _column_112, + _column_113, + _column_114, + _column_115, + _column_116, + _column_117, + _column_118, + _column_211, + _column_233, + _column_228, + _column_229, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape23 groups = Shape23( + source: i0.VersionedTable( + entityName: 'groups', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_id)'], + columns: [ + _column_119, + _column_120, + _column_121, + _column_122, + _column_123, + _column_124, + _column_125, + _column_126, + _column_127, + _column_128, + _column_129, + _column_130, + _column_131, + _column_132, + _column_133, + _column_134, + _column_118, + _column_135, + _column_136, + _column_137, + _column_138, + _column_139, + _column_140, + _column_141, + _column_142, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape36 mediaFiles = Shape36( + source: i0.VersionedTable( + entityName: 'media_files', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(media_id)'], + columns: [ + _column_143, + _column_144, + _column_145, + _column_146, + _column_147, + _column_148, + _column_149, + _column_207, + _column_150, + _column_151, + _column_152, + _column_153, + _column_154, + _column_155, + _column_156, + _column_157, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape25 messages = Shape25( + source: i0.VersionedTable( + entityName: 'messages', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id)'], + columns: [ + _column_158, + _column_159, + _column_160, + _column_144, + _column_161, + _column_162, + _column_163, + _column_164, + _column_165, + _column_153, + _column_166, + _column_167, + _column_168, + _column_169, + _column_118, + _column_170, + _column_171, + _column_172, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape26 messageHistories = Shape26( + source: i0.VersionedTable( + entityName: 'message_histories', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_173, + _column_174, + _column_175, + _column_161, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape27 reactions = Shape27( + source: i0.VersionedTable( + entityName: 'reactions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id, sender_id, emoji)'], + columns: [_column_174, _column_176, _column_177, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape38 groupMembers = Shape38( + source: i0.VersionedTable( + entityName: 'group_members', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_id, contact_id)'], + columns: [ + _column_158, + _column_178, + _column_179, + _column_180, + _column_209, + _column_210, + _column_181, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape37 receipts = Shape37( + source: i0.VersionedTable( + entityName: 'receipts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(receipt_id)'], + columns: [ + _column_182, + _column_183, + _column_184, + _column_185, + _column_186, + _column_208, + _column_187, + _column_188, + _column_189, + _column_190, + _column_191, + _column_118, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape30 receivedReceipts = Shape30( + source: i0.VersionedTable( + entityName: 'received_receipts', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(receipt_id)'], + columns: [_column_182, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape31 signalIdentityKeyStores = Shape31( + source: i0.VersionedTable( + entityName: 'signal_identity_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(device_id, name)'], + columns: [_column_192, _column_193, _column_194, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape32 signalPreKeyStores = Shape32( + source: i0.VersionedTable( + entityName: 'signal_pre_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(pre_key_id)'], + columns: [_column_195, _column_196, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape11 signalSenderKeyStores = Shape11( + source: i0.VersionedTable( + entityName: 'signal_sender_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(sender_key_name)'], + columns: [_column_197, _column_198], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape33 signalSessionStores = Shape33( + source: i0.VersionedTable( + entityName: 'signal_session_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(device_id, name)'], + columns: [_column_192, _column_193, _column_199, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape34 messageActions = Shape34( + source: i0.VersionedTable( + entityName: 'message_actions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(message_id, contact_id, type)'], + columns: [_column_174, _column_183, _column_144, _column_200], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape35 groupHistories = Shape35( + source: i0.VersionedTable( + entityName: 'group_histories', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(group_history_id)'], + columns: [ + _column_201, + _column_158, + _column_202, + _column_203, + _column_204, + _column_205, + _column_206, + _column_144, + _column_200, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape40 keyVerifications = Shape40( + source: i0.VersionedTable( + entityName: 'key_verifications', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(contact_id)'], + columns: [_column_183, _column_144, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape41 verificationTokens = Shape41( + source: i0.VersionedTable( + entityName: 'verification_tokens', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_212, _column_213, _column_118], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape48 userDiscoveryAnnouncedUsers = Shape48( + source: i0.VersionedTable( + entityName: 'user_discovery_announced_users', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(announced_user_id)'], + columns: [ + _column_214, + _column_215, + _column_216, + _column_230, + _column_231, + _column_232, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape43 userDiscoveryUserRelations = Shape43( + source: i0.VersionedTable( + entityName: 'user_discovery_user_relations', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(announced_user_id, from_contact_id)'], + columns: [_column_217, _column_218, _column_219], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape44 userDiscoveryOtherPromotions = Shape44( + source: i0.VersionedTable( + entityName: 'user_discovery_other_promotions', + withoutRowId: false, + isStrict: false, + tableConstraints: ['PRIMARY KEY(from_contact_id, promotion_id)'], + columns: [ + _column_218, + _column_220, + _column_221, + _column_222, + _column_223, + _column_219, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape45 userDiscoveryOwnPromotions = Shape45( + source: i0.VersionedTable( + entityName: 'user_discovery_own_promotions', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_224, _column_183, _column_225], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape46 userDiscoveryShares = Shape46( + source: i0.VersionedTable( + entityName: 'user_discovery_shares', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [_column_226, _column_227, _column_175], + attachedDatabase: database, + ), + alias: null, + ); +} + +class Shape49 extends i0.VersionedTable { + Shape49({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get userId => + columnsByName['user_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get username => + columnsByName['username']! as i1.GeneratedColumn; + i1.GeneratedColumn get displayName => + columnsByName['display_name']! as i1.GeneratedColumn; + i1.GeneratedColumn get nickName => + columnsByName['nick_name']! as i1.GeneratedColumn; + i1.GeneratedColumn get avatarSvgCompressed => + columnsByName['avatar_svg_compressed']! + as i1.GeneratedColumn; + i1.GeneratedColumn get senderProfileCounter => + columnsByName['sender_profile_counter']! as i1.GeneratedColumn; + i1.GeneratedColumn get accepted => + columnsByName['accepted']! as i1.GeneratedColumn; + i1.GeneratedColumn get deletedByUser => + columnsByName['deleted_by_user']! as i1.GeneratedColumn; + i1.GeneratedColumn get requested => + columnsByName['requested']! as i1.GeneratedColumn; + i1.GeneratedColumn get blocked => + columnsByName['blocked']! as i1.GeneratedColumn; + i1.GeneratedColumn get verified => + columnsByName['verified']! as i1.GeneratedColumn; + i1.GeneratedColumn get accountDeleted => + columnsByName['account_deleted']! as i1.GeneratedColumn; + i1.GeneratedColumn get createdAt => + columnsByName['created_at']! as i1.GeneratedColumn; + i1.GeneratedColumn get userDiscoveryVersion => + columnsByName['user_discovery_version']! + as i1.GeneratedColumn; + i1.GeneratedColumn get userDiscoveryExcluded => + columnsByName['user_discovery_excluded']! as i1.GeneratedColumn; + i1.GeneratedColumn get mediaSendCounter => + columnsByName['media_send_counter']! as i1.GeneratedColumn; + i1.GeneratedColumn get mediaReceivedCounter => + columnsByName['media_received_counter']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_233(String aliasedName) => + i1.GeneratedColumn( + 'user_discovery_excluded', + aliasedName, + false, + type: i1.DriftSqlType.int, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (user_discovery_excluded IN (0, 1))', + defaultValue: const i1.CustomExpression('0'), + ); i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema2 schema) from1To2, required Future Function(i1.Migrator m, Schema3 schema) from2To3, @@ -7394,6 +7849,7 @@ i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema12 schema) from11To12, required Future Function(i1.Migrator m, Schema13 schema) from12To13, required Future Function(i1.Migrator m, Schema14 schema) from13To14, + required Future Function(i1.Migrator m, Schema15 schema) from14To15, }) { return (currentVersion, database) async { switch (currentVersion) { @@ -7462,6 +7918,11 @@ i0.MigrationStepWithVersion migrationSteps({ final migrator = i1.Migrator(database, schema); await from13To14(migrator, schema); return 14; + case 14: + final schema = Schema15(database: database); + final migrator = i1.Migrator(database, schema); + await from14To15(migrator, schema); + return 15; default: throw ArgumentError.value('Unknown migration from $currentVersion'); } @@ -7482,6 +7943,7 @@ i1.OnUpgrade stepByStep({ required Future Function(i1.Migrator m, Schema12 schema) from11To12, required Future Function(i1.Migrator m, Schema13 schema) from12To13, required Future Function(i1.Migrator m, Schema14 schema) from13To14, + required Future Function(i1.Migrator m, Schema15 schema) from14To15, }) => i0.VersionedSchema.stepByStepHelper( step: migrationSteps( from1To2: from1To2, @@ -7497,5 +7959,6 @@ i1.OnUpgrade stepByStep({ from11To12: from11To12, from12To13: from12To13, from13To14: from13To14, + from14To15: from14To15, ), ); diff --git a/lib/src/localization/generated/app_localizations.dart b/lib/src/localization/generated/app_localizations.dart index 02d07574..ad0cec1c 100644 --- a/lib/src/localization/generated/app_localizations.dart +++ b/lib/src/localization/generated/app_localizations.dart @@ -397,27 +397,9 @@ abstract class AppLocalizations { /// No description provided for @searchUserNamePending. /// /// In en, this message translates to: - /// **'Pending'** + /// **'Request pending'** String get searchUserNamePending; - /// No description provided for @searchUserNameBlockUserTooltip. - /// - /// In en, this message translates to: - /// **'Block the user without informing.'** - String get searchUserNameBlockUserTooltip; - - /// No description provided for @searchUserNameRejectUserTooltip. - /// - /// In en, this message translates to: - /// **'Reject the request and let the requester know.'** - String get searchUserNameRejectUserTooltip; - - /// No description provided for @searchUserNameArchiveUserTooltip. - /// - /// In en, this message translates to: - /// **'Archive the user. He will appear again as soon as he accepts your request.'** - String get searchUserNameArchiveUserTooltip; - /// No description provided for @searchUsernameNotFound. /// /// In en, this message translates to: @@ -433,7 +415,7 @@ abstract class AppLocalizations { /// No description provided for @searchUsernameNewFollowerTitle. /// /// In en, this message translates to: - /// **'Follow requests'** + /// **'Open requests'** String get searchUsernameNewFollowerTitle; /// No description provided for @searchUsernameQrCodeBtn. @@ -3147,6 +3129,198 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Scan / Show QR'** String get scanQrOrShow; + + /// No description provided for @contactActionBlock. + /// + /// In en, this message translates to: + /// **'Block'** + String get contactActionBlock; + + /// No description provided for @contactActionAccept. + /// + /// In en, this message translates to: + /// **'Accept'** + String get contactActionAccept; + + /// No description provided for @userDiscoverySettingsMinImages. + /// + /// In en, this message translates to: + /// **'Choose the minimum number of images you must have exchanged with a person before you securely share your friends with them.'** + String get userDiscoverySettingsMinImages; + + /// No description provided for @userDiscoverySettingsMutualFriends. + /// + /// In en, this message translates to: + /// **'Choose how many mutual friends a person must have for you to be suggested to them.'** + String get userDiscoverySettingsMutualFriends; + + /// No description provided for @userDiscoverySettingsApply. + /// + /// In en, this message translates to: + /// **'Apply changes'** + String get userDiscoverySettingsApply; + + /// No description provided for @userDiscoveryEnabledDisableWarning. + /// + /// In en, this message translates to: + /// **'If you disable the \"Find friends\" feature, you will no longer see suggestions. You will also stop sharing your friends with new contacts.'** + String get userDiscoveryEnabledDisableWarning; + + /// No description provided for @userDiscoveryEnabledChangeSettings. + /// + /// In en, this message translates to: + /// **'Change settings'** + String get userDiscoveryEnabledChangeSettings; + + /// No description provided for @userDiscoveryEnabledFaq. + /// + /// In en, this message translates to: + /// **'In our FAQ we explain how the \"Find friends\" feature works.'** + String get userDiscoveryEnabledFaq; + + /// No description provided for @userDiscoveryDisabledIntro. + /// + /// In en, this message translates to: + /// **'twonly doesn\'t use phone numbers, so we suggest friends based on mutual contacts instead – securely and privately.'** + String get userDiscoveryDisabledIntro; + + /// No description provided for @userDiscoveryDisabledInvisible. + /// + /// In en, this message translates to: + /// **'Your friend list is *completely invisible to strangers*. Only your friends can see parts of it – and only those people with whom they have *mutual friends* themselves.'** + String get userDiscoveryDisabledInvisible; + + /// No description provided for @userDiscoveryDisabledDecide. + /// + /// In en, this message translates to: + /// **'Decide for yourself who can see your friends. You can change your mind at any time or hide specific people.'** + String get userDiscoveryDisabledDecide; + + /// No description provided for @userDiscoverySettingsTitle. + /// + /// In en, this message translates to: + /// **'Find friends'** + String get userDiscoverySettingsTitle; + + /// No description provided for @userDiscoverySettingsMinImagesTitle. + /// + /// In en, this message translates to: + /// **'Number of shared images'** + String get userDiscoverySettingsMinImagesTitle; + + /// No description provided for @userDiscoverySettingsMutualFriendsTitle. + /// + /// In en, this message translates to: + /// **'Number of mutual friends'** + String get userDiscoverySettingsMutualFriendsTitle; + + /// No description provided for @userDiscoveryDisabledYouHaveControl. + /// + /// In en, this message translates to: + /// **'You are in control'** + String get userDiscoveryDisabledYouHaveControl; + + /// No description provided for @userDiscoveryDisabledEnableWithDefault. + /// + /// In en, this message translates to: + /// **'Enable with default settings'** + String get userDiscoveryDisabledEnableWithDefault; + + /// No description provided for @userDiscoveryDisabledCustomizeSettings. + /// + /// In en, this message translates to: + /// **'Customize settings'** + String get userDiscoveryDisabledCustomizeSettings; + + /// No description provided for @userDiscoveryDisabledLearnMore. + /// + /// In en, this message translates to: + /// **'Learn more'** + String get userDiscoveryDisabledLearnMore; + + /// No description provided for @userDiscoveryEnabledDialogTitle. + /// + /// In en, this message translates to: + /// **'Really disable?'** + String get userDiscoveryEnabledDialogTitle; + + /// No description provided for @userDiscoveryEnabledFriendsShared. + /// + /// In en, this message translates to: + /// **'Friends you share'** + String get userDiscoveryEnabledFriendsShared; + + /// No description provided for @userDiscoveryEnabledFriendsSharedDesc. + /// + /// In en, this message translates to: + /// **'You only share friends who have also activated this feature and who have reached the threshold you set.'** + String get userDiscoveryEnabledFriendsSharedDesc; + + /// No description provided for @userDiscoveryEnabledNoFriendsShared. + /// + /// In en, this message translates to: + /// **'You are not sharing anyone yet.'** + String get userDiscoveryEnabledNoFriendsShared; + + /// No description provided for @userDiscoveryActionDisable. + /// + /// In en, this message translates to: + /// **'Disable'** + String get userDiscoveryActionDisable; + + /// No description provided for @friendSuggestionsTitle. + /// + /// In en, this message translates to: + /// **'Friend suggestions'** + String get friendSuggestionsTitle; + + /// No description provided for @andWord. + /// + /// In en, this message translates to: + /// **'and'** + String get andWord; + + /// No description provided for @friendSuggestionsFriendsWith. + /// + /// In en, this message translates to: + /// **'Friends with {friends}.'** + String friendSuggestionsFriendsWith(Object friends); + + /// No description provided for @friendSuggestionsGroupMemberIn. + /// + /// In en, this message translates to: + /// **' Group member in {groups}.'** + String friendSuggestionsGroupMemberIn(Object groups); + + /// No description provided for @friendSuggestionsRequest. + /// + /// In en, this message translates to: + /// **'Request'** + String get friendSuggestionsRequest; + + /// No description provided for @contactUserDiscoveryImagesLeft. + /// + /// In en, this message translates to: + /// **'{imagesLeft} more images are needed until your friends are shared with {username}.'** + String contactUserDiscoveryImagesLeft(Object imagesLeft, Object username); + + /// No description provided for @userDiscoveryEnabledVersion. + /// + /// In en, this message translates to: + /// **'Version: {version}'** + String userDiscoveryEnabledVersion(Object version); + + /// No description provided for @userDiscoveryEnabledYourVersion. + /// + /// In en, this message translates to: + /// **'Your version: {version}'** + String userDiscoveryEnabledYourVersion(Object version); + + /// No description provided for @userDiscoveryEnabledStopSharing. + /// + /// In en, this message translates to: + /// **'Stop sharing'** + String get userDiscoveryEnabledStopSharing; } class _AppLocalizationsDelegate diff --git a/lib/src/localization/generated/app_localizations_de.dart b/lib/src/localization/generated/app_localizations_de.dart index 4760d924..4e5ccf13 100644 --- a/lib/src/localization/generated/app_localizations_de.dart +++ b/lib/src/localization/generated/app_localizations_de.dart @@ -172,19 +172,7 @@ class AppLocalizationsDe extends AppLocalizations { String get selectSubscription => 'Abo auswählen'; @override - String get searchUserNamePending => 'Ausstehend'; - - @override - String get searchUserNameBlockUserTooltip => - 'Benutzer ohne Benachrichtigung blockieren.'; - - @override - String get searchUserNameRejectUserTooltip => - 'Die Anfrage ablehnen und den Anfragenden informieren.'; - - @override - String get searchUserNameArchiveUserTooltip => - 'Benutzer archivieren. Du wirst informiert sobald er deine Anfrage akzeptiert.'; + String get searchUserNamePending => 'Anfrage ausstehend'; @override String get searchUsernameNotFound => 'Benutzername nicht gefunden'; @@ -195,7 +183,7 @@ class AppLocalizationsDe extends AppLocalizations { } @override - String get searchUsernameNewFollowerTitle => 'Folgeanfragen'; + String get searchUsernameNewFollowerTitle => 'Offene Anfragen'; @override String get searchUsernameQrCodeBtn => 'QR-Code scannen'; @@ -1764,4 +1752,122 @@ class AppLocalizationsDe extends AppLocalizations { @override String get scanQrOrShow => 'QR scannen / anzeigen'; + + @override + String get contactActionBlock => 'Blockieren'; + + @override + String get contactActionAccept => 'Annehmen'; + + @override + String get userDiscoverySettingsMinImages => + 'Wähle die Mindestanzahl an Bildern, die du mit einer Person ausgetauscht haben musst, bevor du ihr deine Freunde sicher teilst.'; + + @override + String get userDiscoverySettingsMutualFriends => + 'Wähle aus, wie viele gemeinsame Freunde eine Person haben muss, damit du ihr vorgeschlagen wirst.'; + + @override + String get userDiscoverySettingsApply => 'Änderungen übernehmen'; + + @override + String get userDiscoveryEnabledDisableWarning => + 'Wenn du das Feature „Freunde finden“ deaktivierst, werden dir keine Vorschläge mehr angezeigt. Du teilst neuen Kontakten dann auch nicht mehr deine Freunde.'; + + @override + String get userDiscoveryEnabledChangeSettings => 'Einstellungen ändern'; + + @override + String get userDiscoveryEnabledFaq => + 'In unserem FAQ erklären wir dir wie das Feature \"Freunde finden\" funktioniert.'; + + @override + String get userDiscoveryDisabledIntro => + 'twonly verzichten auf Telefonnummern, daher schlagen wir dir Freunde stattdessen über gemeinsame Kontakte vor – sicher und privat.'; + + @override + String get userDiscoveryDisabledInvisible => + 'Deine Freundesliste ist für *Fremde komplett unsichtbar*. Nur deine Freunde können Teile davon sehen – und zwar nur die Personen, mit denen sie selbst *gemeinsame Freunde* haben.'; + + @override + String get userDiscoveryDisabledDecide => + 'Entscheide selbst, wer deine Freunde sehen darf. Du kannst deine Meinung jederzeit ändern oder bestimmte Personen verstecken.'; + + @override + String get userDiscoverySettingsTitle => 'Freunde finden'; + + @override + String get userDiscoverySettingsMinImagesTitle => + 'Anzahl an geteilten Bildern'; + + @override + String get userDiscoverySettingsMutualFriendsTitle => + 'Anzahl an gemeinsame Freunde'; + + @override + String get userDiscoveryDisabledYouHaveControl => 'Du hast die Kontrolle'; + + @override + String get userDiscoveryDisabledEnableWithDefault => + 'Mit Standardeinstellungen aktivieren'; + + @override + String get userDiscoveryDisabledCustomizeSettings => 'Einstellungen anpassen'; + + @override + String get userDiscoveryDisabledLearnMore => 'Mehr erfahren'; + + @override + String get userDiscoveryEnabledDialogTitle => 'Wirklich deaktivieren?'; + + @override + String get userDiscoveryEnabledFriendsShared => 'Freunde die du teilst'; + + @override + String get userDiscoveryEnabledFriendsSharedDesc => + 'Du teilst nur Freunde, die diese Funktion ebenfalls aktiviert haben und die den von dir festgelegten Schwellenwert erreicht haben.'; + + @override + String get userDiscoveryEnabledNoFriendsShared => + 'Bisher teilst du noch niemanden.'; + + @override + String get userDiscoveryActionDisable => 'Deaktivieren'; + + @override + String get friendSuggestionsTitle => 'Freundschaftsvorschläge'; + + @override + String get andWord => 'und'; + + @override + String friendSuggestionsFriendsWith(Object friends) { + return 'Befreundet mit $friends.'; + } + + @override + String friendSuggestionsGroupMemberIn(Object groups) { + return ' Gruppenmitglied in $groups.'; + } + + @override + String get friendSuggestionsRequest => 'Anfragen'; + + @override + String contactUserDiscoveryImagesLeft(Object imagesLeft, Object username) { + return 'Es fehlen noch $imagesLeft Bilder bis deine Freunde mit $username geteilt werden.'; + } + + @override + String userDiscoveryEnabledVersion(Object version) { + return 'Version: $version'; + } + + @override + String userDiscoveryEnabledYourVersion(Object version) { + return 'Deine Version: $version'; + } + + @override + String get userDiscoveryEnabledStopSharing => 'Nicht mehr teilen'; } diff --git a/lib/src/localization/generated/app_localizations_en.dart b/lib/src/localization/generated/app_localizations_en.dart index 258e732b..2061b84f 100644 --- a/lib/src/localization/generated/app_localizations_en.dart +++ b/lib/src/localization/generated/app_localizations_en.dart @@ -171,19 +171,7 @@ class AppLocalizationsEn extends AppLocalizations { String get selectSubscription => 'Select subscription'; @override - String get searchUserNamePending => 'Pending'; - - @override - String get searchUserNameBlockUserTooltip => - 'Block the user without informing.'; - - @override - String get searchUserNameRejectUserTooltip => - 'Reject the request and let the requester know.'; - - @override - String get searchUserNameArchiveUserTooltip => - 'Archive the user. He will appear again as soon as he accepts your request.'; + String get searchUserNamePending => 'Request pending'; @override String get searchUsernameNotFound => 'Username not found'; @@ -194,7 +182,7 @@ class AppLocalizationsEn extends AppLocalizations { } @override - String get searchUsernameNewFollowerTitle => 'Follow requests'; + String get searchUsernameNewFollowerTitle => 'Open requests'; @override String get searchUsernameQrCodeBtn => 'Scan QR code'; @@ -1752,4 +1740,121 @@ class AppLocalizationsEn extends AppLocalizations { @override String get scanQrOrShow => 'Scan / Show QR'; + + @override + String get contactActionBlock => 'Block'; + + @override + String get contactActionAccept => 'Accept'; + + @override + String get userDiscoverySettingsMinImages => + 'Choose the minimum number of images you must have exchanged with a person before you securely share your friends with them.'; + + @override + String get userDiscoverySettingsMutualFriends => + 'Choose how many mutual friends a person must have for you to be suggested to them.'; + + @override + String get userDiscoverySettingsApply => 'Apply changes'; + + @override + String get userDiscoveryEnabledDisableWarning => + 'If you disable the \"Find friends\" feature, you will no longer see suggestions. You will also stop sharing your friends with new contacts.'; + + @override + String get userDiscoveryEnabledChangeSettings => 'Change settings'; + + @override + String get userDiscoveryEnabledFaq => + 'In our FAQ we explain how the \"Find friends\" feature works.'; + + @override + String get userDiscoveryDisabledIntro => + 'twonly doesn\'t use phone numbers, so we suggest friends based on mutual contacts instead – securely and privately.'; + + @override + String get userDiscoveryDisabledInvisible => + 'Your friend list is *completely invisible to strangers*. Only your friends can see parts of it – and only those people with whom they have *mutual friends* themselves.'; + + @override + String get userDiscoveryDisabledDecide => + 'Decide for yourself who can see your friends. You can change your mind at any time or hide specific people.'; + + @override + String get userDiscoverySettingsTitle => 'Find friends'; + + @override + String get userDiscoverySettingsMinImagesTitle => 'Number of shared images'; + + @override + String get userDiscoverySettingsMutualFriendsTitle => + 'Number of mutual friends'; + + @override + String get userDiscoveryDisabledYouHaveControl => 'You are in control'; + + @override + String get userDiscoveryDisabledEnableWithDefault => + 'Enable with default settings'; + + @override + String get userDiscoveryDisabledCustomizeSettings => 'Customize settings'; + + @override + String get userDiscoveryDisabledLearnMore => 'Learn more'; + + @override + String get userDiscoveryEnabledDialogTitle => 'Really disable?'; + + @override + String get userDiscoveryEnabledFriendsShared => 'Friends you share'; + + @override + String get userDiscoveryEnabledFriendsSharedDesc => + 'You only share friends who have also activated this feature and who have reached the threshold you set.'; + + @override + String get userDiscoveryEnabledNoFriendsShared => + 'You are not sharing anyone yet.'; + + @override + String get userDiscoveryActionDisable => 'Disable'; + + @override + String get friendSuggestionsTitle => 'Friend suggestions'; + + @override + String get andWord => 'and'; + + @override + String friendSuggestionsFriendsWith(Object friends) { + return 'Friends with $friends.'; + } + + @override + String friendSuggestionsGroupMemberIn(Object groups) { + return ' Group member in $groups.'; + } + + @override + String get friendSuggestionsRequest => 'Request'; + + @override + String contactUserDiscoveryImagesLeft(Object imagesLeft, Object username) { + return '$imagesLeft more images are needed until your friends are shared with $username.'; + } + + @override + String userDiscoveryEnabledVersion(Object version) { + return 'Version: $version'; + } + + @override + String userDiscoveryEnabledYourVersion(Object version) { + return 'Your version: $version'; + } + + @override + String get userDiscoveryEnabledStopSharing => 'Stop sharing'; } diff --git a/lib/src/localization/generated/app_localizations_sv.dart b/lib/src/localization/generated/app_localizations_sv.dart index 8a162e2b..e97f3637 100644 --- a/lib/src/localization/generated/app_localizations_sv.dart +++ b/lib/src/localization/generated/app_localizations_sv.dart @@ -171,19 +171,7 @@ class AppLocalizationsSv extends AppLocalizations { String get selectSubscription => 'Select subscription'; @override - String get searchUserNamePending => 'Pending'; - - @override - String get searchUserNameBlockUserTooltip => - 'Block the user without informing.'; - - @override - String get searchUserNameRejectUserTooltip => - 'Reject the request and let the requester know.'; - - @override - String get searchUserNameArchiveUserTooltip => - 'Archive the user. He will appear again as soon as he accepts your request.'; + String get searchUserNamePending => 'Request pending'; @override String get searchUsernameNotFound => 'Username not found'; @@ -194,7 +182,7 @@ class AppLocalizationsSv extends AppLocalizations { } @override - String get searchUsernameNewFollowerTitle => 'Follow requests'; + String get searchUsernameNewFollowerTitle => 'Open requests'; @override String get searchUsernameQrCodeBtn => 'Scan QR code'; @@ -1752,4 +1740,121 @@ class AppLocalizationsSv extends AppLocalizations { @override String get scanQrOrShow => 'Scan / Show QR'; + + @override + String get contactActionBlock => 'Block'; + + @override + String get contactActionAccept => 'Accept'; + + @override + String get userDiscoverySettingsMinImages => + 'Choose the minimum number of images you must have exchanged with a person before you securely share your friends with them.'; + + @override + String get userDiscoverySettingsMutualFriends => + 'Choose how many mutual friends a person must have for you to be suggested to them.'; + + @override + String get userDiscoverySettingsApply => 'Apply changes'; + + @override + String get userDiscoveryEnabledDisableWarning => + 'If you disable the \"Find friends\" feature, you will no longer see suggestions. You will also stop sharing your friends with new contacts.'; + + @override + String get userDiscoveryEnabledChangeSettings => 'Change settings'; + + @override + String get userDiscoveryEnabledFaq => + 'In our FAQ we explain how the \"Find friends\" feature works.'; + + @override + String get userDiscoveryDisabledIntro => + 'twonly doesn\'t use phone numbers, so we suggest friends based on mutual contacts instead – securely and privately.'; + + @override + String get userDiscoveryDisabledInvisible => + 'Your friend list is *completely invisible to strangers*. Only your friends can see parts of it – and only those people with whom they have *mutual friends* themselves.'; + + @override + String get userDiscoveryDisabledDecide => + 'Decide for yourself who can see your friends. You can change your mind at any time or hide specific people.'; + + @override + String get userDiscoverySettingsTitle => 'Find friends'; + + @override + String get userDiscoverySettingsMinImagesTitle => 'Number of shared images'; + + @override + String get userDiscoverySettingsMutualFriendsTitle => + 'Number of mutual friends'; + + @override + String get userDiscoveryDisabledYouHaveControl => 'You are in control'; + + @override + String get userDiscoveryDisabledEnableWithDefault => + 'Enable with default settings'; + + @override + String get userDiscoveryDisabledCustomizeSettings => 'Customize settings'; + + @override + String get userDiscoveryDisabledLearnMore => 'Learn more'; + + @override + String get userDiscoveryEnabledDialogTitle => 'Really disable?'; + + @override + String get userDiscoveryEnabledFriendsShared => 'Friends you share'; + + @override + String get userDiscoveryEnabledFriendsSharedDesc => + 'You only share friends who have also activated this feature and who have reached the threshold you set.'; + + @override + String get userDiscoveryEnabledNoFriendsShared => + 'You are not sharing anyone yet.'; + + @override + String get userDiscoveryActionDisable => 'Disable'; + + @override + String get friendSuggestionsTitle => 'Friend suggestions'; + + @override + String get andWord => 'and'; + + @override + String friendSuggestionsFriendsWith(Object friends) { + return 'Friends with $friends.'; + } + + @override + String friendSuggestionsGroupMemberIn(Object groups) { + return ' Group member in $groups.'; + } + + @override + String get friendSuggestionsRequest => 'Request'; + + @override + String contactUserDiscoveryImagesLeft(Object imagesLeft, Object username) { + return '$imagesLeft more images are needed until your friends are shared with $username.'; + } + + @override + String userDiscoveryEnabledVersion(Object version) { + return 'Version: $version'; + } + + @override + String userDiscoveryEnabledYourVersion(Object version) { + return 'Your version: $version'; + } + + @override + String get userDiscoveryEnabledStopSharing => 'Stop sharing'; } diff --git a/lib/src/services/api/client2client/contact.c2c.dart b/lib/src/services/api/client2client/contact.c2c.dart index 3f7c0b71..7278bf06 100644 --- a/lib/src/services/api/client2client/contact.c2c.dart +++ b/lib/src/services/api/client2client/contact.c2c.dart @@ -117,15 +117,20 @@ Future handleContactUpdate( case EncryptedContent_ContactUpdate_Type.UPDATE: Log.info('Got a contact update $fromUserId'); - if (contactUpdate.hasAvatarSvgCompressed() && - contactUpdate.hasDisplayName() && + Uint8List? avatarSvgCompressed; + if (contactUpdate.hasAvatarSvgCompressed()) { + avatarSvgCompressed = Uint8List.fromList( + contactUpdate.avatarSvgCompressed, + ); + } + if (contactUpdate.hasDisplayName() && contactUpdate.hasUsername() && senderProfileCounter != null) { await twonlyDB.contactsDao.updateContact( fromUserId, ContactsCompanion( avatarSvgCompressed: Value( - Uint8List.fromList(contactUpdate.avatarSvgCompressed), + avatarSvgCompressed, ), displayName: Value(contactUpdate.displayName), username: Value(contactUpdate.username), @@ -180,6 +185,7 @@ Future checkForProfileUpdate( .getSingleOrNull(); if (contact != null) { if (contact.senderProfileCounter < senderProfileCounter) { + Log.info('${contact.senderProfileCounter} < $senderProfileCounter'); await sendCipherText( fromUserId, EncryptedContent( diff --git a/lib/src/services/api/client2client/user_discovery.c2c.dart b/lib/src/services/api/client2client/user_discovery.c2c.dart index 10f383f7..e61fd465 100644 --- a/lib/src/services/api/client2client/user_discovery.c2c.dart +++ b/lib/src/services/api/client2client/user_discovery.c2c.dart @@ -16,6 +16,7 @@ Future checkForUserDiscoveryChanges( ); if (currentVersion != null) { + Log.info('Having old version from contact. Requesting new version.'); await sendCipherText( fromUserId, EncryptedContent( @@ -31,6 +32,8 @@ Future handleUserDiscoveryRequest( int fromUserId, EncryptedContent_UserDiscoveryRequest request, ) async { + Log.info('Got a user discovery request'); + if (!gUser.isUserDiscoveryEnabled) { Log.warn('Got a user discovery request while it is disabled'); return; @@ -38,9 +41,10 @@ Future handleUserDiscoveryRequest( final contact = await twonlyDB.contactsDao.getContactById(fromUserId); if (contact == null) return; - if (contact.mediaSendCounter < gUser.minimumRequiredImagesExchanged) { + if (contact.mediaSendCounter < gUser.minimumRequiredImagesExchanged || + contact.userDiscoveryExcluded) { Log.warn( - 'Got a request to update user discovery, but mediaSendCounter (${contact.mediaSendCounter}) < ${gUser.minimumRequiredImagesExchanged}', + 'Got a request to update user discovery, but mediaSendCounter (${contact.mediaSendCounter}) < ${gUser.minimumRequiredImagesExchanged} or user is excluded ${contact.userDiscoveryExcluded}', ); return; } @@ -50,6 +54,7 @@ Future handleUserDiscoveryRequest( request.currentVersion, ); if (newMessages != null && newMessages.isNotEmpty) { + Log.info('Sending ${newMessages.length} user discovery messages'); await sendCipherText( fromUserId, EncryptedContent( @@ -71,6 +76,7 @@ Future handleUserDiscoveryUpdate( Log.warn('Got a user discovery update while it is disabled'); return; } + Log.info('Got ${update.messages.length} user discovery messages'); await UserDiscoveryService.handleNewMessages( fromUserId, update.messages.map(Uint8List.fromList).toList(), diff --git a/lib/src/services/api/messages.dart b/lib/src/services/api/messages.dart index 73af6d8a..52129f42 100644 --- a/lib/src/services/api/messages.dart +++ b/lib/src/services/api/messages.dart @@ -347,10 +347,11 @@ Future<(Uint8List, Uint8List?)?> sendCipherText( } encryptedContent.senderProfileCounter = Int64(gUser.avatarCounter); - if (gUser.isUserDiscoveryEnabled) { + if (gUser.isUserDiscoveryEnabled && messageId != null) { final contact = await twonlyDB.contactsDao.getContactById(contactId); if (contact != null && - contact.mediaSendCounter >= gUser.minimumRequiredImagesExchanged) { + contact.mediaSendCounter >= gUser.minimumRequiredImagesExchanged && + !contact.userDiscoveryExcluded) { final version = await UserDiscoveryService.getCurrentVersion(); if (version != null) { encryptedContent.senderUserDiscoveryVersion = version; diff --git a/lib/src/services/api/server_messages.dart b/lib/src/services/api/server_messages.dart index 3db815c3..afd6b17b 100644 --- a/lib/src/services/api/server_messages.dart +++ b/lib/src/services/api/server_messages.dart @@ -355,7 +355,10 @@ Future<(EncryptedContent?, PlaintextContent?)> handleEncryptedMessage( final contact = await twonlyDB.contactsDao .getContactByUserId(fromUserId) .getSingleOrNull(); - if (contact == null || contact.deletedByUser) { + Log.info( + 'Contact exists?: ${contact != null} Is deleted? ${contact?.deletedByUser} Accepted? (${contact?.accepted})', + ); + if (contact == null || !contact.accepted || contact.deletedByUser) { await handleNewContactRequest(fromUserId); Log.error( 'User tries to send message to direct chat while the user does not exists !', diff --git a/lib/src/services/user_discovery.service.dart b/lib/src/services/user_discovery.service.dart index b46248a4..a944db0d 100644 --- a/lib/src/services/user_discovery.service.dart +++ b/lib/src/services/user_discovery.service.dart @@ -1,5 +1,7 @@ import 'dart:convert'; +import 'package:collection/collection.dart'; import 'package:drift/drift.dart'; +import 'package:flutter/foundation.dart'; import 'package:twonly/core/bridge/wrapper/user_discovery.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/database/twonly.db.dart'; @@ -18,8 +20,14 @@ class UserDiscoveryService { announcedUser.announcedUserId, ); if (userdata == null) continue; - if (userdata.publicIdentityKey != - announcedUser.announcedPublicKey.toList()) { + if (!userdata.publicIdentityKey.equals( + announcedUser.announcedPublicKey.toList(), + )) { + if (kDebugMode) { + Log.warn( + '${userdata.publicIdentityKey} != ${announcedUser.announcedPublicKey.toList()}', + ); + } Log.error( 'Server delivered a different public key then received from the announcement.', ); @@ -74,6 +82,21 @@ class UserDiscoveryService { return UserDiscoveryVersion.fromBuffer(version); } + static Future getContactVersionTyped( + int contactId, + ) async { + final contact = await twonlyDB.contactsDao.getContactById(contactId); + if (contact == null || contact.userDiscoveryVersion == null) return null; + return UserDiscoveryVersion.fromBuffer(contact.userDiscoveryVersion!); + } + + static UserDiscoveryVersion? getContactVersionTypedFromContact( + Contact contact, + ) { + if (contact.userDiscoveryVersion == null) return null; + return UserDiscoveryVersion.fromBuffer(contact.userDiscoveryVersion!); + } + static Future shouldRequestNewMessages( int fromUserId, List receivedVersion, diff --git a/lib/src/utils/misc.dart b/lib/src/utils/misc.dart index d36d39ae..2fd324ea 100644 --- a/lib/src/utils/misc.dart +++ b/lib/src/utils/misc.dart @@ -405,13 +405,15 @@ Future> sha256File(File file) async { return sha256Sink.events.single.bytes; } -List formattedText(String input) { - // Pattern to find text between asterisks - final regex = RegExp(r'\*(.*?)\*'); - final List spans = []; +List formattedText(BuildContext context, String input) { + // Access the current theme's text color + // Defaulting to bodyMedium color, but you can use labelLarge, displaySmall, etc. + final defaultColor = Theme.of(context).colorScheme.onSurface; - // Track the current position in the string - int lastMatchEnd = 0; + final regex = RegExp(r'\*(.*?)\*'); + final spans = []; + + var lastMatchEnd = 0; for (final match in regex.allMatches(input)) { // Add text before the match (Normal style) @@ -419,17 +421,18 @@ List formattedText(String input) { spans.add( TextSpan( text: input.substring(lastMatchEnd, match.start), + style: TextStyle(color: defaultColor), ), ); } // Add the matched text (Bold style) - // match.group(1) is the text without the asterisks spans.add( TextSpan( text: match.group(1), - style: const TextStyle( + style: TextStyle( fontWeight: FontWeight.bold, + color: defaultColor, // Ensures bold text also uses the theme color ), ), ); @@ -442,9 +445,16 @@ List formattedText(String input) { spans.add( TextSpan( text: input.substring(lastMatchEnd), + style: TextStyle(color: defaultColor), ), ); } return spans; } + +String joinWithAnd(List items, String andWord) { + if (items.isEmpty) return ''; + if (items.length == 1) return items.first; + return '${items.sublist(0, items.length - 1).join(', ')} $andWord ${items.last}'; +} diff --git a/lib/src/views/chats/add_new_user.view.dart b/lib/src/views/chats/add_new_user.view.dart index 63cc643b..4ce086f8 100644 --- a/lib/src/views/chats/add_new_user.view.dart +++ b/lib/src/views/chats/add_new_user.view.dart @@ -7,15 +7,13 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:go_router/go_router.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/constants/routes.keys.dart'; -import 'package:twonly/src/database/daos/contacts.dao.dart'; +import 'package:twonly/src/database/daos/user_discovery.dao.dart'; import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart'; -import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/services/api/utils.dart'; import 'package:twonly/src/utils/misc.dart'; +import 'package:twonly/src/views/chats/add_new_user_components/friend_suggestions.dart'; +import 'package:twonly/src/views/chats/add_new_user_components/open_requests_list.dart'; import 'package:twonly/src/views/components/alert_dialog.dart'; -import 'package:twonly/src/views/components/avatar_icon.component.dart'; -import 'package:twonly/src/views/components/headline.dart'; class AddNewUserView extends StatefulWidget { const AddNewUserView({ @@ -32,47 +30,76 @@ class AddNewUserView extends StatefulWidget { } class _SearchUsernameView extends State { - final TextEditingController searchUserName = TextEditingController(); + final TextEditingController _usernameController = TextEditingController(); bool _isLoading = false; bool hasRequestedUsers = false; - List contacts = []; - late StreamSubscription> contactsStream; + List _openRequestsContacts = []; + late StreamSubscription> _contactsStream; + + AnnouncedUsersWithRelations _newAnnouncedUsers = {}; + late StreamSubscription _newAnnouncedUsersStream; + + AnnouncedUsersWithRelations _allAnnouncedUsers = {}; + late StreamSubscription _allAnnouncedUsersStream; @override void initState() { super.initState(); - contactsStream = twonlyDB.contactsDao.watchNotAcceptedContacts().listen( - (update) => setState(() { - contacts = update; - }), + _contactsStream = twonlyDB.contactsDao.watchNotAcceptedContacts().listen( + (update) { + if (mounted) { + setState(() { + _openRequestsContacts = update; + }); + } + }, ); + _newAnnouncedUsersStream = twonlyDB.userDiscoveryDao + .watchNewAnnouncedUsersWithRelations() + .listen((update) { + if (mounted) { + setState(() { + _newAnnouncedUsers = update; + }); + } + }); + _allAnnouncedUsersStream = twonlyDB.userDiscoveryDao + .watchAllAnnouncedUsersWithRelations() + .listen((update) { + if (mounted) { + setState(() { + _allAnnouncedUsers = update; + }); + } + }); if (widget.username != null) { - searchUserName.text = widget.username!; + _usernameController.text = widget.username!; WidgetsBinding.instance.addPostFrameCallback((_) { - _addNewUser(context); + _requestNewUserByUsername(widget.username!); }); } + twonlyDB.userDiscoveryDao.markAllValidAnnouncedUsersAsShown(); } @override void dispose() { - unawaited(contactsStream.cancel()); + _contactsStream.cancel(); + _newAnnouncedUsersStream.cancel(); + _allAnnouncedUsersStream.cancel(); super.dispose(); } - Future _addNewUser(BuildContext context) async { - if (gUser.username == searchUserName.text) { - return; - } + Future _requestNewUserByUsername(String username) async { + if (gUser.username == username) return; setState(() { _isLoading = true; }); - final userdata = await apiService.getUserData(searchUserName.text); - if (!context.mounted) return; + final userdata = await apiService.getUserData(username); + if (!mounted) return; setState(() { _isLoading = false; @@ -82,24 +109,22 @@ class _SearchUsernameView extends State { await showAlertDialog( context, context.lang.searchUsernameNotFound, - context.lang.searchUsernameNotFoundBody(searchUserName.text), + context.lang.searchUsernameNotFoundBody(username), ); return; } final addUser = await showAlertDialog( context, - context.lang.userFound(searchUserName.text), + context.lang.userFound(username), context.lang.userFoundBody, ); - if (!addUser || !context.mounted) { - return; - } + if (!addUser || !mounted) return; final added = await twonlyDB.contactsDao.insertOnConflictUpdate( ContactsCompanion( - username: Value(searchUserName.text), + username: Value(username), userId: Value(userdata.userId.toInt()), requested: const Value(false), blocked: const Value(false), @@ -114,7 +139,7 @@ class _SearchUsernameView extends State { if (added > 0) await importSignalContactAndCreateRequest(userdata); } - InputDecoration getInputDecoration(String hintText) { + InputDecoration _getInputDecoration(String hintText) { return InputDecoration( hintText: hintText, focusedBorder: OutlineInputBorder( @@ -146,14 +171,16 @@ class _SearchUsernameView extends State { children: [ Expanded( child: TextField( - onSubmitted: (_) async { - await _addNewUser(context); - }, + onSubmitted: _requestNewUserByUsername, onChanged: (value) { - searchUserName.text = value.toLowerCase(); - searchUserName.selection = TextSelection.fromPosition( - TextPosition(offset: searchUserName.text.length), - ); + _usernameController.text = value.toLowerCase(); + _usernameController.selection = + TextSelection.fromPosition( + TextPosition( + offset: _usernameController.text.length, + ), + ); + setState(() {}); }, inputFormatters: [ LengthLimitingTextInputFormatter(12), @@ -161,8 +188,8 @@ class _SearchUsernameView extends State { RegExp('[a-z0-9A-Z._]'), ), ], - controller: searchUserName, - decoration: getInputDecoration( + controller: _usernameController, + decoration: _getInputDecoration( context.lang.searchUsernameInput, ), ), @@ -173,18 +200,24 @@ class _SearchUsernameView extends State { const SizedBox( height: 20, ), - OutlinedButton.icon( - onPressed: () => context.push(Routes.settingsPublicProfile), - icon: const FaIcon(FontAwesomeIcons.qrcode), - label: Text(context.lang.scanQrOrShow), - ), - const SizedBox(height: 20), - if (contacts.isNotEmpty) - HeadLineComponent( - context.lang.searchUsernameNewFollowerTitle, - ), Expanded( - child: ContactsListView(contacts), + child: ListView( + children: [ + Center( + child: OutlinedButton.icon( + onPressed: () => + context.push(Routes.settingsPublicProfile), + icon: const FaIcon(FontAwesomeIcons.qrcode), + label: Text(context.lang.scanQrOrShow), + ), + ), + OpenRequestsList( + contacts: _openRequestsContacts, + relations: _allAnnouncedUsers, + ), + FriendSuggestions(_newAnnouncedUsers), + ], + ), ), ], ), @@ -193,9 +226,9 @@ class _SearchUsernameView extends State { floatingActionButton: Padding( padding: const EdgeInsets.only(bottom: 30), child: FloatingActionButton( - onPressed: _isLoading || searchUserName.text.isEmpty + onPressed: _isLoading || _usernameController.text.isEmpty ? null - : () async => _addNewUser(context), + : () => _requestNewUserByUsername(_usernameController.text), child: _isLoading ? const Center(child: CircularProgressIndicator()) : const FaIcon(FontAwesomeIcons.magnifyingGlassPlus), @@ -204,114 +237,3 @@ class _SearchUsernameView extends State { ); } } - -class ContactsListView extends StatelessWidget { - const ContactsListView(this.contacts, {super.key}); - final List contacts; - - List sendRequestActions(BuildContext context, Contact contact) { - return [ - Tooltip( - message: context.lang.searchUserNameArchiveUserTooltip, - child: IconButton( - icon: const FaIcon(Icons.archive_outlined, size: 15), - onPressed: () async { - const update = ContactsCompanion(deletedByUser: Value(true)); - await twonlyDB.contactsDao.updateContact(contact.userId, update); - }, - ), - ), - Text(context.lang.searchUserNamePending), - ]; - } - - List requestedActions(BuildContext context, Contact contact) { - return [ - Tooltip( - message: context.lang.searchUserNameBlockUserTooltip, - child: IconButton( - icon: const Icon( - Icons.person_off_rounded, - color: Color.fromARGB(164, 244, 67, 54), - ), - onPressed: () async { - const update = ContactsCompanion(blocked: Value(true)); - await twonlyDB.contactsDao.updateContact(contact.userId, update); - }, - ), - ), - Tooltip( - message: context.lang.searchUserNameRejectUserTooltip, - child: IconButton( - icon: const Icon(Icons.close, color: Colors.red), - onPressed: () async { - await sendCipherText( - contact.userId, - EncryptedContent( - contactRequest: EncryptedContent_ContactRequest( - type: EncryptedContent_ContactRequest_Type.REJECT, - ), - ), - ); - await twonlyDB.contactsDao.updateContact( - contact.userId, - const ContactsCompanion( - accepted: Value(false), - requested: Value(false), - deletedByUser: Value(true), - ), - ); - }, - ), - ), - IconButton( - icon: const Icon(Icons.check, color: Colors.green), - onPressed: () async { - await twonlyDB.contactsDao.updateContact( - contact.userId, - const ContactsCompanion( - accepted: Value(true), - requested: Value(false), - ), - ); - await twonlyDB.groupsDao.createNewDirectChat( - contact.userId, - GroupsCompanion( - groupName: Value(getContactDisplayName(contact)), - ), - ); - await sendCipherText( - contact.userId, - EncryptedContent( - contactRequest: EncryptedContent_ContactRequest( - type: EncryptedContent_ContactRequest_Type.ACCEPT, - ), - ), - ); - await sendContactMyProfileData(contact.userId); - }, - ), - ]; - } - - @override - Widget build(BuildContext context) { - return ListView.builder( - itemCount: contacts.length, - itemBuilder: (context, index) { - final contact = contacts[index]; - return ListTile( - key: ValueKey(contact.userId), - title: Text(substringBy(contact.username, 25)), - leading: AvatarIcon(contactId: contact.userId), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: contact.requested - ? requestedActions(context, contact) - : sendRequestActions(context, contact), - ), - ); - }, - ); - } -} diff --git a/lib/src/views/chats/add_new_user_components/friend_suggestions.dart b/lib/src/views/chats/add_new_user_components/friend_suggestions.dart new file mode 100644 index 00000000..7d154bd9 --- /dev/null +++ b/lib/src/views/chats/add_new_user_components/friend_suggestions.dart @@ -0,0 +1,162 @@ +import 'package:drift/drift.dart' show Value; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/database/daos/contacts.dao.dart'; +import 'package:twonly/src/database/daos/user_discovery.dao.dart'; +import 'package:twonly/src/database/twonly.db.dart'; +import 'package:twonly/src/services/api/utils.dart'; +import 'package:twonly/src/themes/light.dart'; +import 'package:twonly/src/utils/log.dart'; +import 'package:twonly/src/utils/misc.dart'; +import 'package:twonly/src/views/components/avatar_icon.component.dart'; +import 'package:twonly/src/views/components/headline.dart'; +import 'package:twonly/src/views/groups/group.view.dart'; + +List buildFriendsListText( + BuildContext context, + List<(Contact, DateTime?)> friends, +) { + final names = friends.map((f) => '*${getContactDisplayName(f.$1)}*').toList(); + + return formattedText( + context, + context.lang.friendSuggestionsFriendsWith( + joinWithAnd(names, context.lang.andWord), + ), + ); +} + +class FriendSuggestions extends StatelessWidget { + const FriendSuggestions(this.announcedUsers, {super.key}); + + final AnnouncedUsersWithRelations announcedUsers; + + Future _requestAnnouncedUser( + BuildContext context, + UserDiscoveryAnnouncedUser user, + ) async { + Log.info('Requesting user via friend suggestions'); + + final userdata = await apiService.getUserById(user.announcedUserId); + + if (userdata == null) { + if (context.mounted) { + showNetworkIssue(context); + } + return; + } + + final added = await twonlyDB.contactsDao.insertOnConflictUpdate( + ContactsCompanion( + username: Value(user.username!), + userId: Value(userdata.userId.toInt()), + requested: const Value(false), + blocked: const Value(false), + deletedByUser: const Value(false), + ), + ); + + if (added > 0) await importSignalContactAndCreateRequest(userdata); + } + + Future _hideAnnouncedUser(int userId) async { + await twonlyDB.userDiscoveryDao.updateAnnouncedUser( + userId, + const UserDiscoveryAnnouncedUsersCompanion( + isHidden: Value(true), + ), + ); + } + + @override + Widget build(BuildContext context) { + if (announcedUsers.isEmpty) return Container(); + return Column( + children: [ + const SizedBox(height: 20), + HeadLineComponent( + context.lang.friendSuggestionsTitle, + ), + ...announcedUsers.entries.map(( + announcedUser, + ) { + final user = announcedUser.key; + final friends = announcedUser.value; + + final friendsList = buildFriendsListText(context, friends); + + return ListTile( + key: ValueKey(user.announcedUserId), + contentPadding: EdgeInsets.zero, + title: Text(substringBy(user.username!, 25)), + subtitle: StreamBuilder( + stream: twonlyDB.groupsDao.watchNonDirectGroupsForMember( + user.announcedUserId, + ), + builder: (context, snapshot) { + var text = friendsList; + if (snapshot.hasData && snapshot.data!.isNotEmpty) { + text += formattedText( + context, + context.lang.friendSuggestionsGroupMemberIn( + joinWithAnd( + snapshot.data!.map((g) => '*${g.groupName}*').toList(), + context.lang.andWord, + ), + ), + ); + } + return RichText( + text: TextSpan( + children: text, + style: const TextStyle(fontSize: 11), + ), + ); + }, + ), + + leading: const AvatarIcon( + fontSize: 17, + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 26, + child: FilledButton( + style: FilledButton.styleFrom( + padding: const EdgeInsets.only(right: 8, left: 4), + ).merge(secondaryGreyButtonStyle(context)), + child: Row( + children: [ + const Padding( + padding: EdgeInsets.symmetric(horizontal: 6), + child: FaIcon(FontAwesomeIcons.userPlus, size: 12), + ), + Text( + context.lang.friendSuggestionsRequest, + style: const TextStyle(fontSize: 10), + ), + ], + ), + onPressed: () => _requestAnnouncedUser(context, user), + ), + ), + IconButton( + style: IconButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 8), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + constraints: const BoxConstraints(), + icon: const Icon(Icons.close, size: 18), + onPressed: () => _hideAnnouncedUser(user.announcedUserId), + ), + ], + ), + ); + }), + ], + ); + } +} diff --git a/lib/src/views/chats/add_new_user_components/open_requests_list.dart b/lib/src/views/chats/add_new_user_components/open_requests_list.dart new file mode 100644 index 00000000..bdc32dbf --- /dev/null +++ b/lib/src/views/chats/add_new_user_components/open_requests_list.dart @@ -0,0 +1,189 @@ +import 'package:drift/drift.dart' hide Column; +import 'package:flutter/material.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/database/daos/contacts.dao.dart'; +import 'package:twonly/src/database/daos/user_discovery.dao.dart'; +import 'package:twonly/src/database/twonly.db.dart'; +import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart'; +import 'package:twonly/src/services/api/messages.dart'; +import 'package:twonly/src/themes/light.dart'; +import 'package:twonly/src/utils/log.dart'; +import 'package:twonly/src/utils/misc.dart'; +import 'package:twonly/src/views/chats/add_new_user_components/friend_suggestions.dart'; +import 'package:twonly/src/views/components/avatar_icon.component.dart'; +import 'package:twonly/src/views/components/headline.dart'; + +class OpenRequestsList extends StatelessWidget { + const OpenRequestsList({ + required this.contacts, + required this.relations, + super.key, + }); + final List contacts; + final AnnouncedUsersWithRelations relations; + + List sendRequestActions(BuildContext context, Contact contact) { + return [ + Text(context.lang.searchUserNamePending), + IconButton( + style: IconButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 8), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + constraints: const BoxConstraints(), + icon: const Icon(Icons.close, size: 18), + onPressed: () async { + const update = ContactsCompanion(deletedByUser: Value(true)); + await twonlyDB.contactsDao.updateContact(contact.userId, update); + }, + ), + ]; + } + + List requestedActions(BuildContext context, Contact contact) { + return [ + SizedBox( + height: 26, + child: FilledButton( + style: FilledButton.styleFrom( + padding: const EdgeInsets.symmetric( + horizontal: 4, + ), + ).merge(secondaryGreyButtonStyle(context)), + child: Row( + children: [ + const Icon( + Icons.person_off_rounded, + color: Color.fromARGB(164, 244, 67, 54), + ), + Text( + context.lang.contactActionBlock, + style: const TextStyle(fontSize: 10), + ), + ], + ), + onPressed: () async { + const update = ContactsCompanion(blocked: Value(true)); + await twonlyDB.contactsDao.updateContact(contact.userId, update); + }, + ), + ), + const SizedBox(width: 9), + SizedBox( + height: 26, + child: FilledButton( + style: FilledButton.styleFrom( + padding: const EdgeInsets.only(right: 8, left: 4), + ).merge(secondaryGreyButtonStyle(context)), + child: Row( + children: [ + const Icon(Icons.check, color: Colors.green), + Text( + context.lang.contactActionAccept, + style: const TextStyle(fontSize: 10), + ), + ], + ), + onPressed: () async { + await twonlyDB.contactsDao.updateContact( + contact.userId, + const ContactsCompanion( + accepted: Value(true), + requested: Value(false), + ), + ); + await twonlyDB.groupsDao.createNewDirectChat( + contact.userId, + GroupsCompanion( + groupName: Value(getContactDisplayName(contact)), + ), + ); + await sendCipherText( + contact.userId, + EncryptedContent( + contactRequest: EncryptedContent_ContactRequest( + type: EncryptedContent_ContactRequest_Type.ACCEPT, + ), + ), + ); + await sendContactMyProfileData(contact.userId); + }, + ), + ), + IconButton( + style: IconButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 8), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + constraints: const BoxConstraints(), + icon: const Icon(Icons.close, size: 18), + onPressed: () async { + await sendCipherText( + contact.userId, + EncryptedContent( + contactRequest: EncryptedContent_ContactRequest( + type: EncryptedContent_ContactRequest_Type.REJECT, + ), + ), + ); + await twonlyDB.contactsDao.updateContact( + contact.userId, + const ContactsCompanion( + accepted: Value(false), + requested: Value(false), + deletedByUser: Value(true), + ), + ); + }, + ), + ]; + } + + @override + Widget build(BuildContext context) { + if (contacts.isEmpty) return Container(); + return Column( + children: [ + const SizedBox(height: 20), + HeadLineComponent( + context.lang.searchUsernameNewFollowerTitle, + ), + ...contacts.map((contact) { + Widget? subtitle; + + Log.info('Relations count: ${relations.entries.length}'); + + for (final relation in relations.entries) { + if (relation.key.announcedUserId == contact.userId) { + subtitle = RichText( + text: TextSpan( + children: buildFriendsListText(context, relation.value), + style: const TextStyle(fontSize: 11), + ), + ); + + break; + } + } + + return ListTile( + key: ValueKey(contact.userId), + contentPadding: EdgeInsets.zero, + title: Text(substringBy(contact.username, 25)), + subtitle: subtitle, + leading: AvatarIcon( + contactId: contact.userId, + fontSize: 17, + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: contact.requested + ? requestedActions(context, contact) + : sendRequestActions(context, contact), + ), + ); + }), + ], + ); + } +} diff --git a/lib/src/views/chats/chat_list.view.dart b/lib/src/views/chats/chat_list.view.dart index 802c360e..dda5cf72 100644 --- a/lib/src/views/chats/chat_list.view.dart +++ b/lib/src/views/chats/chat_list.view.dart @@ -11,6 +11,7 @@ import 'package:twonly/src/constants/routes.keys.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/providers/purchases.provider.dart'; import 'package:twonly/src/services/subscription.service.dart'; +import 'package:twonly/src/themes/light.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/views/chats/chat_list_components/feedback_btn.dart'; @@ -48,6 +49,7 @@ class _ChatListViewState extends State { Future initAsync() async { final stream = twonlyDB.groupsDao.watchGroupsForChatList(); _contactsSub = stream.listen((groups) { + if (!mounted) return; setState(() { _groupsNotPinned = groups .where((x) => !x.pinned && !x.archived) @@ -61,15 +63,17 @@ class _ChatListViewState extends State { .watchContactsRequestedCount() .listen((update) { if (update != null) { + if (!mounted) return; setState(() { _countContactRequest = update; }); } }); - _countContactRequestStream = twonlyDB.userDiscoveryDao + _countAnnouncedStream = twonlyDB.userDiscoveryDao .watchNewAnnouncementsWithDataCount() .listen((update) { + if (!mounted) return; setState(() { _countAnnouncedUsers = update; }); @@ -165,8 +169,8 @@ class _ChatListViewState extends State { child: Container( width: 40, height: 40, - decoration: BoxDecoration( - color: context.color.primary, + decoration: const BoxDecoration( + color: primaryColor, shape: BoxShape.circle, ), ), @@ -174,6 +178,10 @@ class _ChatListViewState extends State { ), Center( child: NotificationBadge( + backgroundColor: isDarkMode(context) + ? Colors.white + : Colors.black, + textColor: isDarkMode(context) ? Colors.black : Colors.white, count: (_countAnnouncedUsers + _countContactRequest) .toString(), child: IconButton( diff --git a/lib/src/views/chats/chat_messages_components/typing_indicator.dart b/lib/src/views/chats/chat_messages_components/typing_indicator.dart index b48908b5..ea949a66 100644 --- a/lib/src/views/chats/chat_messages_components/typing_indicator.dart +++ b/lib/src/views/chats/chat_messages_components/typing_indicator.dart @@ -41,8 +41,6 @@ class TypingIndicator extends StatefulWidget { } class _TypingIndicatorState extends State { - late AnimationController _controller; - List _groupMembers = []; late StreamSubscription> membersSub; @@ -75,7 +73,6 @@ class _TypingIndicatorState extends State { @override void dispose() { - _controller.dispose(); membersSub.cancel(); _periodicUpdate.cancel(); super.dispose(); @@ -183,6 +180,12 @@ class _AnimatedTypingDotsState extends State super.initState(); } + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Row( diff --git a/lib/src/views/components/notification_badge.dart b/lib/src/views/components/notification_badge.dart index dd4e0ac0..a75ded0a 100644 --- a/lib/src/views/components/notification_badge.dart +++ b/lib/src/views/components/notification_badge.dart @@ -4,9 +4,13 @@ class NotificationBadge extends StatelessWidget { const NotificationBadge({ required this.count, required this.child, + this.backgroundColor = Colors.red, + this.textColor = Colors.white, super.key, }); final String count; + final Color backgroundColor; + final Color textColor; final Widget child; @override @@ -23,14 +27,14 @@ class NotificationBadge extends StatelessWidget { height: 18, width: 18, child: CircleAvatar( - backgroundColor: Colors.red, + backgroundColor: backgroundColor, child: Center( child: Transform.rotate( angle: infinity ? 90 * (3.141592653589793 / 180) : 0, child: Text( infinity ? '8' : count, - style: const TextStyle( - color: Colors.white, // Text color + style: TextStyle( + color: textColor, fontSize: 10, ), ), diff --git a/lib/src/views/contact/contact.view.dart b/lib/src/views/contact/contact.view.dart index 2adf1058..b438b604 100644 --- a/lib/src/views/contact/contact.view.dart +++ b/lib/src/views/contact/contact.view.dart @@ -87,14 +87,15 @@ class _ContactViewState extends State { context.lang.contactRemoveBody, ); if (remove) { - await twonlyDB.contactsDao.updateContact( - contact.userId, - const ContactsCompanion( - accepted: Value(false), - requested: Value(false), - deletedByUser: Value(true), - ), - ); + await twonlyDB.contactsDao.deleteContactByUserId(contact.userId); + // await twonlyDB.contactsDao.updateContact( + // contact.userId, + // const ContactsCompanion( + // accepted: Value(false), + // requested: Value(false), + // deletedByUser: Value(true), + // ), + // ); if (mounted) { Navigator.popUntil(context, (route) => route.isFirst); } @@ -221,6 +222,36 @@ class _ContactViewState extends State { setState(() {}); }, ), + if (gUser.isUserDiscoveryEnabled) + BetterListTile( + icon: FontAwesomeIcons.usersViewfinder, + text: context.lang.userDiscoverySettingsTitle, + subtitle: + !contact.userDiscoveryExcluded && + contact.mediaSendCounter < + gUser.minimumRequiredImagesExchanged + ? Text( + context.lang.contactUserDiscoveryImagesLeft( + gUser.minimumRequiredImagesExchanged - + contact.mediaSendCounter, + getContactDisplayName(contact), + ), + style: const TextStyle(fontSize: 9), + ) + : null, + trailing: Transform.scale( + scale: 0.8, + child: Switch( + value: !contact.userDiscoveryExcluded, + onChanged: (a) async { + await twonlyDB.contactsDao.updateContact( + contact.userId, + ContactsCompanion(userDiscoveryExcluded: Value(!a)), + ); + }, + ), + ), + ), BetterListTile( icon: FontAwesomeIcons.flag, text: context.lang.reportUser, diff --git a/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart b/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart index 4840a242..36c9ab87 100644 --- a/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart +++ b/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart @@ -30,28 +30,29 @@ class _UserDiscoveryDisabledComponentState child: ListView( children: [ const SizedBox(height: 45), - const Text( - 'twonly verzichten auf Telefonnummern, daher schlagen wir dir Freunde stattdessen über gemeinsame Kontakte vor – sicher und privat.', + Text( + context.lang.userDiscoveryDisabledIntro, textAlign: TextAlign.center, ), const SizedBox(height: 30), RichText( text: TextSpan( children: formattedText( - 'Deine Freundesliste ist für *Fremde komplett unsichtbar*. Nur deine Freunde können Teile davon sehen – und zwar nur die Personen, mit denen sie selbst *gemeinsame Freunde* haben.', + context, + context.lang.userDiscoveryDisabledInvisible, ), ), textAlign: TextAlign.center, ), const SizedBox(height: 35), - const Text( - 'Du hast die Kontrolle', - style: TextStyle(fontSize: 17), + Text( + context.lang.userDiscoveryDisabledYouHaveControl, + style: const TextStyle(fontSize: 17), textAlign: TextAlign.center, ), const SizedBox(height: 20), - const Text( - 'Entscheide selbst, wer deine Freunde sehen darf. Du kannst deine Meinung jederzeit ändern oder bestimmte Personen verstecken.', + Text( + context.lang.userDiscoveryDisabledDecide, textAlign: TextAlign.center, ), @@ -61,10 +62,13 @@ class _UserDiscoveryDisabledComponentState onPressed: initializeUserDiscoveryWithDefaultSettings, style: primaryColorButtonStyle.merge( FilledButton.styleFrom( - padding: EdgeInsets.symmetric(horizontal: 32, vertical: 24), + padding: const EdgeInsets.symmetric( + horizontal: 32, + vertical: 24, + ), ), ), - child: const Text('Mit Standardeinstellungen aktivieren'), + child: Text(context.lang.userDiscoveryDisabledEnableWithDefault), ), const SizedBox(height: 20), @@ -74,7 +78,7 @@ class _UserDiscoveryDisabledComponentState child: FilledButton( onPressed: () {}, style: secondaryGreyButtonStyle(context), - child: const Text('Einstellungen anpassen'), + child: Text(context.lang.userDiscoveryDisabledCustomizeSettings), ), ), const SizedBox(height: 15), @@ -83,7 +87,7 @@ class _UserDiscoveryDisabledComponentState child: FilledButton( onPressed: () {}, style: secondaryGreyButtonStyle(context), - child: const Text('Mehr erfahren'), + child: Text(context.lang.userDiscoveryDisabledLearnMore), ), ), ], diff --git a/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart b/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart index 10c6971a..8acc3022 100644 --- a/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart +++ b/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart @@ -1,12 +1,17 @@ import 'dart:async'; +import 'package:drift/drift.dart' show Value; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/database/daos/contacts.dao.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/model/protobuf/client/generated/user_discovery/types.pb.dart'; import 'package:twonly/src/services/user_discovery.service.dart'; +import 'package:twonly/src/themes/light.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/views/components/alert_dialog.dart'; +import 'package:twonly/src/views/components/avatar_icon.component.dart'; +import 'package:twonly/src/views/components/user_context_menu.component.dart'; import 'package:twonly/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart'; class UserDiscoveryEnabledComponent extends StatefulWidget { @@ -57,8 +62,8 @@ class _UserDiscoveryEnabledComponentState Future _disableUserDiscovery() async { final ok = await showAlertDialog( context, - 'Wirklich deaktivieren?', - 'Wenn du das Feature „Freunde finden“ deaktivierst, werden dir keine Vorschläge mehr angezeigt. Du teilst neuen Kontakten dann auch nicht mehr deine Freunde.', + context.lang.userDiscoveryEnabledDialogTitle, + context.lang.userDiscoveryEnabledDisableWarning, ); if (ok) { @@ -80,48 +85,98 @@ class _UserDiscoveryEnabledComponentState backgroundColor: context.color.surfaceContainer, collapsedShape: const RoundedRectangleBorder(), tilePadding: const EdgeInsets.symmetric(horizontal: 17), - title: const Text('Freunde die du teilst'), - subtitle: const Text( - 'Du teilst nur Freunde, die diese Funktion ebenfalls aktiviert haben und die den von dir festgelegten Schwellenwert erreicht haben.', - style: TextStyle(fontSize: 10), + title: Text(context.lang.userDiscoveryEnabledFriendsShared), + subtitle: Text( + context.lang.userDiscoveryEnabledFriendsSharedDesc, + style: const TextStyle(fontSize: 10), ), children: _contactsGettingAnnounced.isEmpty ? [ - const Padding( - padding: EdgeInsetsGeometry.symmetric(vertical: 12), + Padding( + padding: const EdgeInsetsGeometry.symmetric(vertical: 12), child: Text( - 'Bisher teilst du noch niemanden.', + context.lang.userDiscoveryEnabledNoFriendsShared, ), ), ] : _contactsGettingAnnounced.map((contact) { - return Text(getContactDisplayName(contact)); + final version = + UserDiscoveryService.getContactVersionTypedFromContact( + contact, + ); + + return UserContextMenu( + key: ValueKey(contact.userId), + contact: contact, + child: ListTile( + dense: true, + visualDensity: VisualDensity.compact, + minVerticalPadding: 0, + title: Text(getContactDisplayName(contact)), + leading: AvatarIcon( + contactId: contact.userId, + fontSize: 17, + ), + subtitle: + (version != null && + (gUser.isDeveloper || !kReleaseMode)) + ? Text( + context.lang.userDiscoveryEnabledVersion( + '${version.announcement}.${version.promotion}', + ), + style: const TextStyle(fontSize: 10), + ) + : null, + trailing: SizedBox( + height: 26, + child: FilledButton( + style: FilledButton.styleFrom( + padding: const EdgeInsets.only(right: 8, left: 8), + ).merge(secondaryGreyButtonStyle(context)), + child: Text( + context.lang.userDiscoveryEnabledStopSharing, + style: const TextStyle(fontSize: 10), + ), + onPressed: () async { + await twonlyDB.contactsDao.updateContact( + contact.userId, + const ContactsCompanion( + userDiscoveryExcluded: Value(true), + ), + ); + }, + ), + ), + ), + ); }).toList(), ), ListTile( - title: const Text('Einstellungen ändern'), + title: Text(context.lang.userDiscoveryEnabledChangeSettings), onTap: () async { await context.navPush(const UserDiscoverySettingsView()); await _initAsync(); }, ), const Divider(), - const ListTile( - title: Text('Mehr erfahren'), + ListTile( + title: Text(context.lang.userDiscoveryDisabledLearnMore), subtitle: Text( - 'In unserem FAQ erklären wir dir wie das Feature "Freunde finden" funktioniert.', + context.lang.userDiscoveryEnabledFaq, ), // onTap: _disableUserDiscovery, ), const Divider(), ListTile( - title: const Text('Deaktivieren'), + title: Text(context.lang.userDiscoveryActionDisable), onTap: _disableUserDiscovery, ), - if (_version != null) + if (_version != null && (gUser.isDeveloper || !kReleaseMode)) ListTile( title: Text( - 'Your version: ${_version!.announcement}.${_version!.promotion}', + context.lang.userDiscoveryEnabledYourVersion( + '${_version!.announcement}.${_version!.promotion}', + ), style: const TextStyle(color: Colors.grey, fontSize: 13), ), ), diff --git a/lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart b/lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart index e7a8e643..e0cf5c0c 100644 --- a/lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart +++ b/lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/services/user_discovery.service.dart'; import 'package:twonly/src/themes/light.dart'; +import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/storage.dart'; class UserDiscoverySettingsView extends StatefulWidget { @@ -50,16 +51,16 @@ class _UserDiscoverySettingsViewState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Freunde finden'), + title: Text(context.lang.userDiscoverySettingsTitle), ), body: Padding( padding: const EdgeInsets.only(top: 10), child: ListView( children: [ ListTile( - title: const Text('Anzahl an geteilten Bildern'), - subtitle: const Text( - 'Wähle die Mindestanzahl an Bildern, die du mit einer Person ausgetauscht haben musst, bevor du ihr deine Freunde sicher teilst.', + title: Text(context.lang.userDiscoverySettingsMinImagesTitle), + subtitle: Text( + context.lang.userDiscoverySettingsMinImages, ), trailing: SizedBox( width: 60, @@ -83,9 +84,9 @@ class _UserDiscoverySettingsViewState extends State { ), ), ListTile( - title: const Text('Anzahl an gemeinsame Freunde'), - subtitle: const Text( - 'Wähle aus, wie viele gemeinsame Freunde eine Person haben muss, damit du ihr vorgeschlagen wirst.', + title: Text(context.lang.userDiscoverySettingsMutualFriendsTitle), + subtitle: Text( + context.lang.userDiscoverySettingsMutualFriends, ), trailing: SizedBox( width: 60, @@ -120,13 +121,13 @@ class _UserDiscoverySettingsViewState extends State { onPressed: _saveChanges, style: primaryColorButtonStyle.merge( FilledButton.styleFrom( - padding: EdgeInsets.symmetric( + padding: const EdgeInsets.symmetric( horizontal: 32, vertical: 24, ), ), ), - child: const Text('Änderungen übernehmen'), + child: Text(context.lang.userDiscoverySettingsApply), ), ), ], diff --git a/rust_builder/pubspec.yaml b/rust_builder/pubspec.yaml index 6da7e8bc..ecdd1117 100644 --- a/rust_builder/pubspec.yaml +++ b/rust_builder/pubspec.yaml @@ -15,9 +15,9 @@ dependencies: dev_dependencies: ffi: ^2.0.2 ffigen: ^11.0.0 + flutter_lints: ^2.0.0 flutter_test: sdk: flutter - flutter_lints: ^2.0.0 flutter: plugin: diff --git a/test/drift/twonly_db/generated/schema.dart b/test/drift/twonly_db/generated/schema.dart index 938ab126..ad724535 100644 --- a/test/drift/twonly_db/generated/schema.dart +++ b/test/drift/twonly_db/generated/schema.dart @@ -18,6 +18,7 @@ import 'schema_v11.dart' as v11; import 'schema_v12.dart' as v12; import 'schema_v13.dart' as v13; import 'schema_v14.dart' as v14; +import 'schema_v15.dart' as v15; class GeneratedHelper implements SchemaInstantiationHelper { @override @@ -51,10 +52,28 @@ class GeneratedHelper implements SchemaInstantiationHelper { return v13.DatabaseAtV13(db); case 14: return v14.DatabaseAtV14(db); + case 15: + return v15.DatabaseAtV15(db); default: throw MissingSchemaException(version, versions); } } - static const versions = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; + static const versions = const [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + ]; } diff --git a/test/drift/twonly_db/generated/schema_v15.dart b/test/drift/twonly_db/generated/schema_v15.dart new file mode 100644 index 00000000..8200e3b3 --- /dev/null +++ b/test/drift/twonly_db/generated/schema_v15.dart @@ -0,0 +1,9602 @@ +// dart format width=80 +import 'dart:typed_data' as i2; +// GENERATED BY drift_dev, DO NOT MODIFY. +// ignore_for_file: type=lint,unused_import +// +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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn username = GeneratedColumn( + 'username', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn displayName = GeneratedColumn( + 'display_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn nickName = GeneratedColumn( + 'nick_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn avatarSvgCompressed = + GeneratedColumn( + 'avatar_svg_compressed', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn senderProfileCounter = GeneratedColumn( + 'sender_profile_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn accepted = GeneratedColumn( + 'accepted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (accepted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deletedByUser = GeneratedColumn( + 'deleted_by_user', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (deleted_by_user IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn requested = GeneratedColumn( + 'requested', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (requested IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn blocked = GeneratedColumn( + 'blocked', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (blocked IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn verified = GeneratedColumn( + 'verified', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (verified IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn accountDeleted = GeneratedColumn( + 'account_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (account_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn userDiscoveryVersion = + GeneratedColumn( + 'user_discovery_version', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn userDiscoveryExcluded = GeneratedColumn( + 'user_discovery_excluded', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (user_discovery_excluded IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn mediaSendCounter = GeneratedColumn( + 'media_send_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn mediaReceivedCounter = GeneratedColumn( + 'media_received_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [ + userId, + username, + displayName, + nickName, + avatarSvgCompressed, + senderProfileCounter, + accepted, + deletedByUser, + requested, + blocked, + verified, + accountDeleted, + createdAt, + userDiscoveryVersion, + userDiscoveryExcluded, + mediaSendCounter, + mediaReceivedCounter, + ]; + @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'], + ), + avatarSvgCompressed: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}avatar_svg_compressed'], + ), + senderProfileCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_profile_counter'], + )!, + accepted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}accepted'], + )!, + deletedByUser: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}deleted_by_user'], + )!, + requested: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}requested'], + )!, + blocked: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}blocked'], + )!, + verified: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}verified'], + )!, + accountDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}account_deleted'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + userDiscoveryVersion: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}user_discovery_version'], + ), + userDiscoveryExcluded: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}user_discovery_excluded'], + )!, + mediaSendCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_send_counter'], + )!, + mediaReceivedCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_received_counter'], + )!, + ); + } + + @override + Contacts createAlias(String alias) { + return Contacts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(user_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ContactsData extends DataClass implements Insertable { + final int userId; + final String username; + final String? displayName; + final String? nickName; + final i2.Uint8List? avatarSvgCompressed; + final int senderProfileCounter; + final int accepted; + final int deletedByUser; + final int requested; + final int blocked; + final int verified; + final int accountDeleted; + final int createdAt; + final i2.Uint8List? userDiscoveryVersion; + final int userDiscoveryExcluded; + final int mediaSendCounter; + final int mediaReceivedCounter; + const ContactsData({ + required this.userId, + required this.username, + this.displayName, + this.nickName, + this.avatarSvgCompressed, + required this.senderProfileCounter, + required this.accepted, + required this.deletedByUser, + required this.requested, + required this.blocked, + required this.verified, + required this.accountDeleted, + required this.createdAt, + this.userDiscoveryVersion, + required this.userDiscoveryExcluded, + required this.mediaSendCounter, + required this.mediaReceivedCounter, + }); + @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 || avatarSvgCompressed != null) { + map['avatar_svg_compressed'] = Variable( + avatarSvgCompressed, + ); + } + map['sender_profile_counter'] = Variable(senderProfileCounter); + map['accepted'] = Variable(accepted); + map['deleted_by_user'] = Variable(deletedByUser); + map['requested'] = Variable(requested); + map['blocked'] = Variable(blocked); + map['verified'] = Variable(verified); + map['account_deleted'] = Variable(accountDeleted); + map['created_at'] = Variable(createdAt); + if (!nullToAbsent || userDiscoveryVersion != null) { + map['user_discovery_version'] = Variable( + userDiscoveryVersion, + ); + } + map['user_discovery_excluded'] = Variable(userDiscoveryExcluded); + map['media_send_counter'] = Variable(mediaSendCounter); + map['media_received_counter'] = Variable(mediaReceivedCounter); + 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), + avatarSvgCompressed: avatarSvgCompressed == null && nullToAbsent + ? const Value.absent() + : Value(avatarSvgCompressed), + senderProfileCounter: Value(senderProfileCounter), + accepted: Value(accepted), + deletedByUser: Value(deletedByUser), + requested: Value(requested), + blocked: Value(blocked), + verified: Value(verified), + accountDeleted: Value(accountDeleted), + createdAt: Value(createdAt), + userDiscoveryVersion: userDiscoveryVersion == null && nullToAbsent + ? const Value.absent() + : Value(userDiscoveryVersion), + userDiscoveryExcluded: Value(userDiscoveryExcluded), + mediaSendCounter: Value(mediaSendCounter), + mediaReceivedCounter: Value(mediaReceivedCounter), + ); + } + + 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']), + avatarSvgCompressed: serializer.fromJson( + json['avatarSvgCompressed'], + ), + senderProfileCounter: serializer.fromJson( + json['senderProfileCounter'], + ), + accepted: serializer.fromJson(json['accepted']), + deletedByUser: serializer.fromJson(json['deletedByUser']), + requested: serializer.fromJson(json['requested']), + blocked: serializer.fromJson(json['blocked']), + verified: serializer.fromJson(json['verified']), + accountDeleted: serializer.fromJson(json['accountDeleted']), + createdAt: serializer.fromJson(json['createdAt']), + userDiscoveryVersion: serializer.fromJson( + json['userDiscoveryVersion'], + ), + userDiscoveryExcluded: serializer.fromJson( + json['userDiscoveryExcluded'], + ), + mediaSendCounter: serializer.fromJson(json['mediaSendCounter']), + mediaReceivedCounter: serializer.fromJson( + json['mediaReceivedCounter'], + ), + ); + } + @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), + 'avatarSvgCompressed': serializer.toJson( + avatarSvgCompressed, + ), + 'senderProfileCounter': serializer.toJson(senderProfileCounter), + 'accepted': serializer.toJson(accepted), + 'deletedByUser': serializer.toJson(deletedByUser), + 'requested': serializer.toJson(requested), + 'blocked': serializer.toJson(blocked), + 'verified': serializer.toJson(verified), + 'accountDeleted': serializer.toJson(accountDeleted), + 'createdAt': serializer.toJson(createdAt), + 'userDiscoveryVersion': serializer.toJson( + userDiscoveryVersion, + ), + 'userDiscoveryExcluded': serializer.toJson(userDiscoveryExcluded), + 'mediaSendCounter': serializer.toJson(mediaSendCounter), + 'mediaReceivedCounter': serializer.toJson(mediaReceivedCounter), + }; + } + + ContactsData copyWith({ + int? userId, + String? username, + Value displayName = const Value.absent(), + Value nickName = const Value.absent(), + Value avatarSvgCompressed = const Value.absent(), + int? senderProfileCounter, + int? accepted, + int? deletedByUser, + int? requested, + int? blocked, + int? verified, + int? accountDeleted, + int? createdAt, + Value userDiscoveryVersion = const Value.absent(), + int? userDiscoveryExcluded, + int? mediaSendCounter, + int? mediaReceivedCounter, + }) => ContactsData( + userId: userId ?? this.userId, + username: username ?? this.username, + displayName: displayName.present ? displayName.value : this.displayName, + nickName: nickName.present ? nickName.value : this.nickName, + avatarSvgCompressed: avatarSvgCompressed.present + ? avatarSvgCompressed.value + : this.avatarSvgCompressed, + senderProfileCounter: senderProfileCounter ?? this.senderProfileCounter, + accepted: accepted ?? this.accepted, + deletedByUser: deletedByUser ?? this.deletedByUser, + requested: requested ?? this.requested, + blocked: blocked ?? this.blocked, + verified: verified ?? this.verified, + accountDeleted: accountDeleted ?? this.accountDeleted, + createdAt: createdAt ?? this.createdAt, + userDiscoveryVersion: userDiscoveryVersion.present + ? userDiscoveryVersion.value + : this.userDiscoveryVersion, + userDiscoveryExcluded: userDiscoveryExcluded ?? this.userDiscoveryExcluded, + mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter, + mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter, + ); + 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, + avatarSvgCompressed: data.avatarSvgCompressed.present + ? data.avatarSvgCompressed.value + : this.avatarSvgCompressed, + senderProfileCounter: data.senderProfileCounter.present + ? data.senderProfileCounter.value + : this.senderProfileCounter, + accepted: data.accepted.present ? data.accepted.value : this.accepted, + deletedByUser: data.deletedByUser.present + ? data.deletedByUser.value + : this.deletedByUser, + 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, + accountDeleted: data.accountDeleted.present + ? data.accountDeleted.value + : this.accountDeleted, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + userDiscoveryVersion: data.userDiscoveryVersion.present + ? data.userDiscoveryVersion.value + : this.userDiscoveryVersion, + userDiscoveryExcluded: data.userDiscoveryExcluded.present + ? data.userDiscoveryExcluded.value + : this.userDiscoveryExcluded, + mediaSendCounter: data.mediaSendCounter.present + ? data.mediaSendCounter.value + : this.mediaSendCounter, + mediaReceivedCounter: data.mediaReceivedCounter.present + ? data.mediaReceivedCounter.value + : this.mediaReceivedCounter, + ); + } + + @override + String toString() { + return (StringBuffer('ContactsData(') + ..write('userId: $userId, ') + ..write('username: $username, ') + ..write('displayName: $displayName, ') + ..write('nickName: $nickName, ') + ..write('avatarSvgCompressed: $avatarSvgCompressed, ') + ..write('senderProfileCounter: $senderProfileCounter, ') + ..write('accepted: $accepted, ') + ..write('deletedByUser: $deletedByUser, ') + ..write('requested: $requested, ') + ..write('blocked: $blocked, ') + ..write('verified: $verified, ') + ..write('accountDeleted: $accountDeleted, ') + ..write('createdAt: $createdAt, ') + ..write('userDiscoveryVersion: $userDiscoveryVersion, ') + ..write('userDiscoveryExcluded: $userDiscoveryExcluded, ') + ..write('mediaSendCounter: $mediaSendCounter, ') + ..write('mediaReceivedCounter: $mediaReceivedCounter') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + userId, + username, + displayName, + nickName, + $driftBlobEquality.hash(avatarSvgCompressed), + senderProfileCounter, + accepted, + deletedByUser, + requested, + blocked, + verified, + accountDeleted, + createdAt, + $driftBlobEquality.hash(userDiscoveryVersion), + userDiscoveryExcluded, + mediaSendCounter, + mediaReceivedCounter, + ); + @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 && + $driftBlobEquality.equals( + other.avatarSvgCompressed, + this.avatarSvgCompressed, + ) && + other.senderProfileCounter == this.senderProfileCounter && + other.accepted == this.accepted && + other.deletedByUser == this.deletedByUser && + other.requested == this.requested && + other.blocked == this.blocked && + other.verified == this.verified && + other.accountDeleted == this.accountDeleted && + other.createdAt == this.createdAt && + $driftBlobEquality.equals( + other.userDiscoveryVersion, + this.userDiscoveryVersion, + ) && + other.userDiscoveryExcluded == this.userDiscoveryExcluded && + other.mediaSendCounter == this.mediaSendCounter && + other.mediaReceivedCounter == this.mediaReceivedCounter); +} + +class ContactsCompanion extends UpdateCompanion { + final Value userId; + final Value username; + final Value displayName; + final Value nickName; + final Value avatarSvgCompressed; + final Value senderProfileCounter; + final Value accepted; + final Value deletedByUser; + final Value requested; + final Value blocked; + final Value verified; + final Value accountDeleted; + final Value createdAt; + final Value userDiscoveryVersion; + final Value userDiscoveryExcluded; + final Value mediaSendCounter; + final Value mediaReceivedCounter; + const ContactsCompanion({ + this.userId = const Value.absent(), + this.username = const Value.absent(), + this.displayName = const Value.absent(), + this.nickName = const Value.absent(), + this.avatarSvgCompressed = const Value.absent(), + this.senderProfileCounter = const Value.absent(), + this.accepted = const Value.absent(), + this.deletedByUser = const Value.absent(), + this.requested = const Value.absent(), + this.blocked = const Value.absent(), + this.verified = const Value.absent(), + this.accountDeleted = const Value.absent(), + this.createdAt = const Value.absent(), + this.userDiscoveryVersion = const Value.absent(), + this.userDiscoveryExcluded = const Value.absent(), + this.mediaSendCounter = const Value.absent(), + this.mediaReceivedCounter = const Value.absent(), + }); + ContactsCompanion.insert({ + this.userId = const Value.absent(), + required String username, + this.displayName = const Value.absent(), + this.nickName = const Value.absent(), + this.avatarSvgCompressed = const Value.absent(), + this.senderProfileCounter = const Value.absent(), + this.accepted = const Value.absent(), + this.deletedByUser = const Value.absent(), + this.requested = const Value.absent(), + this.blocked = const Value.absent(), + this.verified = const Value.absent(), + this.accountDeleted = const Value.absent(), + this.createdAt = const Value.absent(), + this.userDiscoveryVersion = const Value.absent(), + this.userDiscoveryExcluded = const Value.absent(), + this.mediaSendCounter = const Value.absent(), + this.mediaReceivedCounter = const Value.absent(), + }) : username = Value(username); + static Insertable custom({ + Expression? userId, + Expression? username, + Expression? displayName, + Expression? nickName, + Expression? avatarSvgCompressed, + Expression? senderProfileCounter, + Expression? accepted, + Expression? deletedByUser, + Expression? requested, + Expression? blocked, + Expression? verified, + Expression? accountDeleted, + Expression? createdAt, + Expression? userDiscoveryVersion, + Expression? userDiscoveryExcluded, + Expression? mediaSendCounter, + Expression? mediaReceivedCounter, + }) { + 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 (avatarSvgCompressed != null) + 'avatar_svg_compressed': avatarSvgCompressed, + if (senderProfileCounter != null) + 'sender_profile_counter': senderProfileCounter, + if (accepted != null) 'accepted': accepted, + if (deletedByUser != null) 'deleted_by_user': deletedByUser, + if (requested != null) 'requested': requested, + if (blocked != null) 'blocked': blocked, + if (verified != null) 'verified': verified, + if (accountDeleted != null) 'account_deleted': accountDeleted, + if (createdAt != null) 'created_at': createdAt, + if (userDiscoveryVersion != null) + 'user_discovery_version': userDiscoveryVersion, + if (userDiscoveryExcluded != null) + 'user_discovery_excluded': userDiscoveryExcluded, + if (mediaSendCounter != null) 'media_send_counter': mediaSendCounter, + if (mediaReceivedCounter != null) + 'media_received_counter': mediaReceivedCounter, + }); + } + + ContactsCompanion copyWith({ + Value? userId, + Value? username, + Value? displayName, + Value? nickName, + Value? avatarSvgCompressed, + Value? senderProfileCounter, + Value? accepted, + Value? deletedByUser, + Value? requested, + Value? blocked, + Value? verified, + Value? accountDeleted, + Value? createdAt, + Value? userDiscoveryVersion, + Value? userDiscoveryExcluded, + Value? mediaSendCounter, + Value? mediaReceivedCounter, + }) { + return ContactsCompanion( + userId: userId ?? this.userId, + username: username ?? this.username, + displayName: displayName ?? this.displayName, + nickName: nickName ?? this.nickName, + avatarSvgCompressed: avatarSvgCompressed ?? this.avatarSvgCompressed, + senderProfileCounter: senderProfileCounter ?? this.senderProfileCounter, + accepted: accepted ?? this.accepted, + deletedByUser: deletedByUser ?? this.deletedByUser, + requested: requested ?? this.requested, + blocked: blocked ?? this.blocked, + verified: verified ?? this.verified, + accountDeleted: accountDeleted ?? this.accountDeleted, + createdAt: createdAt ?? this.createdAt, + userDiscoveryVersion: userDiscoveryVersion ?? this.userDiscoveryVersion, + userDiscoveryExcluded: + userDiscoveryExcluded ?? this.userDiscoveryExcluded, + mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter, + mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter, + ); + } + + @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 (avatarSvgCompressed.present) { + map['avatar_svg_compressed'] = Variable( + avatarSvgCompressed.value, + ); + } + if (senderProfileCounter.present) { + map['sender_profile_counter'] = Variable(senderProfileCounter.value); + } + if (accepted.present) { + map['accepted'] = Variable(accepted.value); + } + if (deletedByUser.present) { + map['deleted_by_user'] = Variable(deletedByUser.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 (accountDeleted.present) { + map['account_deleted'] = Variable(accountDeleted.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (userDiscoveryVersion.present) { + map['user_discovery_version'] = Variable( + userDiscoveryVersion.value, + ); + } + if (userDiscoveryExcluded.present) { + map['user_discovery_excluded'] = Variable( + userDiscoveryExcluded.value, + ); + } + if (mediaSendCounter.present) { + map['media_send_counter'] = Variable(mediaSendCounter.value); + } + if (mediaReceivedCounter.present) { + map['media_received_counter'] = Variable(mediaReceivedCounter.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ContactsCompanion(') + ..write('userId: $userId, ') + ..write('username: $username, ') + ..write('displayName: $displayName, ') + ..write('nickName: $nickName, ') + ..write('avatarSvgCompressed: $avatarSvgCompressed, ') + ..write('senderProfileCounter: $senderProfileCounter, ') + ..write('accepted: $accepted, ') + ..write('deletedByUser: $deletedByUser, ') + ..write('requested: $requested, ') + ..write('blocked: $blocked, ') + ..write('verified: $verified, ') + ..write('accountDeleted: $accountDeleted, ') + ..write('createdAt: $createdAt, ') + ..write('userDiscoveryVersion: $userDiscoveryVersion, ') + ..write('userDiscoveryExcluded: $userDiscoveryExcluded, ') + ..write('mediaSendCounter: $mediaSendCounter, ') + ..write('mediaReceivedCounter: $mediaReceivedCounter') + ..write(')')) + .toString(); + } +} + +class Groups extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Groups(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isGroupAdmin = GeneratedColumn( + 'is_group_admin', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_group_admin IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn isDirectChat = GeneratedColumn( + 'is_direct_chat', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_direct_chat IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn pinned = GeneratedColumn( + 'pinned', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (pinned IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn archived = GeneratedColumn( + 'archived', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (archived IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn joinedGroup = GeneratedColumn( + 'joined_group', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (joined_group IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn leftGroup = GeneratedColumn( + 'left_group', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (left_group IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deletedContent = GeneratedColumn( + 'deleted_content', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (deleted_content IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stateVersionId = GeneratedColumn( + 'state_version_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stateEncryptionKey = + GeneratedColumn( + 'state_encryption_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn myGroupPrivateKey = + GeneratedColumn( + 'my_group_private_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn groupName = GeneratedColumn( + 'group_name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn draftMessage = GeneratedColumn( + 'draft_message', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn totalMediaCounter = GeneratedColumn( + 'total_media_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn alsoBestFriend = GeneratedColumn( + 'also_best_friend', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (also_best_friend IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn deleteMessagesAfterMilliseconds = + GeneratedColumn( + 'delete_messages_after_milliseconds', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 86400000', + defaultValue: const CustomExpression('86400000'), + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn lastMessageSend = GeneratedColumn( + 'last_message_send', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessageReceived = GeneratedColumn( + 'last_message_received', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastFlameCounterChange = GeneratedColumn( + 'last_flame_counter_change', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastFlameSync = GeneratedColumn( + 'last_flame_sync', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn flameCounter = GeneratedColumn( + 'flame_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn maxFlameCounter = GeneratedColumn( + 'max_flame_counter', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn maxFlameCounterFrom = GeneratedColumn( + 'max_flame_counter_from', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessageExchange = GeneratedColumn( + 'last_message_exchange', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupId, + isGroupAdmin, + isDirectChat, + pinned, + archived, + joinedGroup, + leftGroup, + deletedContent, + stateVersionId, + stateEncryptionKey, + myGroupPrivateKey, + groupName, + draftMessage, + totalMediaCounter, + alsoBestFriend, + deleteMessagesAfterMilliseconds, + createdAt, + lastMessageSend, + lastMessageReceived, + lastFlameCounterChange, + lastFlameSync, + flameCounter, + maxFlameCounter, + maxFlameCounterFrom, + lastMessageExchange, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'groups'; + @override + Set get $primaryKey => {groupId}; + @override + GroupsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupsData( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + isGroupAdmin: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_group_admin'], + )!, + isDirectChat: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_direct_chat'], + )!, + pinned: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}pinned'], + )!, + archived: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}archived'], + )!, + joinedGroup: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}joined_group'], + )!, + leftGroup: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}left_group'], + )!, + deletedContent: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}deleted_content'], + )!, + stateVersionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}state_version_id'], + )!, + stateEncryptionKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}state_encryption_key'], + ), + myGroupPrivateKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}my_group_private_key'], + ), + groupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_name'], + )!, + draftMessage: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}draft_message'], + ), + totalMediaCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}total_media_counter'], + )!, + alsoBestFriend: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}also_best_friend'], + )!, + deleteMessagesAfterMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}delete_messages_after_milliseconds'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + lastMessageSend: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_send'], + ), + lastMessageReceived: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_received'], + ), + lastFlameCounterChange: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_flame_counter_change'], + ), + lastFlameSync: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_flame_sync'], + ), + flameCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}flame_counter'], + )!, + maxFlameCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}max_flame_counter'], + )!, + maxFlameCounterFrom: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}max_flame_counter_from'], + ), + lastMessageExchange: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message_exchange'], + )!, + ); + } + + @override + Groups createAlias(String alias) { + return Groups(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(group_id)']; + @override + bool get dontWriteConstraints => true; +} + +class GroupsData extends DataClass implements Insertable { + final String groupId; + final int isGroupAdmin; + final int isDirectChat; + final int pinned; + final int archived; + final int joinedGroup; + final int leftGroup; + final int deletedContent; + final int stateVersionId; + final i2.Uint8List? stateEncryptionKey; + final i2.Uint8List? myGroupPrivateKey; + final String groupName; + final String? draftMessage; + final int totalMediaCounter; + final int alsoBestFriend; + final int deleteMessagesAfterMilliseconds; + final int createdAt; + final int? lastMessageSend; + final int? lastMessageReceived; + final int? lastFlameCounterChange; + final int? lastFlameSync; + final int flameCounter; + final int maxFlameCounter; + final int? maxFlameCounterFrom; + final int lastMessageExchange; + const GroupsData({ + required this.groupId, + required this.isGroupAdmin, + required this.isDirectChat, + required this.pinned, + required this.archived, + required this.joinedGroup, + required this.leftGroup, + required this.deletedContent, + required this.stateVersionId, + this.stateEncryptionKey, + this.myGroupPrivateKey, + required this.groupName, + this.draftMessage, + required this.totalMediaCounter, + required this.alsoBestFriend, + required this.deleteMessagesAfterMilliseconds, + required this.createdAt, + this.lastMessageSend, + this.lastMessageReceived, + this.lastFlameCounterChange, + this.lastFlameSync, + required this.flameCounter, + required this.maxFlameCounter, + this.maxFlameCounterFrom, + required this.lastMessageExchange, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['is_group_admin'] = Variable(isGroupAdmin); + map['is_direct_chat'] = Variable(isDirectChat); + map['pinned'] = Variable(pinned); + map['archived'] = Variable(archived); + map['joined_group'] = Variable(joinedGroup); + map['left_group'] = Variable(leftGroup); + map['deleted_content'] = Variable(deletedContent); + map['state_version_id'] = Variable(stateVersionId); + if (!nullToAbsent || stateEncryptionKey != null) { + map['state_encryption_key'] = Variable(stateEncryptionKey); + } + if (!nullToAbsent || myGroupPrivateKey != null) { + map['my_group_private_key'] = Variable(myGroupPrivateKey); + } + map['group_name'] = Variable(groupName); + if (!nullToAbsent || draftMessage != null) { + map['draft_message'] = Variable(draftMessage); + } + map['total_media_counter'] = Variable(totalMediaCounter); + map['also_best_friend'] = Variable(alsoBestFriend); + map['delete_messages_after_milliseconds'] = Variable( + deleteMessagesAfterMilliseconds, + ); + map['created_at'] = Variable(createdAt); + 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['flame_counter'] = Variable(flameCounter); + map['max_flame_counter'] = Variable(maxFlameCounter); + if (!nullToAbsent || maxFlameCounterFrom != null) { + map['max_flame_counter_from'] = Variable(maxFlameCounterFrom); + } + map['last_message_exchange'] = Variable(lastMessageExchange); + return map; + } + + GroupsCompanion toCompanion(bool nullToAbsent) { + return GroupsCompanion( + groupId: Value(groupId), + isGroupAdmin: Value(isGroupAdmin), + isDirectChat: Value(isDirectChat), + pinned: Value(pinned), + archived: Value(archived), + joinedGroup: Value(joinedGroup), + leftGroup: Value(leftGroup), + deletedContent: Value(deletedContent), + stateVersionId: Value(stateVersionId), + stateEncryptionKey: stateEncryptionKey == null && nullToAbsent + ? const Value.absent() + : Value(stateEncryptionKey), + myGroupPrivateKey: myGroupPrivateKey == null && nullToAbsent + ? const Value.absent() + : Value(myGroupPrivateKey), + groupName: Value(groupName), + draftMessage: draftMessage == null && nullToAbsent + ? const Value.absent() + : Value(draftMessage), + totalMediaCounter: Value(totalMediaCounter), + alsoBestFriend: Value(alsoBestFriend), + deleteMessagesAfterMilliseconds: Value(deleteMessagesAfterMilliseconds), + createdAt: Value(createdAt), + 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), + flameCounter: Value(flameCounter), + maxFlameCounter: Value(maxFlameCounter), + maxFlameCounterFrom: maxFlameCounterFrom == null && nullToAbsent + ? const Value.absent() + : Value(maxFlameCounterFrom), + lastMessageExchange: Value(lastMessageExchange), + ); + } + + factory GroupsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupsData( + groupId: serializer.fromJson(json['groupId']), + isGroupAdmin: serializer.fromJson(json['isGroupAdmin']), + isDirectChat: serializer.fromJson(json['isDirectChat']), + pinned: serializer.fromJson(json['pinned']), + archived: serializer.fromJson(json['archived']), + joinedGroup: serializer.fromJson(json['joinedGroup']), + leftGroup: serializer.fromJson(json['leftGroup']), + deletedContent: serializer.fromJson(json['deletedContent']), + stateVersionId: serializer.fromJson(json['stateVersionId']), + stateEncryptionKey: serializer.fromJson( + json['stateEncryptionKey'], + ), + myGroupPrivateKey: serializer.fromJson( + json['myGroupPrivateKey'], + ), + groupName: serializer.fromJson(json['groupName']), + draftMessage: serializer.fromJson(json['draftMessage']), + totalMediaCounter: serializer.fromJson(json['totalMediaCounter']), + alsoBestFriend: serializer.fromJson(json['alsoBestFriend']), + deleteMessagesAfterMilliseconds: serializer.fromJson( + json['deleteMessagesAfterMilliseconds'], + ), + createdAt: serializer.fromJson(json['createdAt']), + lastMessageSend: serializer.fromJson(json['lastMessageSend']), + lastMessageReceived: serializer.fromJson( + json['lastMessageReceived'], + ), + lastFlameCounterChange: serializer.fromJson( + json['lastFlameCounterChange'], + ), + lastFlameSync: serializer.fromJson(json['lastFlameSync']), + flameCounter: serializer.fromJson(json['flameCounter']), + maxFlameCounter: serializer.fromJson(json['maxFlameCounter']), + maxFlameCounterFrom: serializer.fromJson( + json['maxFlameCounterFrom'], + ), + lastMessageExchange: serializer.fromJson( + json['lastMessageExchange'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'isGroupAdmin': serializer.toJson(isGroupAdmin), + 'isDirectChat': serializer.toJson(isDirectChat), + 'pinned': serializer.toJson(pinned), + 'archived': serializer.toJson(archived), + 'joinedGroup': serializer.toJson(joinedGroup), + 'leftGroup': serializer.toJson(leftGroup), + 'deletedContent': serializer.toJson(deletedContent), + 'stateVersionId': serializer.toJson(stateVersionId), + 'stateEncryptionKey': serializer.toJson( + stateEncryptionKey, + ), + 'myGroupPrivateKey': serializer.toJson(myGroupPrivateKey), + 'groupName': serializer.toJson(groupName), + 'draftMessage': serializer.toJson(draftMessage), + 'totalMediaCounter': serializer.toJson(totalMediaCounter), + 'alsoBestFriend': serializer.toJson(alsoBestFriend), + 'deleteMessagesAfterMilliseconds': serializer.toJson( + deleteMessagesAfterMilliseconds, + ), + 'createdAt': serializer.toJson(createdAt), + 'lastMessageSend': serializer.toJson(lastMessageSend), + 'lastMessageReceived': serializer.toJson(lastMessageReceived), + 'lastFlameCounterChange': serializer.toJson(lastFlameCounterChange), + 'lastFlameSync': serializer.toJson(lastFlameSync), + 'flameCounter': serializer.toJson(flameCounter), + 'maxFlameCounter': serializer.toJson(maxFlameCounter), + 'maxFlameCounterFrom': serializer.toJson(maxFlameCounterFrom), + 'lastMessageExchange': serializer.toJson(lastMessageExchange), + }; + } + + GroupsData copyWith({ + String? groupId, + int? isGroupAdmin, + int? isDirectChat, + int? pinned, + int? archived, + int? joinedGroup, + int? leftGroup, + int? deletedContent, + int? stateVersionId, + Value stateEncryptionKey = const Value.absent(), + Value myGroupPrivateKey = const Value.absent(), + String? groupName, + Value draftMessage = const Value.absent(), + int? totalMediaCounter, + int? alsoBestFriend, + int? deleteMessagesAfterMilliseconds, + int? createdAt, + Value lastMessageSend = const Value.absent(), + Value lastMessageReceived = const Value.absent(), + Value lastFlameCounterChange = const Value.absent(), + Value lastFlameSync = const Value.absent(), + int? flameCounter, + int? maxFlameCounter, + Value maxFlameCounterFrom = const Value.absent(), + int? lastMessageExchange, + }) => GroupsData( + groupId: groupId ?? this.groupId, + isGroupAdmin: isGroupAdmin ?? this.isGroupAdmin, + isDirectChat: isDirectChat ?? this.isDirectChat, + pinned: pinned ?? this.pinned, + archived: archived ?? this.archived, + joinedGroup: joinedGroup ?? this.joinedGroup, + leftGroup: leftGroup ?? this.leftGroup, + deletedContent: deletedContent ?? this.deletedContent, + stateVersionId: stateVersionId ?? this.stateVersionId, + stateEncryptionKey: stateEncryptionKey.present + ? stateEncryptionKey.value + : this.stateEncryptionKey, + myGroupPrivateKey: myGroupPrivateKey.present + ? myGroupPrivateKey.value + : this.myGroupPrivateKey, + groupName: groupName ?? this.groupName, + draftMessage: draftMessage.present ? draftMessage.value : this.draftMessage, + totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter, + alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + deleteMessagesAfterMilliseconds ?? this.deleteMessagesAfterMilliseconds, + createdAt: createdAt ?? this.createdAt, + 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, + flameCounter: flameCounter ?? this.flameCounter, + maxFlameCounter: maxFlameCounter ?? this.maxFlameCounter, + maxFlameCounterFrom: maxFlameCounterFrom.present + ? maxFlameCounterFrom.value + : this.maxFlameCounterFrom, + lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, + ); + GroupsData copyWithCompanion(GroupsCompanion data) { + return GroupsData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + isGroupAdmin: data.isGroupAdmin.present + ? data.isGroupAdmin.value + : this.isGroupAdmin, + isDirectChat: data.isDirectChat.present + ? data.isDirectChat.value + : this.isDirectChat, + pinned: data.pinned.present ? data.pinned.value : this.pinned, + archived: data.archived.present ? data.archived.value : this.archived, + joinedGroup: data.joinedGroup.present + ? data.joinedGroup.value + : this.joinedGroup, + leftGroup: data.leftGroup.present ? data.leftGroup.value : this.leftGroup, + deletedContent: data.deletedContent.present + ? data.deletedContent.value + : this.deletedContent, + stateVersionId: data.stateVersionId.present + ? data.stateVersionId.value + : this.stateVersionId, + stateEncryptionKey: data.stateEncryptionKey.present + ? data.stateEncryptionKey.value + : this.stateEncryptionKey, + myGroupPrivateKey: data.myGroupPrivateKey.present + ? data.myGroupPrivateKey.value + : this.myGroupPrivateKey, + groupName: data.groupName.present ? data.groupName.value : this.groupName, + draftMessage: data.draftMessage.present + ? data.draftMessage.value + : this.draftMessage, + totalMediaCounter: data.totalMediaCounter.present + ? data.totalMediaCounter.value + : this.totalMediaCounter, + alsoBestFriend: data.alsoBestFriend.present + ? data.alsoBestFriend.value + : this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + data.deleteMessagesAfterMilliseconds.present + ? data.deleteMessagesAfterMilliseconds.value + : this.deleteMessagesAfterMilliseconds, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + 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, + flameCounter: data.flameCounter.present + ? data.flameCounter.value + : this.flameCounter, + maxFlameCounter: data.maxFlameCounter.present + ? data.maxFlameCounter.value + : this.maxFlameCounter, + maxFlameCounterFrom: data.maxFlameCounterFrom.present + ? data.maxFlameCounterFrom.value + : this.maxFlameCounterFrom, + lastMessageExchange: data.lastMessageExchange.present + ? data.lastMessageExchange.value + : this.lastMessageExchange, + ); + } + + @override + String toString() { + return (StringBuffer('GroupsData(') + ..write('groupId: $groupId, ') + ..write('isGroupAdmin: $isGroupAdmin, ') + ..write('isDirectChat: $isDirectChat, ') + ..write('pinned: $pinned, ') + ..write('archived: $archived, ') + ..write('joinedGroup: $joinedGroup, ') + ..write('leftGroup: $leftGroup, ') + ..write('deletedContent: $deletedContent, ') + ..write('stateVersionId: $stateVersionId, ') + ..write('stateEncryptionKey: $stateEncryptionKey, ') + ..write('myGroupPrivateKey: $myGroupPrivateKey, ') + ..write('groupName: $groupName, ') + ..write('draftMessage: $draftMessage, ') + ..write('totalMediaCounter: $totalMediaCounter, ') + ..write('alsoBestFriend: $alsoBestFriend, ') + ..write( + 'deleteMessagesAfterMilliseconds: $deleteMessagesAfterMilliseconds, ', + ) + ..write('createdAt: $createdAt, ') + ..write('lastMessageSend: $lastMessageSend, ') + ..write('lastMessageReceived: $lastMessageReceived, ') + ..write('lastFlameCounterChange: $lastFlameCounterChange, ') + ..write('lastFlameSync: $lastFlameSync, ') + ..write('flameCounter: $flameCounter, ') + ..write('maxFlameCounter: $maxFlameCounter, ') + ..write('maxFlameCounterFrom: $maxFlameCounterFrom, ') + ..write('lastMessageExchange: $lastMessageExchange') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hashAll([ + groupId, + isGroupAdmin, + isDirectChat, + pinned, + archived, + joinedGroup, + leftGroup, + deletedContent, + stateVersionId, + $driftBlobEquality.hash(stateEncryptionKey), + $driftBlobEquality.hash(myGroupPrivateKey), + groupName, + draftMessage, + totalMediaCounter, + alsoBestFriend, + deleteMessagesAfterMilliseconds, + createdAt, + lastMessageSend, + lastMessageReceived, + lastFlameCounterChange, + lastFlameSync, + flameCounter, + maxFlameCounter, + maxFlameCounterFrom, + lastMessageExchange, + ]); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupsData && + other.groupId == this.groupId && + other.isGroupAdmin == this.isGroupAdmin && + other.isDirectChat == this.isDirectChat && + other.pinned == this.pinned && + other.archived == this.archived && + other.joinedGroup == this.joinedGroup && + other.leftGroup == this.leftGroup && + other.deletedContent == this.deletedContent && + other.stateVersionId == this.stateVersionId && + $driftBlobEquality.equals( + other.stateEncryptionKey, + this.stateEncryptionKey, + ) && + $driftBlobEquality.equals( + other.myGroupPrivateKey, + this.myGroupPrivateKey, + ) && + other.groupName == this.groupName && + other.draftMessage == this.draftMessage && + other.totalMediaCounter == this.totalMediaCounter && + other.alsoBestFriend == this.alsoBestFriend && + other.deleteMessagesAfterMilliseconds == + this.deleteMessagesAfterMilliseconds && + other.createdAt == this.createdAt && + other.lastMessageSend == this.lastMessageSend && + other.lastMessageReceived == this.lastMessageReceived && + other.lastFlameCounterChange == this.lastFlameCounterChange && + other.lastFlameSync == this.lastFlameSync && + other.flameCounter == this.flameCounter && + other.maxFlameCounter == this.maxFlameCounter && + other.maxFlameCounterFrom == this.maxFlameCounterFrom && + other.lastMessageExchange == this.lastMessageExchange); +} + +class GroupsCompanion extends UpdateCompanion { + final Value groupId; + final Value isGroupAdmin; + final Value isDirectChat; + final Value pinned; + final Value archived; + final Value joinedGroup; + final Value leftGroup; + final Value deletedContent; + final Value stateVersionId; + final Value stateEncryptionKey; + final Value myGroupPrivateKey; + final Value groupName; + final Value draftMessage; + final Value totalMediaCounter; + final Value alsoBestFriend; + final Value deleteMessagesAfterMilliseconds; + final Value createdAt; + final Value lastMessageSend; + final Value lastMessageReceived; + final Value lastFlameCounterChange; + final Value lastFlameSync; + final Value flameCounter; + final Value maxFlameCounter; + final Value maxFlameCounterFrom; + final Value lastMessageExchange; + final Value rowid; + const GroupsCompanion({ + this.groupId = const Value.absent(), + this.isGroupAdmin = const Value.absent(), + this.isDirectChat = const Value.absent(), + this.pinned = const Value.absent(), + this.archived = const Value.absent(), + this.joinedGroup = const Value.absent(), + this.leftGroup = const Value.absent(), + this.deletedContent = const Value.absent(), + this.stateVersionId = const Value.absent(), + this.stateEncryptionKey = const Value.absent(), + this.myGroupPrivateKey = const Value.absent(), + this.groupName = const Value.absent(), + this.draftMessage = const Value.absent(), + this.totalMediaCounter = const Value.absent(), + this.alsoBestFriend = const Value.absent(), + this.deleteMessagesAfterMilliseconds = const Value.absent(), + this.createdAt = const Value.absent(), + this.lastMessageSend = const Value.absent(), + this.lastMessageReceived = const Value.absent(), + this.lastFlameCounterChange = const Value.absent(), + this.lastFlameSync = const Value.absent(), + this.flameCounter = const Value.absent(), + this.maxFlameCounter = const Value.absent(), + this.maxFlameCounterFrom = const Value.absent(), + this.lastMessageExchange = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupsCompanion.insert({ + required String groupId, + this.isGroupAdmin = const Value.absent(), + this.isDirectChat = const Value.absent(), + this.pinned = const Value.absent(), + this.archived = const Value.absent(), + this.joinedGroup = const Value.absent(), + this.leftGroup = const Value.absent(), + this.deletedContent = const Value.absent(), + this.stateVersionId = const Value.absent(), + this.stateEncryptionKey = const Value.absent(), + this.myGroupPrivateKey = const Value.absent(), + required String groupName, + this.draftMessage = const Value.absent(), + this.totalMediaCounter = const Value.absent(), + this.alsoBestFriend = const Value.absent(), + this.deleteMessagesAfterMilliseconds = const Value.absent(), + this.createdAt = const Value.absent(), + this.lastMessageSend = const Value.absent(), + this.lastMessageReceived = const Value.absent(), + this.lastFlameCounterChange = const Value.absent(), + this.lastFlameSync = const Value.absent(), + this.flameCounter = const Value.absent(), + this.maxFlameCounter = const Value.absent(), + this.maxFlameCounterFrom = const Value.absent(), + this.lastMessageExchange = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + groupName = Value(groupName); + static Insertable custom({ + Expression? groupId, + Expression? isGroupAdmin, + Expression? isDirectChat, + Expression? pinned, + Expression? archived, + Expression? joinedGroup, + Expression? leftGroup, + Expression? deletedContent, + Expression? stateVersionId, + Expression? stateEncryptionKey, + Expression? myGroupPrivateKey, + Expression? groupName, + Expression? draftMessage, + Expression? totalMediaCounter, + Expression? alsoBestFriend, + Expression? deleteMessagesAfterMilliseconds, + Expression? createdAt, + Expression? lastMessageSend, + Expression? lastMessageReceived, + Expression? lastFlameCounterChange, + Expression? lastFlameSync, + Expression? flameCounter, + Expression? maxFlameCounter, + Expression? maxFlameCounterFrom, + Expression? lastMessageExchange, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (isGroupAdmin != null) 'is_group_admin': isGroupAdmin, + if (isDirectChat != null) 'is_direct_chat': isDirectChat, + if (pinned != null) 'pinned': pinned, + if (archived != null) 'archived': archived, + if (joinedGroup != null) 'joined_group': joinedGroup, + if (leftGroup != null) 'left_group': leftGroup, + if (deletedContent != null) 'deleted_content': deletedContent, + if (stateVersionId != null) 'state_version_id': stateVersionId, + if (stateEncryptionKey != null) + 'state_encryption_key': stateEncryptionKey, + if (myGroupPrivateKey != null) 'my_group_private_key': myGroupPrivateKey, + if (groupName != null) 'group_name': groupName, + if (draftMessage != null) 'draft_message': draftMessage, + if (totalMediaCounter != null) 'total_media_counter': totalMediaCounter, + if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend, + if (deleteMessagesAfterMilliseconds != null) + 'delete_messages_after_milliseconds': deleteMessagesAfterMilliseconds, + if (createdAt != null) 'created_at': createdAt, + 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 (flameCounter != null) 'flame_counter': flameCounter, + if (maxFlameCounter != null) 'max_flame_counter': maxFlameCounter, + if (maxFlameCounterFrom != null) + 'max_flame_counter_from': maxFlameCounterFrom, + if (lastMessageExchange != null) + 'last_message_exchange': lastMessageExchange, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupsCompanion copyWith({ + Value? groupId, + Value? isGroupAdmin, + Value? isDirectChat, + Value? pinned, + Value? archived, + Value? joinedGroup, + Value? leftGroup, + Value? deletedContent, + Value? stateVersionId, + Value? stateEncryptionKey, + Value? myGroupPrivateKey, + Value? groupName, + Value? draftMessage, + Value? totalMediaCounter, + Value? alsoBestFriend, + Value? deleteMessagesAfterMilliseconds, + Value? createdAt, + Value? lastMessageSend, + Value? lastMessageReceived, + Value? lastFlameCounterChange, + Value? lastFlameSync, + Value? flameCounter, + Value? maxFlameCounter, + Value? maxFlameCounterFrom, + Value? lastMessageExchange, + Value? rowid, + }) { + return GroupsCompanion( + groupId: groupId ?? this.groupId, + isGroupAdmin: isGroupAdmin ?? this.isGroupAdmin, + isDirectChat: isDirectChat ?? this.isDirectChat, + pinned: pinned ?? this.pinned, + archived: archived ?? this.archived, + joinedGroup: joinedGroup ?? this.joinedGroup, + leftGroup: leftGroup ?? this.leftGroup, + deletedContent: deletedContent ?? this.deletedContent, + stateVersionId: stateVersionId ?? this.stateVersionId, + stateEncryptionKey: stateEncryptionKey ?? this.stateEncryptionKey, + myGroupPrivateKey: myGroupPrivateKey ?? this.myGroupPrivateKey, + groupName: groupName ?? this.groupName, + draftMessage: draftMessage ?? this.draftMessage, + totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter, + alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, + deleteMessagesAfterMilliseconds: + deleteMessagesAfterMilliseconds ?? + this.deleteMessagesAfterMilliseconds, + createdAt: createdAt ?? this.createdAt, + lastMessageSend: lastMessageSend ?? this.lastMessageSend, + lastMessageReceived: lastMessageReceived ?? this.lastMessageReceived, + lastFlameCounterChange: + lastFlameCounterChange ?? this.lastFlameCounterChange, + lastFlameSync: lastFlameSync ?? this.lastFlameSync, + flameCounter: flameCounter ?? this.flameCounter, + maxFlameCounter: maxFlameCounter ?? this.maxFlameCounter, + maxFlameCounterFrom: maxFlameCounterFrom ?? this.maxFlameCounterFrom, + lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (isGroupAdmin.present) { + map['is_group_admin'] = Variable(isGroupAdmin.value); + } + if (isDirectChat.present) { + map['is_direct_chat'] = Variable(isDirectChat.value); + } + if (pinned.present) { + map['pinned'] = Variable(pinned.value); + } + if (archived.present) { + map['archived'] = Variable(archived.value); + } + if (joinedGroup.present) { + map['joined_group'] = Variable(joinedGroup.value); + } + if (leftGroup.present) { + map['left_group'] = Variable(leftGroup.value); + } + if (deletedContent.present) { + map['deleted_content'] = Variable(deletedContent.value); + } + if (stateVersionId.present) { + map['state_version_id'] = Variable(stateVersionId.value); + } + if (stateEncryptionKey.present) { + map['state_encryption_key'] = Variable( + stateEncryptionKey.value, + ); + } + if (myGroupPrivateKey.present) { + map['my_group_private_key'] = Variable( + myGroupPrivateKey.value, + ); + } + if (groupName.present) { + map['group_name'] = Variable(groupName.value); + } + if (draftMessage.present) { + map['draft_message'] = Variable(draftMessage.value); + } + if (totalMediaCounter.present) { + map['total_media_counter'] = Variable(totalMediaCounter.value); + } + if (alsoBestFriend.present) { + map['also_best_friend'] = Variable(alsoBestFriend.value); + } + if (deleteMessagesAfterMilliseconds.present) { + map['delete_messages_after_milliseconds'] = Variable( + deleteMessagesAfterMilliseconds.value, + ); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.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 (flameCounter.present) { + map['flame_counter'] = Variable(flameCounter.value); + } + if (maxFlameCounter.present) { + map['max_flame_counter'] = Variable(maxFlameCounter.value); + } + if (maxFlameCounterFrom.present) { + map['max_flame_counter_from'] = Variable(maxFlameCounterFrom.value); + } + if (lastMessageExchange.present) { + map['last_message_exchange'] = Variable(lastMessageExchange.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GroupsCompanion(') + ..write('groupId: $groupId, ') + ..write('isGroupAdmin: $isGroupAdmin, ') + ..write('isDirectChat: $isDirectChat, ') + ..write('pinned: $pinned, ') + ..write('archived: $archived, ') + ..write('joinedGroup: $joinedGroup, ') + ..write('leftGroup: $leftGroup, ') + ..write('deletedContent: $deletedContent, ') + ..write('stateVersionId: $stateVersionId, ') + ..write('stateEncryptionKey: $stateEncryptionKey, ') + ..write('myGroupPrivateKey: $myGroupPrivateKey, ') + ..write('groupName: $groupName, ') + ..write('draftMessage: $draftMessage, ') + ..write('totalMediaCounter: $totalMediaCounter, ') + ..write('alsoBestFriend: $alsoBestFriend, ') + ..write( + 'deleteMessagesAfterMilliseconds: $deleteMessagesAfterMilliseconds, ', + ) + ..write('createdAt: $createdAt, ') + ..write('lastMessageSend: $lastMessageSend, ') + ..write('lastMessageReceived: $lastMessageReceived, ') + ..write('lastFlameCounterChange: $lastFlameCounterChange, ') + ..write('lastFlameSync: $lastFlameSync, ') + ..write('flameCounter: $flameCounter, ') + ..write('maxFlameCounter: $maxFlameCounter, ') + ..write('maxFlameCounterFrom: $maxFlameCounterFrom, ') + ..write('lastMessageExchange: $lastMessageExchange, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class MediaFiles extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MediaFiles(this.attachedDatabase, [this._alias]); + late final GeneratedColumn mediaId = GeneratedColumn( + 'media_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn uploadState = GeneratedColumn( + 'upload_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn downloadState = GeneratedColumn( + 'download_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn requiresAuthentication = GeneratedColumn( + 'requires_authentication', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (requires_authentication IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn stored = GeneratedColumn( + 'stored', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK ("stored" IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn isDraftMedia = GeneratedColumn( + 'is_draft_media', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_draft_media IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn preProgressingProcess = GeneratedColumn( + 'pre_progressing_process', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn reuploadRequestedBy = + GeneratedColumn( + 'reupload_requested_by', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn displayLimitInMilliseconds = + GeneratedColumn( + 'display_limit_in_milliseconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn removeAudio = GeneratedColumn( + 'remove_audio', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL CHECK (remove_audio IN (0, 1))', + ); + late final GeneratedColumn downloadToken = + GeneratedColumn( + 'download_token', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionKey = + GeneratedColumn( + 'encryption_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionMac = + GeneratedColumn( + 'encryption_mac', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn encryptionNonce = + GeneratedColumn( + 'encryption_nonce', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn storedFileHash = + GeneratedColumn( + 'stored_file_hash', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + mediaId, + type, + uploadState, + downloadState, + requiresAuthentication, + stored, + isDraftMedia, + preProgressingProcess, + reuploadRequestedBy, + displayLimitInMilliseconds, + removeAudio, + downloadToken, + encryptionKey, + encryptionMac, + encryptionNonce, + storedFileHash, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'media_files'; + @override + Set get $primaryKey => {mediaId}; + @override + MediaFilesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MediaFilesData( + mediaId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}media_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + uploadState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}upload_state'], + ), + downloadState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}download_state'], + ), + requiresAuthentication: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}requires_authentication'], + )!, + stored: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}stored'], + )!, + isDraftMedia: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_draft_media'], + )!, + preProgressingProcess: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}pre_progressing_process'], + ), + reuploadRequestedBy: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}reupload_requested_by'], + ), + displayLimitInMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}display_limit_in_milliseconds'], + ), + removeAudio: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}remove_audio'], + ), + downloadToken: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}download_token'], + ), + encryptionKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_key'], + ), + encryptionMac: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_mac'], + ), + encryptionNonce: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}encryption_nonce'], + ), + storedFileHash: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}stored_file_hash'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + MediaFiles createAlias(String alias) { + return MediaFiles(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(media_id)']; + @override + bool get dontWriteConstraints => true; +} + +class MediaFilesData extends DataClass implements Insertable { + final String mediaId; + final String type; + final String? uploadState; + final String? downloadState; + final int requiresAuthentication; + final int stored; + final int isDraftMedia; + final int? preProgressingProcess; + final String? reuploadRequestedBy; + final int? displayLimitInMilliseconds; + final int? removeAudio; + final i2.Uint8List? downloadToken; + final i2.Uint8List? encryptionKey; + final i2.Uint8List? encryptionMac; + final i2.Uint8List? encryptionNonce; + final i2.Uint8List? storedFileHash; + final int createdAt; + const MediaFilesData({ + required this.mediaId, + required this.type, + this.uploadState, + this.downloadState, + required this.requiresAuthentication, + required this.stored, + required this.isDraftMedia, + this.preProgressingProcess, + this.reuploadRequestedBy, + this.displayLimitInMilliseconds, + this.removeAudio, + this.downloadToken, + this.encryptionKey, + this.encryptionMac, + this.encryptionNonce, + this.storedFileHash, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['media_id'] = Variable(mediaId); + map['type'] = Variable(type); + if (!nullToAbsent || uploadState != null) { + map['upload_state'] = Variable(uploadState); + } + if (!nullToAbsent || downloadState != null) { + map['download_state'] = Variable(downloadState); + } + map['requires_authentication'] = Variable(requiresAuthentication); + map['stored'] = Variable(stored); + map['is_draft_media'] = Variable(isDraftMedia); + if (!nullToAbsent || preProgressingProcess != null) { + map['pre_progressing_process'] = Variable(preProgressingProcess); + } + if (!nullToAbsent || reuploadRequestedBy != null) { + map['reupload_requested_by'] = Variable(reuploadRequestedBy); + } + if (!nullToAbsent || displayLimitInMilliseconds != null) { + map['display_limit_in_milliseconds'] = Variable( + displayLimitInMilliseconds, + ); + } + if (!nullToAbsent || removeAudio != null) { + map['remove_audio'] = Variable(removeAudio); + } + if (!nullToAbsent || downloadToken != null) { + map['download_token'] = Variable(downloadToken); + } + if (!nullToAbsent || encryptionKey != null) { + map['encryption_key'] = Variable(encryptionKey); + } + if (!nullToAbsent || encryptionMac != null) { + map['encryption_mac'] = Variable(encryptionMac); + } + if (!nullToAbsent || encryptionNonce != null) { + map['encryption_nonce'] = Variable(encryptionNonce); + } + if (!nullToAbsent || storedFileHash != null) { + map['stored_file_hash'] = Variable(storedFileHash); + } + map['created_at'] = Variable(createdAt); + return map; + } + + MediaFilesCompanion toCompanion(bool nullToAbsent) { + return MediaFilesCompanion( + mediaId: Value(mediaId), + type: Value(type), + uploadState: uploadState == null && nullToAbsent + ? const Value.absent() + : Value(uploadState), + downloadState: downloadState == null && nullToAbsent + ? const Value.absent() + : Value(downloadState), + requiresAuthentication: Value(requiresAuthentication), + stored: Value(stored), + isDraftMedia: Value(isDraftMedia), + preProgressingProcess: preProgressingProcess == null && nullToAbsent + ? const Value.absent() + : Value(preProgressingProcess), + reuploadRequestedBy: reuploadRequestedBy == null && nullToAbsent + ? const Value.absent() + : Value(reuploadRequestedBy), + displayLimitInMilliseconds: + displayLimitInMilliseconds == null && nullToAbsent + ? const Value.absent() + : Value(displayLimitInMilliseconds), + removeAudio: removeAudio == null && nullToAbsent + ? const Value.absent() + : Value(removeAudio), + downloadToken: downloadToken == null && nullToAbsent + ? const Value.absent() + : Value(downloadToken), + encryptionKey: encryptionKey == null && nullToAbsent + ? const Value.absent() + : Value(encryptionKey), + encryptionMac: encryptionMac == null && nullToAbsent + ? const Value.absent() + : Value(encryptionMac), + encryptionNonce: encryptionNonce == null && nullToAbsent + ? const Value.absent() + : Value(encryptionNonce), + storedFileHash: storedFileHash == null && nullToAbsent + ? const Value.absent() + : Value(storedFileHash), + createdAt: Value(createdAt), + ); + } + + factory MediaFilesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MediaFilesData( + mediaId: serializer.fromJson(json['mediaId']), + type: serializer.fromJson(json['type']), + uploadState: serializer.fromJson(json['uploadState']), + downloadState: serializer.fromJson(json['downloadState']), + requiresAuthentication: serializer.fromJson( + json['requiresAuthentication'], + ), + stored: serializer.fromJson(json['stored']), + isDraftMedia: serializer.fromJson(json['isDraftMedia']), + preProgressingProcess: serializer.fromJson( + json['preProgressingProcess'], + ), + reuploadRequestedBy: serializer.fromJson( + json['reuploadRequestedBy'], + ), + displayLimitInMilliseconds: serializer.fromJson( + json['displayLimitInMilliseconds'], + ), + removeAudio: serializer.fromJson(json['removeAudio']), + downloadToken: serializer.fromJson(json['downloadToken']), + encryptionKey: serializer.fromJson(json['encryptionKey']), + encryptionMac: serializer.fromJson(json['encryptionMac']), + encryptionNonce: serializer.fromJson( + json['encryptionNonce'], + ), + storedFileHash: serializer.fromJson( + json['storedFileHash'], + ), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'mediaId': serializer.toJson(mediaId), + 'type': serializer.toJson(type), + 'uploadState': serializer.toJson(uploadState), + 'downloadState': serializer.toJson(downloadState), + 'requiresAuthentication': serializer.toJson(requiresAuthentication), + 'stored': serializer.toJson(stored), + 'isDraftMedia': serializer.toJson(isDraftMedia), + 'preProgressingProcess': serializer.toJson(preProgressingProcess), + 'reuploadRequestedBy': serializer.toJson(reuploadRequestedBy), + 'displayLimitInMilliseconds': serializer.toJson( + displayLimitInMilliseconds, + ), + 'removeAudio': serializer.toJson(removeAudio), + 'downloadToken': serializer.toJson(downloadToken), + 'encryptionKey': serializer.toJson(encryptionKey), + 'encryptionMac': serializer.toJson(encryptionMac), + 'encryptionNonce': serializer.toJson(encryptionNonce), + 'storedFileHash': serializer.toJson(storedFileHash), + 'createdAt': serializer.toJson(createdAt), + }; + } + + MediaFilesData copyWith({ + String? mediaId, + String? type, + Value uploadState = const Value.absent(), + Value downloadState = const Value.absent(), + int? requiresAuthentication, + int? stored, + int? isDraftMedia, + Value preProgressingProcess = const Value.absent(), + Value reuploadRequestedBy = const Value.absent(), + Value displayLimitInMilliseconds = const Value.absent(), + Value removeAudio = const Value.absent(), + Value downloadToken = const Value.absent(), + Value encryptionKey = const Value.absent(), + Value encryptionMac = const Value.absent(), + Value encryptionNonce = const Value.absent(), + Value storedFileHash = const Value.absent(), + int? createdAt, + }) => MediaFilesData( + mediaId: mediaId ?? this.mediaId, + type: type ?? this.type, + uploadState: uploadState.present ? uploadState.value : this.uploadState, + downloadState: downloadState.present + ? downloadState.value + : this.downloadState, + requiresAuthentication: + requiresAuthentication ?? this.requiresAuthentication, + stored: stored ?? this.stored, + isDraftMedia: isDraftMedia ?? this.isDraftMedia, + preProgressingProcess: preProgressingProcess.present + ? preProgressingProcess.value + : this.preProgressingProcess, + reuploadRequestedBy: reuploadRequestedBy.present + ? reuploadRequestedBy.value + : this.reuploadRequestedBy, + displayLimitInMilliseconds: displayLimitInMilliseconds.present + ? displayLimitInMilliseconds.value + : this.displayLimitInMilliseconds, + removeAudio: removeAudio.present ? removeAudio.value : this.removeAudio, + downloadToken: downloadToken.present + ? downloadToken.value + : this.downloadToken, + encryptionKey: encryptionKey.present + ? encryptionKey.value + : this.encryptionKey, + encryptionMac: encryptionMac.present + ? encryptionMac.value + : this.encryptionMac, + encryptionNonce: encryptionNonce.present + ? encryptionNonce.value + : this.encryptionNonce, + storedFileHash: storedFileHash.present + ? storedFileHash.value + : this.storedFileHash, + createdAt: createdAt ?? this.createdAt, + ); + MediaFilesData copyWithCompanion(MediaFilesCompanion data) { + return MediaFilesData( + mediaId: data.mediaId.present ? data.mediaId.value : this.mediaId, + type: data.type.present ? data.type.value : this.type, + uploadState: data.uploadState.present + ? data.uploadState.value + : this.uploadState, + downloadState: data.downloadState.present + ? data.downloadState.value + : this.downloadState, + requiresAuthentication: data.requiresAuthentication.present + ? data.requiresAuthentication.value + : this.requiresAuthentication, + stored: data.stored.present ? data.stored.value : this.stored, + isDraftMedia: data.isDraftMedia.present + ? data.isDraftMedia.value + : this.isDraftMedia, + preProgressingProcess: data.preProgressingProcess.present + ? data.preProgressingProcess.value + : this.preProgressingProcess, + reuploadRequestedBy: data.reuploadRequestedBy.present + ? data.reuploadRequestedBy.value + : this.reuploadRequestedBy, + displayLimitInMilliseconds: data.displayLimitInMilliseconds.present + ? data.displayLimitInMilliseconds.value + : this.displayLimitInMilliseconds, + removeAudio: data.removeAudio.present + ? data.removeAudio.value + : this.removeAudio, + downloadToken: data.downloadToken.present + ? data.downloadToken.value + : this.downloadToken, + encryptionKey: data.encryptionKey.present + ? data.encryptionKey.value + : this.encryptionKey, + encryptionMac: data.encryptionMac.present + ? data.encryptionMac.value + : this.encryptionMac, + encryptionNonce: data.encryptionNonce.present + ? data.encryptionNonce.value + : this.encryptionNonce, + storedFileHash: data.storedFileHash.present + ? data.storedFileHash.value + : this.storedFileHash, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('MediaFilesData(') + ..write('mediaId: $mediaId, ') + ..write('type: $type, ') + ..write('uploadState: $uploadState, ') + ..write('downloadState: $downloadState, ') + ..write('requiresAuthentication: $requiresAuthentication, ') + ..write('stored: $stored, ') + ..write('isDraftMedia: $isDraftMedia, ') + ..write('preProgressingProcess: $preProgressingProcess, ') + ..write('reuploadRequestedBy: $reuploadRequestedBy, ') + ..write('displayLimitInMilliseconds: $displayLimitInMilliseconds, ') + ..write('removeAudio: $removeAudio, ') + ..write('downloadToken: $downloadToken, ') + ..write('encryptionKey: $encryptionKey, ') + ..write('encryptionMac: $encryptionMac, ') + ..write('encryptionNonce: $encryptionNonce, ') + ..write('storedFileHash: $storedFileHash, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + mediaId, + type, + uploadState, + downloadState, + requiresAuthentication, + stored, + isDraftMedia, + preProgressingProcess, + reuploadRequestedBy, + displayLimitInMilliseconds, + removeAudio, + $driftBlobEquality.hash(downloadToken), + $driftBlobEquality.hash(encryptionKey), + $driftBlobEquality.hash(encryptionMac), + $driftBlobEquality.hash(encryptionNonce), + $driftBlobEquality.hash(storedFileHash), + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MediaFilesData && + other.mediaId == this.mediaId && + other.type == this.type && + other.uploadState == this.uploadState && + other.downloadState == this.downloadState && + other.requiresAuthentication == this.requiresAuthentication && + other.stored == this.stored && + other.isDraftMedia == this.isDraftMedia && + other.preProgressingProcess == this.preProgressingProcess && + other.reuploadRequestedBy == this.reuploadRequestedBy && + other.displayLimitInMilliseconds == this.displayLimitInMilliseconds && + other.removeAudio == this.removeAudio && + $driftBlobEquality.equals(other.downloadToken, this.downloadToken) && + $driftBlobEquality.equals(other.encryptionKey, this.encryptionKey) && + $driftBlobEquality.equals(other.encryptionMac, this.encryptionMac) && + $driftBlobEquality.equals( + other.encryptionNonce, + this.encryptionNonce, + ) && + $driftBlobEquality.equals( + other.storedFileHash, + this.storedFileHash, + ) && + other.createdAt == this.createdAt); +} + +class MediaFilesCompanion extends UpdateCompanion { + final Value mediaId; + final Value type; + final Value uploadState; + final Value downloadState; + final Value requiresAuthentication; + final Value stored; + final Value isDraftMedia; + final Value preProgressingProcess; + final Value reuploadRequestedBy; + final Value displayLimitInMilliseconds; + final Value removeAudio; + final Value downloadToken; + final Value encryptionKey; + final Value encryptionMac; + final Value encryptionNonce; + final Value storedFileHash; + final Value createdAt; + final Value rowid; + const MediaFilesCompanion({ + this.mediaId = const Value.absent(), + this.type = const Value.absent(), + this.uploadState = const Value.absent(), + this.downloadState = const Value.absent(), + this.requiresAuthentication = const Value.absent(), + this.stored = const Value.absent(), + this.isDraftMedia = const Value.absent(), + this.preProgressingProcess = const Value.absent(), + this.reuploadRequestedBy = const Value.absent(), + this.displayLimitInMilliseconds = const Value.absent(), + this.removeAudio = const Value.absent(), + this.downloadToken = const Value.absent(), + this.encryptionKey = const Value.absent(), + this.encryptionMac = const Value.absent(), + this.encryptionNonce = const Value.absent(), + this.storedFileHash = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + MediaFilesCompanion.insert({ + required String mediaId, + required String type, + this.uploadState = const Value.absent(), + this.downloadState = const Value.absent(), + this.requiresAuthentication = const Value.absent(), + this.stored = const Value.absent(), + this.isDraftMedia = const Value.absent(), + this.preProgressingProcess = const Value.absent(), + this.reuploadRequestedBy = const Value.absent(), + this.displayLimitInMilliseconds = const Value.absent(), + this.removeAudio = const Value.absent(), + this.downloadToken = const Value.absent(), + this.encryptionKey = const Value.absent(), + this.encryptionMac = const Value.absent(), + this.encryptionNonce = const Value.absent(), + this.storedFileHash = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : mediaId = Value(mediaId), + type = Value(type); + static Insertable custom({ + Expression? mediaId, + Expression? type, + Expression? uploadState, + Expression? downloadState, + Expression? requiresAuthentication, + Expression? stored, + Expression? isDraftMedia, + Expression? preProgressingProcess, + Expression? reuploadRequestedBy, + Expression? displayLimitInMilliseconds, + Expression? removeAudio, + Expression? downloadToken, + Expression? encryptionKey, + Expression? encryptionMac, + Expression? encryptionNonce, + Expression? storedFileHash, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (mediaId != null) 'media_id': mediaId, + if (type != null) 'type': type, + if (uploadState != null) 'upload_state': uploadState, + if (downloadState != null) 'download_state': downloadState, + if (requiresAuthentication != null) + 'requires_authentication': requiresAuthentication, + if (stored != null) 'stored': stored, + if (isDraftMedia != null) 'is_draft_media': isDraftMedia, + if (preProgressingProcess != null) + 'pre_progressing_process': preProgressingProcess, + if (reuploadRequestedBy != null) + 'reupload_requested_by': reuploadRequestedBy, + if (displayLimitInMilliseconds != null) + 'display_limit_in_milliseconds': displayLimitInMilliseconds, + if (removeAudio != null) 'remove_audio': removeAudio, + if (downloadToken != null) 'download_token': downloadToken, + if (encryptionKey != null) 'encryption_key': encryptionKey, + if (encryptionMac != null) 'encryption_mac': encryptionMac, + if (encryptionNonce != null) 'encryption_nonce': encryptionNonce, + if (storedFileHash != null) 'stored_file_hash': storedFileHash, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + MediaFilesCompanion copyWith({ + Value? mediaId, + Value? type, + Value? uploadState, + Value? downloadState, + Value? requiresAuthentication, + Value? stored, + Value? isDraftMedia, + Value? preProgressingProcess, + Value? reuploadRequestedBy, + Value? displayLimitInMilliseconds, + Value? removeAudio, + Value? downloadToken, + Value? encryptionKey, + Value? encryptionMac, + Value? encryptionNonce, + Value? storedFileHash, + Value? createdAt, + Value? rowid, + }) { + return MediaFilesCompanion( + mediaId: mediaId ?? this.mediaId, + type: type ?? this.type, + uploadState: uploadState ?? this.uploadState, + downloadState: downloadState ?? this.downloadState, + requiresAuthentication: + requiresAuthentication ?? this.requiresAuthentication, + stored: stored ?? this.stored, + isDraftMedia: isDraftMedia ?? this.isDraftMedia, + preProgressingProcess: + preProgressingProcess ?? this.preProgressingProcess, + reuploadRequestedBy: reuploadRequestedBy ?? this.reuploadRequestedBy, + displayLimitInMilliseconds: + displayLimitInMilliseconds ?? this.displayLimitInMilliseconds, + removeAudio: removeAudio ?? this.removeAudio, + downloadToken: downloadToken ?? this.downloadToken, + encryptionKey: encryptionKey ?? this.encryptionKey, + encryptionMac: encryptionMac ?? this.encryptionMac, + encryptionNonce: encryptionNonce ?? this.encryptionNonce, + storedFileHash: storedFileHash ?? this.storedFileHash, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (mediaId.present) { + map['media_id'] = Variable(mediaId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (uploadState.present) { + map['upload_state'] = Variable(uploadState.value); + } + if (downloadState.present) { + map['download_state'] = Variable(downloadState.value); + } + if (requiresAuthentication.present) { + map['requires_authentication'] = Variable( + requiresAuthentication.value, + ); + } + if (stored.present) { + map['stored'] = Variable(stored.value); + } + if (isDraftMedia.present) { + map['is_draft_media'] = Variable(isDraftMedia.value); + } + if (preProgressingProcess.present) { + map['pre_progressing_process'] = Variable( + preProgressingProcess.value, + ); + } + if (reuploadRequestedBy.present) { + map['reupload_requested_by'] = Variable( + reuploadRequestedBy.value, + ); + } + if (displayLimitInMilliseconds.present) { + map['display_limit_in_milliseconds'] = Variable( + displayLimitInMilliseconds.value, + ); + } + if (removeAudio.present) { + map['remove_audio'] = Variable(removeAudio.value); + } + if (downloadToken.present) { + map['download_token'] = Variable(downloadToken.value); + } + if (encryptionKey.present) { + map['encryption_key'] = Variable(encryptionKey.value); + } + if (encryptionMac.present) { + map['encryption_mac'] = Variable(encryptionMac.value); + } + if (encryptionNonce.present) { + map['encryption_nonce'] = Variable(encryptionNonce.value); + } + if (storedFileHash.present) { + map['stored_file_hash'] = Variable(storedFileHash.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('MediaFilesCompanion(') + ..write('mediaId: $mediaId, ') + ..write('type: $type, ') + ..write('uploadState: $uploadState, ') + ..write('downloadState: $downloadState, ') + ..write('requiresAuthentication: $requiresAuthentication, ') + ..write('stored: $stored, ') + ..write('isDraftMedia: $isDraftMedia, ') + ..write('preProgressingProcess: $preProgressingProcess, ') + ..write('reuploadRequestedBy: $reuploadRequestedBy, ') + ..write('displayLimitInMilliseconds: $displayLimitInMilliseconds, ') + ..write('removeAudio: $removeAudio, ') + ..write('downloadToken: $downloadToken, ') + ..write('encryptionKey: $encryptionKey, ') + ..write('encryptionMac: $encryptionMac, ') + ..write('encryptionNonce: $encryptionNonce, ') + ..write('storedFileHash: $storedFileHash, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class Messages extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Messages(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderId = GeneratedColumn( + 'sender_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn content = GeneratedColumn( + 'content', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mediaId = GeneratedColumn( + 'media_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: + 'NULL REFERENCES media_files(media_id)ON DELETE SET NULL', + ); + late final GeneratedColumn additionalMessageData = + GeneratedColumn( + 'additional_message_data', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mediaStored = GeneratedColumn( + 'media_stored', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (media_stored IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn mediaReopened = GeneratedColumn( + 'media_reopened', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (media_reopened IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn downloadToken = + GeneratedColumn( + 'download_token', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quotesMessageId = GeneratedColumn( + 'quotes_message_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn isDeletedFromSender = GeneratedColumn( + 'is_deleted_from_sender', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (is_deleted_from_sender IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn openedAt = GeneratedColumn( + 'opened_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn openedByAll = GeneratedColumn( + 'opened_by_all', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + late final GeneratedColumn modifiedAt = GeneratedColumn( + 'modified_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByUser = GeneratedColumn( + 'ack_by_user', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByServer = GeneratedColumn( + 'ack_by_server', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + groupId, + messageId, + senderId, + type, + content, + mediaId, + additionalMessageData, + mediaStored, + mediaReopened, + downloadToken, + quotesMessageId, + isDeletedFromSender, + openedAt, + openedByAll, + createdAt, + modifiedAt, + ackByUser, + ackByServer, + ]; + @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( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + senderId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_id'], + ), + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + content: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}content'], + ), + mediaId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}media_id'], + ), + additionalMessageData: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}additional_message_data'], + ), + mediaStored: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_stored'], + )!, + mediaReopened: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}media_reopened'], + )!, + downloadToken: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}download_token'], + ), + quotesMessageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}quotes_message_id'], + ), + isDeletedFromSender: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_deleted_from_sender'], + )!, + openedAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}opened_at'], + ), + openedByAll: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}opened_by_all'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + modifiedAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}modified_at'], + ), + ackByUser: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_user'], + ), + ackByServer: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_server'], + ), + ); + } + + @override + Messages createAlias(String alias) { + return Messages(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(message_id)']; + @override + bool get dontWriteConstraints => true; +} + +class MessagesData extends DataClass implements Insertable { + final String groupId; + final String messageId; + final int? senderId; + final String type; + final String? content; + final String? mediaId; + final i2.Uint8List? additionalMessageData; + final int mediaStored; + final int mediaReopened; + final i2.Uint8List? downloadToken; + final String? quotesMessageId; + final int isDeletedFromSender; + final int? openedAt; + final int? openedByAll; + final int createdAt; + final int? modifiedAt; + final int? ackByUser; + final int? ackByServer; + const MessagesData({ + required this.groupId, + required this.messageId, + this.senderId, + required this.type, + this.content, + this.mediaId, + this.additionalMessageData, + required this.mediaStored, + required this.mediaReopened, + this.downloadToken, + this.quotesMessageId, + required this.isDeletedFromSender, + this.openedAt, + this.openedByAll, + required this.createdAt, + this.modifiedAt, + this.ackByUser, + this.ackByServer, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['message_id'] = Variable(messageId); + if (!nullToAbsent || senderId != null) { + map['sender_id'] = Variable(senderId); + } + map['type'] = Variable(type); + if (!nullToAbsent || content != null) { + map['content'] = Variable(content); + } + if (!nullToAbsent || mediaId != null) { + map['media_id'] = Variable(mediaId); + } + if (!nullToAbsent || additionalMessageData != null) { + map['additional_message_data'] = Variable( + additionalMessageData, + ); + } + map['media_stored'] = Variable(mediaStored); + map['media_reopened'] = Variable(mediaReopened); + if (!nullToAbsent || downloadToken != null) { + map['download_token'] = Variable(downloadToken); + } + if (!nullToAbsent || quotesMessageId != null) { + map['quotes_message_id'] = Variable(quotesMessageId); + } + map['is_deleted_from_sender'] = Variable(isDeletedFromSender); + if (!nullToAbsent || openedAt != null) { + map['opened_at'] = Variable(openedAt); + } + if (!nullToAbsent || openedByAll != null) { + map['opened_by_all'] = Variable(openedByAll); + } + map['created_at'] = Variable(createdAt); + if (!nullToAbsent || modifiedAt != null) { + map['modified_at'] = Variable(modifiedAt); + } + if (!nullToAbsent || ackByUser != null) { + map['ack_by_user'] = Variable(ackByUser); + } + if (!nullToAbsent || ackByServer != null) { + map['ack_by_server'] = Variable(ackByServer); + } + return map; + } + + MessagesCompanion toCompanion(bool nullToAbsent) { + return MessagesCompanion( + groupId: Value(groupId), + messageId: Value(messageId), + senderId: senderId == null && nullToAbsent + ? const Value.absent() + : Value(senderId), + type: Value(type), + content: content == null && nullToAbsent + ? const Value.absent() + : Value(content), + mediaId: mediaId == null && nullToAbsent + ? const Value.absent() + : Value(mediaId), + additionalMessageData: additionalMessageData == null && nullToAbsent + ? const Value.absent() + : Value(additionalMessageData), + mediaStored: Value(mediaStored), + mediaReopened: Value(mediaReopened), + downloadToken: downloadToken == null && nullToAbsent + ? const Value.absent() + : Value(downloadToken), + quotesMessageId: quotesMessageId == null && nullToAbsent + ? const Value.absent() + : Value(quotesMessageId), + isDeletedFromSender: Value(isDeletedFromSender), + openedAt: openedAt == null && nullToAbsent + ? const Value.absent() + : Value(openedAt), + openedByAll: openedByAll == null && nullToAbsent + ? const Value.absent() + : Value(openedByAll), + createdAt: Value(createdAt), + modifiedAt: modifiedAt == null && nullToAbsent + ? const Value.absent() + : Value(modifiedAt), + ackByUser: ackByUser == null && nullToAbsent + ? const Value.absent() + : Value(ackByUser), + ackByServer: ackByServer == null && nullToAbsent + ? const Value.absent() + : Value(ackByServer), + ); + } + + factory MessagesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessagesData( + groupId: serializer.fromJson(json['groupId']), + messageId: serializer.fromJson(json['messageId']), + senderId: serializer.fromJson(json['senderId']), + type: serializer.fromJson(json['type']), + content: serializer.fromJson(json['content']), + mediaId: serializer.fromJson(json['mediaId']), + additionalMessageData: serializer.fromJson( + json['additionalMessageData'], + ), + mediaStored: serializer.fromJson(json['mediaStored']), + mediaReopened: serializer.fromJson(json['mediaReopened']), + downloadToken: serializer.fromJson(json['downloadToken']), + quotesMessageId: serializer.fromJson(json['quotesMessageId']), + isDeletedFromSender: serializer.fromJson( + json['isDeletedFromSender'], + ), + openedAt: serializer.fromJson(json['openedAt']), + openedByAll: serializer.fromJson(json['openedByAll']), + createdAt: serializer.fromJson(json['createdAt']), + modifiedAt: serializer.fromJson(json['modifiedAt']), + ackByUser: serializer.fromJson(json['ackByUser']), + ackByServer: serializer.fromJson(json['ackByServer']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'messageId': serializer.toJson(messageId), + 'senderId': serializer.toJson(senderId), + 'type': serializer.toJson(type), + 'content': serializer.toJson(content), + 'mediaId': serializer.toJson(mediaId), + 'additionalMessageData': serializer.toJson( + additionalMessageData, + ), + 'mediaStored': serializer.toJson(mediaStored), + 'mediaReopened': serializer.toJson(mediaReopened), + 'downloadToken': serializer.toJson(downloadToken), + 'quotesMessageId': serializer.toJson(quotesMessageId), + 'isDeletedFromSender': serializer.toJson(isDeletedFromSender), + 'openedAt': serializer.toJson(openedAt), + 'openedByAll': serializer.toJson(openedByAll), + 'createdAt': serializer.toJson(createdAt), + 'modifiedAt': serializer.toJson(modifiedAt), + 'ackByUser': serializer.toJson(ackByUser), + 'ackByServer': serializer.toJson(ackByServer), + }; + } + + MessagesData copyWith({ + String? groupId, + String? messageId, + Value senderId = const Value.absent(), + String? type, + Value content = const Value.absent(), + Value mediaId = const Value.absent(), + Value additionalMessageData = const Value.absent(), + int? mediaStored, + int? mediaReopened, + Value downloadToken = const Value.absent(), + Value quotesMessageId = const Value.absent(), + int? isDeletedFromSender, + Value openedAt = const Value.absent(), + Value openedByAll = const Value.absent(), + int? createdAt, + Value modifiedAt = const Value.absent(), + Value ackByUser = const Value.absent(), + Value ackByServer = const Value.absent(), + }) => MessagesData( + groupId: groupId ?? this.groupId, + messageId: messageId ?? this.messageId, + senderId: senderId.present ? senderId.value : this.senderId, + type: type ?? this.type, + content: content.present ? content.value : this.content, + mediaId: mediaId.present ? mediaId.value : this.mediaId, + additionalMessageData: additionalMessageData.present + ? additionalMessageData.value + : this.additionalMessageData, + mediaStored: mediaStored ?? this.mediaStored, + mediaReopened: mediaReopened ?? this.mediaReopened, + downloadToken: downloadToken.present + ? downloadToken.value + : this.downloadToken, + quotesMessageId: quotesMessageId.present + ? quotesMessageId.value + : this.quotesMessageId, + isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, + openedAt: openedAt.present ? openedAt.value : this.openedAt, + openedByAll: openedByAll.present ? openedByAll.value : this.openedByAll, + createdAt: createdAt ?? this.createdAt, + modifiedAt: modifiedAt.present ? modifiedAt.value : this.modifiedAt, + ackByUser: ackByUser.present ? ackByUser.value : this.ackByUser, + ackByServer: ackByServer.present ? ackByServer.value : this.ackByServer, + ); + MessagesData copyWithCompanion(MessagesCompanion data) { + return MessagesData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + senderId: data.senderId.present ? data.senderId.value : this.senderId, + type: data.type.present ? data.type.value : this.type, + content: data.content.present ? data.content.value : this.content, + mediaId: data.mediaId.present ? data.mediaId.value : this.mediaId, + additionalMessageData: data.additionalMessageData.present + ? data.additionalMessageData.value + : this.additionalMessageData, + mediaStored: data.mediaStored.present + ? data.mediaStored.value + : this.mediaStored, + mediaReopened: data.mediaReopened.present + ? data.mediaReopened.value + : this.mediaReopened, + downloadToken: data.downloadToken.present + ? data.downloadToken.value + : this.downloadToken, + quotesMessageId: data.quotesMessageId.present + ? data.quotesMessageId.value + : this.quotesMessageId, + isDeletedFromSender: data.isDeletedFromSender.present + ? data.isDeletedFromSender.value + : this.isDeletedFromSender, + openedAt: data.openedAt.present ? data.openedAt.value : this.openedAt, + openedByAll: data.openedByAll.present + ? data.openedByAll.value + : this.openedByAll, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + modifiedAt: data.modifiedAt.present + ? data.modifiedAt.value + : this.modifiedAt, + ackByUser: data.ackByUser.present ? data.ackByUser.value : this.ackByUser, + ackByServer: data.ackByServer.present + ? data.ackByServer.value + : this.ackByServer, + ); + } + + @override + String toString() { + return (StringBuffer('MessagesData(') + ..write('groupId: $groupId, ') + ..write('messageId: $messageId, ') + ..write('senderId: $senderId, ') + ..write('type: $type, ') + ..write('content: $content, ') + ..write('mediaId: $mediaId, ') + ..write('additionalMessageData: $additionalMessageData, ') + ..write('mediaStored: $mediaStored, ') + ..write('mediaReopened: $mediaReopened, ') + ..write('downloadToken: $downloadToken, ') + ..write('quotesMessageId: $quotesMessageId, ') + ..write('isDeletedFromSender: $isDeletedFromSender, ') + ..write('openedAt: $openedAt, ') + ..write('openedByAll: $openedByAll, ') + ..write('createdAt: $createdAt, ') + ..write('modifiedAt: $modifiedAt, ') + ..write('ackByUser: $ackByUser, ') + ..write('ackByServer: $ackByServer') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupId, + messageId, + senderId, + type, + content, + mediaId, + $driftBlobEquality.hash(additionalMessageData), + mediaStored, + mediaReopened, + $driftBlobEquality.hash(downloadToken), + quotesMessageId, + isDeletedFromSender, + openedAt, + openedByAll, + createdAt, + modifiedAt, + ackByUser, + ackByServer, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessagesData && + other.groupId == this.groupId && + other.messageId == this.messageId && + other.senderId == this.senderId && + other.type == this.type && + other.content == this.content && + other.mediaId == this.mediaId && + $driftBlobEquality.equals( + other.additionalMessageData, + this.additionalMessageData, + ) && + other.mediaStored == this.mediaStored && + other.mediaReopened == this.mediaReopened && + $driftBlobEquality.equals(other.downloadToken, this.downloadToken) && + other.quotesMessageId == this.quotesMessageId && + other.isDeletedFromSender == this.isDeletedFromSender && + other.openedAt == this.openedAt && + other.openedByAll == this.openedByAll && + other.createdAt == this.createdAt && + other.modifiedAt == this.modifiedAt && + other.ackByUser == this.ackByUser && + other.ackByServer == this.ackByServer); +} + +class MessagesCompanion extends UpdateCompanion { + final Value groupId; + final Value messageId; + final Value senderId; + final Value type; + final Value content; + final Value mediaId; + final Value additionalMessageData; + final Value mediaStored; + final Value mediaReopened; + final Value downloadToken; + final Value quotesMessageId; + final Value isDeletedFromSender; + final Value openedAt; + final Value openedByAll; + final Value createdAt; + final Value modifiedAt; + final Value ackByUser; + final Value ackByServer; + final Value rowid; + const MessagesCompanion({ + this.groupId = const Value.absent(), + this.messageId = const Value.absent(), + this.senderId = const Value.absent(), + this.type = const Value.absent(), + this.content = const Value.absent(), + this.mediaId = const Value.absent(), + this.additionalMessageData = const Value.absent(), + this.mediaStored = const Value.absent(), + this.mediaReopened = const Value.absent(), + this.downloadToken = const Value.absent(), + this.quotesMessageId = const Value.absent(), + this.isDeletedFromSender = const Value.absent(), + this.openedAt = const Value.absent(), + this.openedByAll = const Value.absent(), + this.createdAt = const Value.absent(), + this.modifiedAt = const Value.absent(), + this.ackByUser = const Value.absent(), + this.ackByServer = const Value.absent(), + this.rowid = const Value.absent(), + }); + MessagesCompanion.insert({ + required String groupId, + required String messageId, + this.senderId = const Value.absent(), + required String type, + this.content = const Value.absent(), + this.mediaId = const Value.absent(), + this.additionalMessageData = const Value.absent(), + this.mediaStored = const Value.absent(), + this.mediaReopened = const Value.absent(), + this.downloadToken = const Value.absent(), + this.quotesMessageId = const Value.absent(), + this.isDeletedFromSender = const Value.absent(), + this.openedAt = const Value.absent(), + this.openedByAll = const Value.absent(), + this.createdAt = const Value.absent(), + this.modifiedAt = const Value.absent(), + this.ackByUser = const Value.absent(), + this.ackByServer = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + messageId = Value(messageId), + type = Value(type); + static Insertable custom({ + Expression? groupId, + Expression? messageId, + Expression? senderId, + Expression? type, + Expression? content, + Expression? mediaId, + Expression? additionalMessageData, + Expression? mediaStored, + Expression? mediaReopened, + Expression? downloadToken, + Expression? quotesMessageId, + Expression? isDeletedFromSender, + Expression? openedAt, + Expression? openedByAll, + Expression? createdAt, + Expression? modifiedAt, + Expression? ackByUser, + Expression? ackByServer, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (messageId != null) 'message_id': messageId, + if (senderId != null) 'sender_id': senderId, + if (type != null) 'type': type, + if (content != null) 'content': content, + if (mediaId != null) 'media_id': mediaId, + if (additionalMessageData != null) + 'additional_message_data': additionalMessageData, + if (mediaStored != null) 'media_stored': mediaStored, + if (mediaReopened != null) 'media_reopened': mediaReopened, + if (downloadToken != null) 'download_token': downloadToken, + if (quotesMessageId != null) 'quotes_message_id': quotesMessageId, + if (isDeletedFromSender != null) + 'is_deleted_from_sender': isDeletedFromSender, + if (openedAt != null) 'opened_at': openedAt, + if (openedByAll != null) 'opened_by_all': openedByAll, + if (createdAt != null) 'created_at': createdAt, + if (modifiedAt != null) 'modified_at': modifiedAt, + if (ackByUser != null) 'ack_by_user': ackByUser, + if (ackByServer != null) 'ack_by_server': ackByServer, + if (rowid != null) 'rowid': rowid, + }); + } + + MessagesCompanion copyWith({ + Value? groupId, + Value? messageId, + Value? senderId, + Value? type, + Value? content, + Value? mediaId, + Value? additionalMessageData, + Value? mediaStored, + Value? mediaReopened, + Value? downloadToken, + Value? quotesMessageId, + Value? isDeletedFromSender, + Value? openedAt, + Value? openedByAll, + Value? createdAt, + Value? modifiedAt, + Value? ackByUser, + Value? ackByServer, + Value? rowid, + }) { + return MessagesCompanion( + groupId: groupId ?? this.groupId, + messageId: messageId ?? this.messageId, + senderId: senderId ?? this.senderId, + type: type ?? this.type, + content: content ?? this.content, + mediaId: mediaId ?? this.mediaId, + additionalMessageData: + additionalMessageData ?? this.additionalMessageData, + mediaStored: mediaStored ?? this.mediaStored, + mediaReopened: mediaReopened ?? this.mediaReopened, + downloadToken: downloadToken ?? this.downloadToken, + quotesMessageId: quotesMessageId ?? this.quotesMessageId, + isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, + openedAt: openedAt ?? this.openedAt, + openedByAll: openedByAll ?? this.openedByAll, + createdAt: createdAt ?? this.createdAt, + modifiedAt: modifiedAt ?? this.modifiedAt, + ackByUser: ackByUser ?? this.ackByUser, + ackByServer: ackByServer ?? this.ackByServer, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (senderId.present) { + map['sender_id'] = Variable(senderId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (mediaId.present) { + map['media_id'] = Variable(mediaId.value); + } + if (additionalMessageData.present) { + map['additional_message_data'] = Variable( + additionalMessageData.value, + ); + } + if (mediaStored.present) { + map['media_stored'] = Variable(mediaStored.value); + } + if (mediaReopened.present) { + map['media_reopened'] = Variable(mediaReopened.value); + } + if (downloadToken.present) { + map['download_token'] = Variable(downloadToken.value); + } + if (quotesMessageId.present) { + map['quotes_message_id'] = Variable(quotesMessageId.value); + } + if (isDeletedFromSender.present) { + map['is_deleted_from_sender'] = Variable(isDeletedFromSender.value); + } + if (openedAt.present) { + map['opened_at'] = Variable(openedAt.value); + } + if (openedByAll.present) { + map['opened_by_all'] = Variable(openedByAll.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (modifiedAt.present) { + map['modified_at'] = Variable(modifiedAt.value); + } + if (ackByUser.present) { + map['ack_by_user'] = Variable(ackByUser.value); + } + if (ackByServer.present) { + map['ack_by_server'] = Variable(ackByServer.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessagesCompanion(') + ..write('groupId: $groupId, ') + ..write('messageId: $messageId, ') + ..write('senderId: $senderId, ') + ..write('type: $type, ') + ..write('content: $content, ') + ..write('mediaId: $mediaId, ') + ..write('additionalMessageData: $additionalMessageData, ') + ..write('mediaStored: $mediaStored, ') + ..write('mediaReopened: $mediaReopened, ') + ..write('downloadToken: $downloadToken, ') + ..write('quotesMessageId: $quotesMessageId, ') + ..write('isDeletedFromSender: $isDeletedFromSender, ') + ..write('openedAt: $openedAt, ') + ..write('openedByAll: $openedByAll, ') + ..write('createdAt: $createdAt, ') + ..write('modifiedAt: $modifiedAt, ') + ..write('ackByUser: $ackByUser, ') + ..write('ackByServer: $ackByServer, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class MessageHistories extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MessageHistories(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn content = GeneratedColumn( + 'content', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + id, + messageId, + contactId, + content, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'message_histories'; + @override + Set get $primaryKey => {id}; + @override + MessageHistoriesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MessageHistoriesData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + content: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}content'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + MessageHistories createAlias(String alias) { + return MessageHistories(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class MessageHistoriesData extends DataClass + implements Insertable { + final int id; + final String messageId; + final int? contactId; + final String? content; + final int createdAt; + const MessageHistoriesData({ + required this.id, + required this.messageId, + this.contactId, + this.content, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['message_id'] = Variable(messageId); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + if (!nullToAbsent || content != null) { + map['content'] = Variable(content); + } + map['created_at'] = Variable(createdAt); + return map; + } + + MessageHistoriesCompanion toCompanion(bool nullToAbsent) { + return MessageHistoriesCompanion( + id: Value(id), + messageId: Value(messageId), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + content: content == null && nullToAbsent + ? const Value.absent() + : Value(content), + createdAt: Value(createdAt), + ); + } + + factory MessageHistoriesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessageHistoriesData( + id: serializer.fromJson(json['id']), + messageId: serializer.fromJson(json['messageId']), + contactId: serializer.fromJson(json['contactId']), + content: serializer.fromJson(json['content']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'messageId': serializer.toJson(messageId), + 'contactId': serializer.toJson(contactId), + 'content': serializer.toJson(content), + 'createdAt': serializer.toJson(createdAt), + }; + } + + MessageHistoriesData copyWith({ + int? id, + String? messageId, + Value contactId = const Value.absent(), + Value content = const Value.absent(), + int? createdAt, + }) => MessageHistoriesData( + id: id ?? this.id, + messageId: messageId ?? this.messageId, + contactId: contactId.present ? contactId.value : this.contactId, + content: content.present ? content.value : this.content, + createdAt: createdAt ?? this.createdAt, + ); + MessageHistoriesData copyWithCompanion(MessageHistoriesCompanion data) { + return MessageHistoriesData( + id: data.id.present ? data.id.value : this.id, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + content: data.content.present ? data.content.value : this.content, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('MessageHistoriesData(') + ..write('id: $id, ') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('content: $content, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, messageId, contactId, content, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessageHistoriesData && + other.id == this.id && + other.messageId == this.messageId && + other.contactId == this.contactId && + other.content == this.content && + other.createdAt == this.createdAt); +} + +class MessageHistoriesCompanion extends UpdateCompanion { + final Value id; + final Value messageId; + final Value contactId; + final Value content; + final Value createdAt; + const MessageHistoriesCompanion({ + this.id = const Value.absent(), + this.messageId = const Value.absent(), + this.contactId = const Value.absent(), + this.content = const Value.absent(), + this.createdAt = const Value.absent(), + }); + MessageHistoriesCompanion.insert({ + this.id = const Value.absent(), + required String messageId, + this.contactId = const Value.absent(), + this.content = const Value.absent(), + this.createdAt = const Value.absent(), + }) : messageId = Value(messageId); + static Insertable custom({ + Expression? id, + Expression? messageId, + Expression? contactId, + Expression? content, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (messageId != null) 'message_id': messageId, + if (contactId != null) 'contact_id': contactId, + if (content != null) 'content': content, + if (createdAt != null) 'created_at': createdAt, + }); + } + + MessageHistoriesCompanion copyWith({ + Value? id, + Value? messageId, + Value? contactId, + Value? content, + Value? createdAt, + }) { + return MessageHistoriesCompanion( + id: id ?? this.id, + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + content: content ?? this.content, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessageHistoriesCompanion(') + ..write('id: $id, ') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('content: $content, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class Reactions extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Reactions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn emoji = GeneratedColumn( + 'emoji', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderId = GeneratedColumn( + 'sender_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [messageId, emoji, senderId, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'reactions'; + @override + Set get $primaryKey => {messageId, senderId, emoji}; + @override + ReactionsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReactionsData( + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + emoji: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}emoji'], + )!, + senderId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sender_id'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + Reactions createAlias(String alias) { + return Reactions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(message_id, sender_id, emoji)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class ReactionsData extends DataClass implements Insertable { + final String messageId; + final String emoji; + final int? senderId; + final int createdAt; + const ReactionsData({ + required this.messageId, + required this.emoji, + this.senderId, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['message_id'] = Variable(messageId); + map['emoji'] = Variable(emoji); + if (!nullToAbsent || senderId != null) { + map['sender_id'] = Variable(senderId); + } + map['created_at'] = Variable(createdAt); + return map; + } + + ReactionsCompanion toCompanion(bool nullToAbsent) { + return ReactionsCompanion( + messageId: Value(messageId), + emoji: Value(emoji), + senderId: senderId == null && nullToAbsent + ? const Value.absent() + : Value(senderId), + createdAt: Value(createdAt), + ); + } + + factory ReactionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReactionsData( + messageId: serializer.fromJson(json['messageId']), + emoji: serializer.fromJson(json['emoji']), + senderId: serializer.fromJson(json['senderId']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'messageId': serializer.toJson(messageId), + 'emoji': serializer.toJson(emoji), + 'senderId': serializer.toJson(senderId), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReactionsData copyWith({ + String? messageId, + String? emoji, + Value senderId = const Value.absent(), + int? createdAt, + }) => ReactionsData( + messageId: messageId ?? this.messageId, + emoji: emoji ?? this.emoji, + senderId: senderId.present ? senderId.value : this.senderId, + createdAt: createdAt ?? this.createdAt, + ); + ReactionsData copyWithCompanion(ReactionsCompanion data) { + return ReactionsData( + messageId: data.messageId.present ? data.messageId.value : this.messageId, + emoji: data.emoji.present ? data.emoji.value : this.emoji, + senderId: data.senderId.present ? data.senderId.value : this.senderId, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReactionsData(') + ..write('messageId: $messageId, ') + ..write('emoji: $emoji, ') + ..write('senderId: $senderId, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(messageId, emoji, senderId, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReactionsData && + other.messageId == this.messageId && + other.emoji == this.emoji && + other.senderId == this.senderId && + other.createdAt == this.createdAt); +} + +class ReactionsCompanion extends UpdateCompanion { + final Value messageId; + final Value emoji; + final Value senderId; + final Value createdAt; + final Value rowid; + const ReactionsCompanion({ + this.messageId = const Value.absent(), + this.emoji = const Value.absent(), + this.senderId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReactionsCompanion.insert({ + required String messageId, + required String emoji, + this.senderId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : messageId = Value(messageId), + emoji = Value(emoji); + static Insertable custom({ + Expression? messageId, + Expression? emoji, + Expression? senderId, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (messageId != null) 'message_id': messageId, + if (emoji != null) 'emoji': emoji, + if (senderId != null) 'sender_id': senderId, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReactionsCompanion copyWith({ + Value? messageId, + Value? emoji, + Value? senderId, + Value? createdAt, + Value? rowid, + }) { + return ReactionsCompanion( + messageId: messageId ?? this.messageId, + emoji: emoji ?? this.emoji, + senderId: senderId ?? this.senderId, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (emoji.present) { + map['emoji'] = Variable(emoji.value); + } + if (senderId.present) { + map['sender_id'] = Variable(senderId.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('ReactionsCompanion(') + ..write('messageId: $messageId, ') + ..write('emoji: $emoji, ') + ..write('senderId: $senderId, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class GroupMembers extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + GroupMembers(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn memberState = GeneratedColumn( + 'member_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn groupPublicKey = + GeneratedColumn( + 'group_public_key', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastChatOpened = GeneratedColumn( + 'last_chat_opened', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastTypeIndicator = GeneratedColumn( + 'last_type_indicator', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn lastMessage = GeneratedColumn( + 'last_message', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupId, + contactId, + memberState, + groupPublicKey, + lastChatOpened, + lastTypeIndicator, + lastMessage, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'group_members'; + @override + Set get $primaryKey => {groupId, contactId}; + @override + GroupMembersData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupMembersData( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + memberState: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}member_state'], + ), + groupPublicKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}group_public_key'], + ), + lastChatOpened: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_chat_opened'], + ), + lastTypeIndicator: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_type_indicator'], + ), + lastMessage: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_message'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + GroupMembers createAlias(String alias) { + return GroupMembers(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(group_id, contact_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class GroupMembersData extends DataClass + implements Insertable { + final String groupId; + final int contactId; + final String? memberState; + final i2.Uint8List? groupPublicKey; + final int? lastChatOpened; + final int? lastTypeIndicator; + final int? lastMessage; + final int createdAt; + const GroupMembersData({ + required this.groupId, + required this.contactId, + this.memberState, + this.groupPublicKey, + this.lastChatOpened, + this.lastTypeIndicator, + this.lastMessage, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['contact_id'] = Variable(contactId); + if (!nullToAbsent || memberState != null) { + map['member_state'] = Variable(memberState); + } + if (!nullToAbsent || groupPublicKey != null) { + map['group_public_key'] = Variable(groupPublicKey); + } + if (!nullToAbsent || lastChatOpened != null) { + map['last_chat_opened'] = Variable(lastChatOpened); + } + if (!nullToAbsent || lastTypeIndicator != null) { + map['last_type_indicator'] = Variable(lastTypeIndicator); + } + if (!nullToAbsent || lastMessage != null) { + map['last_message'] = Variable(lastMessage); + } + map['created_at'] = Variable(createdAt); + return map; + } + + GroupMembersCompanion toCompanion(bool nullToAbsent) { + return GroupMembersCompanion( + groupId: Value(groupId), + contactId: Value(contactId), + memberState: memberState == null && nullToAbsent + ? const Value.absent() + : Value(memberState), + groupPublicKey: groupPublicKey == null && nullToAbsent + ? const Value.absent() + : Value(groupPublicKey), + lastChatOpened: lastChatOpened == null && nullToAbsent + ? const Value.absent() + : Value(lastChatOpened), + lastTypeIndicator: lastTypeIndicator == null && nullToAbsent + ? const Value.absent() + : Value(lastTypeIndicator), + lastMessage: lastMessage == null && nullToAbsent + ? const Value.absent() + : Value(lastMessage), + createdAt: Value(createdAt), + ); + } + + factory GroupMembersData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupMembersData( + groupId: serializer.fromJson(json['groupId']), + contactId: serializer.fromJson(json['contactId']), + memberState: serializer.fromJson(json['memberState']), + groupPublicKey: serializer.fromJson( + json['groupPublicKey'], + ), + lastChatOpened: serializer.fromJson(json['lastChatOpened']), + lastTypeIndicator: serializer.fromJson(json['lastTypeIndicator']), + lastMessage: serializer.fromJson(json['lastMessage']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'contactId': serializer.toJson(contactId), + 'memberState': serializer.toJson(memberState), + 'groupPublicKey': serializer.toJson(groupPublicKey), + 'lastChatOpened': serializer.toJson(lastChatOpened), + 'lastTypeIndicator': serializer.toJson(lastTypeIndicator), + 'lastMessage': serializer.toJson(lastMessage), + 'createdAt': serializer.toJson(createdAt), + }; + } + + GroupMembersData copyWith({ + String? groupId, + int? contactId, + Value memberState = const Value.absent(), + Value groupPublicKey = const Value.absent(), + Value lastChatOpened = const Value.absent(), + Value lastTypeIndicator = const Value.absent(), + Value lastMessage = const Value.absent(), + int? createdAt, + }) => GroupMembersData( + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + memberState: memberState.present ? memberState.value : this.memberState, + groupPublicKey: groupPublicKey.present + ? groupPublicKey.value + : this.groupPublicKey, + lastChatOpened: lastChatOpened.present + ? lastChatOpened.value + : this.lastChatOpened, + lastTypeIndicator: lastTypeIndicator.present + ? lastTypeIndicator.value + : this.lastTypeIndicator, + lastMessage: lastMessage.present ? lastMessage.value : this.lastMessage, + createdAt: createdAt ?? this.createdAt, + ); + GroupMembersData copyWithCompanion(GroupMembersCompanion data) { + return GroupMembersData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + memberState: data.memberState.present + ? data.memberState.value + : this.memberState, + groupPublicKey: data.groupPublicKey.present + ? data.groupPublicKey.value + : this.groupPublicKey, + lastChatOpened: data.lastChatOpened.present + ? data.lastChatOpened.value + : this.lastChatOpened, + lastTypeIndicator: data.lastTypeIndicator.present + ? data.lastTypeIndicator.value + : this.lastTypeIndicator, + lastMessage: data.lastMessage.present + ? data.lastMessage.value + : this.lastMessage, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('GroupMembersData(') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('memberState: $memberState, ') + ..write('groupPublicKey: $groupPublicKey, ') + ..write('lastChatOpened: $lastChatOpened, ') + ..write('lastTypeIndicator: $lastTypeIndicator, ') + ..write('lastMessage: $lastMessage, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupId, + contactId, + memberState, + $driftBlobEquality.hash(groupPublicKey), + lastChatOpened, + lastTypeIndicator, + lastMessage, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupMembersData && + other.groupId == this.groupId && + other.contactId == this.contactId && + other.memberState == this.memberState && + $driftBlobEquality.equals( + other.groupPublicKey, + this.groupPublicKey, + ) && + other.lastChatOpened == this.lastChatOpened && + other.lastTypeIndicator == this.lastTypeIndicator && + other.lastMessage == this.lastMessage && + other.createdAt == this.createdAt); +} + +class GroupMembersCompanion extends UpdateCompanion { + final Value groupId; + final Value contactId; + final Value memberState; + final Value groupPublicKey; + final Value lastChatOpened; + final Value lastTypeIndicator; + final Value lastMessage; + final Value createdAt; + final Value rowid; + const GroupMembersCompanion({ + this.groupId = const Value.absent(), + this.contactId = const Value.absent(), + this.memberState = const Value.absent(), + this.groupPublicKey = const Value.absent(), + this.lastChatOpened = const Value.absent(), + this.lastTypeIndicator = const Value.absent(), + this.lastMessage = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupMembersCompanion.insert({ + required String groupId, + required int contactId, + this.memberState = const Value.absent(), + this.groupPublicKey = const Value.absent(), + this.lastChatOpened = const Value.absent(), + this.lastTypeIndicator = const Value.absent(), + this.lastMessage = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + contactId = Value(contactId); + static Insertable custom({ + Expression? groupId, + Expression? contactId, + Expression? memberState, + Expression? groupPublicKey, + Expression? lastChatOpened, + Expression? lastTypeIndicator, + Expression? lastMessage, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (contactId != null) 'contact_id': contactId, + if (memberState != null) 'member_state': memberState, + if (groupPublicKey != null) 'group_public_key': groupPublicKey, + if (lastChatOpened != null) 'last_chat_opened': lastChatOpened, + if (lastTypeIndicator != null) 'last_type_indicator': lastTypeIndicator, + if (lastMessage != null) 'last_message': lastMessage, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupMembersCompanion copyWith({ + Value? groupId, + Value? contactId, + Value? memberState, + Value? groupPublicKey, + Value? lastChatOpened, + Value? lastTypeIndicator, + Value? lastMessage, + Value? createdAt, + Value? rowid, + }) { + return GroupMembersCompanion( + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + memberState: memberState ?? this.memberState, + groupPublicKey: groupPublicKey ?? this.groupPublicKey, + lastChatOpened: lastChatOpened ?? this.lastChatOpened, + lastTypeIndicator: lastTypeIndicator ?? this.lastTypeIndicator, + lastMessage: lastMessage ?? this.lastMessage, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (memberState.present) { + map['member_state'] = Variable(memberState.value); + } + if (groupPublicKey.present) { + map['group_public_key'] = Variable(groupPublicKey.value); + } + if (lastChatOpened.present) { + map['last_chat_opened'] = Variable(lastChatOpened.value); + } + if (lastTypeIndicator.present) { + map['last_type_indicator'] = Variable(lastTypeIndicator.value); + } + if (lastMessage.present) { + map['last_message'] = Variable(lastMessage.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('GroupMembersCompanion(') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('memberState: $memberState, ') + ..write('groupPublicKey: $groupPublicKey, ') + ..write('lastChatOpened: $lastChatOpened, ') + ..write('lastTypeIndicator: $lastTypeIndicator, ') + ..write('lastMessage: $lastMessage, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class Receipts extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Receipts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn receiptId = GeneratedColumn( + 'receipt_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn message = + GeneratedColumn( + 'message', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactWillSendsReceipt = + GeneratedColumn( + 'contact_will_sends_receipt', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 1 CHECK (contact_will_sends_receipt IN (0, 1))', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn + willBeRetriedByMediaUpload = GeneratedColumn( + 'will_be_retried_by_media_upload', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (will_be_retried_by_media_upload IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn markForRetry = GeneratedColumn( + 'mark_for_retry', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn markForRetryAfterAccepted = + GeneratedColumn( + 'mark_for_retry_after_accepted', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn ackByServerAt = GeneratedColumn( + 'ack_by_server_at', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn retryCount = GeneratedColumn( + 'retry_count', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn lastRetry = GeneratedColumn( + 'last_retry', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + receiptId, + contactId, + messageId, + message, + contactWillSendsReceipt, + willBeRetriedByMediaUpload, + markForRetry, + markForRetryAfterAccepted, + ackByServerAt, + retryCount, + lastRetry, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'receipts'; + @override + Set get $primaryKey => {receiptId}; + @override + ReceiptsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReceiptsData( + receiptId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}receipt_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + ), + message: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}message'], + )!, + contactWillSendsReceipt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_will_sends_receipt'], + )!, + willBeRetriedByMediaUpload: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}will_be_retried_by_media_upload'], + )!, + markForRetry: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}mark_for_retry'], + ), + markForRetryAfterAccepted: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}mark_for_retry_after_accepted'], + ), + ackByServerAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}ack_by_server_at'], + ), + retryCount: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}retry_count'], + )!, + lastRetry: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}last_retry'], + ), + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + Receipts createAlias(String alias) { + return Receipts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(receipt_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ReceiptsData extends DataClass implements Insertable { + final String receiptId; + final int contactId; + final String? messageId; + final i2.Uint8List message; + final int contactWillSendsReceipt; + final int willBeRetriedByMediaUpload; + final int? markForRetry; + final int? markForRetryAfterAccepted; + final int? ackByServerAt; + final int retryCount; + final int? lastRetry; + final int createdAt; + const ReceiptsData({ + required this.receiptId, + required this.contactId, + this.messageId, + required this.message, + required this.contactWillSendsReceipt, + required this.willBeRetriedByMediaUpload, + this.markForRetry, + this.markForRetryAfterAccepted, + this.ackByServerAt, + required this.retryCount, + this.lastRetry, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['receipt_id'] = Variable(receiptId); + map['contact_id'] = Variable(contactId); + if (!nullToAbsent || messageId != null) { + map['message_id'] = Variable(messageId); + } + map['message'] = Variable(message); + map['contact_will_sends_receipt'] = Variable(contactWillSendsReceipt); + map['will_be_retried_by_media_upload'] = Variable( + willBeRetriedByMediaUpload, + ); + if (!nullToAbsent || markForRetry != null) { + map['mark_for_retry'] = Variable(markForRetry); + } + if (!nullToAbsent || markForRetryAfterAccepted != null) { + map['mark_for_retry_after_accepted'] = Variable( + markForRetryAfterAccepted, + ); + } + if (!nullToAbsent || ackByServerAt != null) { + map['ack_by_server_at'] = Variable(ackByServerAt); + } + map['retry_count'] = Variable(retryCount); + if (!nullToAbsent || lastRetry != null) { + map['last_retry'] = Variable(lastRetry); + } + map['created_at'] = Variable(createdAt); + return map; + } + + ReceiptsCompanion toCompanion(bool nullToAbsent) { + return ReceiptsCompanion( + receiptId: Value(receiptId), + contactId: Value(contactId), + messageId: messageId == null && nullToAbsent + ? const Value.absent() + : Value(messageId), + message: Value(message), + contactWillSendsReceipt: Value(contactWillSendsReceipt), + willBeRetriedByMediaUpload: Value(willBeRetriedByMediaUpload), + markForRetry: markForRetry == null && nullToAbsent + ? const Value.absent() + : Value(markForRetry), + markForRetryAfterAccepted: + markForRetryAfterAccepted == null && nullToAbsent + ? const Value.absent() + : Value(markForRetryAfterAccepted), + ackByServerAt: ackByServerAt == null && nullToAbsent + ? const Value.absent() + : Value(ackByServerAt), + retryCount: Value(retryCount), + lastRetry: lastRetry == null && nullToAbsent + ? const Value.absent() + : Value(lastRetry), + createdAt: Value(createdAt), + ); + } + + factory ReceiptsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReceiptsData( + receiptId: serializer.fromJson(json['receiptId']), + contactId: serializer.fromJson(json['contactId']), + messageId: serializer.fromJson(json['messageId']), + message: serializer.fromJson(json['message']), + contactWillSendsReceipt: serializer.fromJson( + json['contactWillSendsReceipt'], + ), + willBeRetriedByMediaUpload: serializer.fromJson( + json['willBeRetriedByMediaUpload'], + ), + markForRetry: serializer.fromJson(json['markForRetry']), + markForRetryAfterAccepted: serializer.fromJson( + json['markForRetryAfterAccepted'], + ), + ackByServerAt: serializer.fromJson(json['ackByServerAt']), + retryCount: serializer.fromJson(json['retryCount']), + lastRetry: serializer.fromJson(json['lastRetry']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'receiptId': serializer.toJson(receiptId), + 'contactId': serializer.toJson(contactId), + 'messageId': serializer.toJson(messageId), + 'message': serializer.toJson(message), + 'contactWillSendsReceipt': serializer.toJson( + contactWillSendsReceipt, + ), + 'willBeRetriedByMediaUpload': serializer.toJson( + willBeRetriedByMediaUpload, + ), + 'markForRetry': serializer.toJson(markForRetry), + 'markForRetryAfterAccepted': serializer.toJson( + markForRetryAfterAccepted, + ), + 'ackByServerAt': serializer.toJson(ackByServerAt), + 'retryCount': serializer.toJson(retryCount), + 'lastRetry': serializer.toJson(lastRetry), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReceiptsData copyWith({ + String? receiptId, + int? contactId, + Value messageId = const Value.absent(), + i2.Uint8List? message, + int? contactWillSendsReceipt, + int? willBeRetriedByMediaUpload, + Value markForRetry = const Value.absent(), + Value markForRetryAfterAccepted = const Value.absent(), + Value ackByServerAt = const Value.absent(), + int? retryCount, + Value lastRetry = const Value.absent(), + int? createdAt, + }) => ReceiptsData( + receiptId: receiptId ?? this.receiptId, + contactId: contactId ?? this.contactId, + messageId: messageId.present ? messageId.value : this.messageId, + message: message ?? this.message, + contactWillSendsReceipt: + contactWillSendsReceipt ?? this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: + willBeRetriedByMediaUpload ?? this.willBeRetriedByMediaUpload, + markForRetry: markForRetry.present ? markForRetry.value : this.markForRetry, + markForRetryAfterAccepted: markForRetryAfterAccepted.present + ? markForRetryAfterAccepted.value + : this.markForRetryAfterAccepted, + ackByServerAt: ackByServerAt.present + ? ackByServerAt.value + : this.ackByServerAt, + retryCount: retryCount ?? this.retryCount, + lastRetry: lastRetry.present ? lastRetry.value : this.lastRetry, + createdAt: createdAt ?? this.createdAt, + ); + ReceiptsData copyWithCompanion(ReceiptsCompanion data) { + return ReceiptsData( + receiptId: data.receiptId.present ? data.receiptId.value : this.receiptId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + message: data.message.present ? data.message.value : this.message, + contactWillSendsReceipt: data.contactWillSendsReceipt.present + ? data.contactWillSendsReceipt.value + : this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: data.willBeRetriedByMediaUpload.present + ? data.willBeRetriedByMediaUpload.value + : this.willBeRetriedByMediaUpload, + markForRetry: data.markForRetry.present + ? data.markForRetry.value + : this.markForRetry, + markForRetryAfterAccepted: data.markForRetryAfterAccepted.present + ? data.markForRetryAfterAccepted.value + : this.markForRetryAfterAccepted, + ackByServerAt: data.ackByServerAt.present + ? data.ackByServerAt.value + : this.ackByServerAt, + retryCount: data.retryCount.present + ? data.retryCount.value + : this.retryCount, + lastRetry: data.lastRetry.present ? data.lastRetry.value : this.lastRetry, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReceiptsData(') + ..write('receiptId: $receiptId, ') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('message: $message, ') + ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') + ..write('willBeRetriedByMediaUpload: $willBeRetriedByMediaUpload, ') + ..write('markForRetry: $markForRetry, ') + ..write('markForRetryAfterAccepted: $markForRetryAfterAccepted, ') + ..write('ackByServerAt: $ackByServerAt, ') + ..write('retryCount: $retryCount, ') + ..write('lastRetry: $lastRetry, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + receiptId, + contactId, + messageId, + $driftBlobEquality.hash(message), + contactWillSendsReceipt, + willBeRetriedByMediaUpload, + markForRetry, + markForRetryAfterAccepted, + ackByServerAt, + retryCount, + lastRetry, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReceiptsData && + other.receiptId == this.receiptId && + other.contactId == this.contactId && + other.messageId == this.messageId && + $driftBlobEquality.equals(other.message, this.message) && + other.contactWillSendsReceipt == this.contactWillSendsReceipt && + other.willBeRetriedByMediaUpload == this.willBeRetriedByMediaUpload && + other.markForRetry == this.markForRetry && + other.markForRetryAfterAccepted == this.markForRetryAfterAccepted && + other.ackByServerAt == this.ackByServerAt && + other.retryCount == this.retryCount && + other.lastRetry == this.lastRetry && + other.createdAt == this.createdAt); +} + +class ReceiptsCompanion extends UpdateCompanion { + final Value receiptId; + final Value contactId; + final Value messageId; + final Value message; + final Value contactWillSendsReceipt; + final Value willBeRetriedByMediaUpload; + final Value markForRetry; + final Value markForRetryAfterAccepted; + final Value ackByServerAt; + final Value retryCount; + final Value lastRetry; + final Value createdAt; + final Value rowid; + const ReceiptsCompanion({ + this.receiptId = const Value.absent(), + this.contactId = const Value.absent(), + this.messageId = const Value.absent(), + this.message = const Value.absent(), + this.contactWillSendsReceipt = const Value.absent(), + this.willBeRetriedByMediaUpload = const Value.absent(), + this.markForRetry = const Value.absent(), + this.markForRetryAfterAccepted = const Value.absent(), + this.ackByServerAt = const Value.absent(), + this.retryCount = const Value.absent(), + this.lastRetry = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReceiptsCompanion.insert({ + required String receiptId, + required int contactId, + this.messageId = const Value.absent(), + required i2.Uint8List message, + this.contactWillSendsReceipt = const Value.absent(), + this.willBeRetriedByMediaUpload = const Value.absent(), + this.markForRetry = const Value.absent(), + this.markForRetryAfterAccepted = const Value.absent(), + this.ackByServerAt = const Value.absent(), + this.retryCount = const Value.absent(), + this.lastRetry = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : receiptId = Value(receiptId), + contactId = Value(contactId), + message = Value(message); + static Insertable custom({ + Expression? receiptId, + Expression? contactId, + Expression? messageId, + Expression? message, + Expression? contactWillSendsReceipt, + Expression? willBeRetriedByMediaUpload, + Expression? markForRetry, + Expression? markForRetryAfterAccepted, + Expression? ackByServerAt, + Expression? retryCount, + Expression? lastRetry, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (receiptId != null) 'receipt_id': receiptId, + if (contactId != null) 'contact_id': contactId, + if (messageId != null) 'message_id': messageId, + if (message != null) 'message': message, + if (contactWillSendsReceipt != null) + 'contact_will_sends_receipt': contactWillSendsReceipt, + if (willBeRetriedByMediaUpload != null) + 'will_be_retried_by_media_upload': willBeRetriedByMediaUpload, + if (markForRetry != null) 'mark_for_retry': markForRetry, + if (markForRetryAfterAccepted != null) + 'mark_for_retry_after_accepted': markForRetryAfterAccepted, + if (ackByServerAt != null) 'ack_by_server_at': ackByServerAt, + if (retryCount != null) 'retry_count': retryCount, + if (lastRetry != null) 'last_retry': lastRetry, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReceiptsCompanion copyWith({ + Value? receiptId, + Value? contactId, + Value? messageId, + Value? message, + Value? contactWillSendsReceipt, + Value? willBeRetriedByMediaUpload, + Value? markForRetry, + Value? markForRetryAfterAccepted, + Value? ackByServerAt, + Value? retryCount, + Value? lastRetry, + Value? createdAt, + Value? rowid, + }) { + return ReceiptsCompanion( + receiptId: receiptId ?? this.receiptId, + contactId: contactId ?? this.contactId, + messageId: messageId ?? this.messageId, + message: message ?? this.message, + contactWillSendsReceipt: + contactWillSendsReceipt ?? this.contactWillSendsReceipt, + willBeRetriedByMediaUpload: + willBeRetriedByMediaUpload ?? this.willBeRetriedByMediaUpload, + markForRetry: markForRetry ?? this.markForRetry, + markForRetryAfterAccepted: + markForRetryAfterAccepted ?? this.markForRetryAfterAccepted, + ackByServerAt: ackByServerAt ?? this.ackByServerAt, + retryCount: retryCount ?? this.retryCount, + lastRetry: lastRetry ?? this.lastRetry, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (receiptId.present) { + map['receipt_id'] = Variable(receiptId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (message.present) { + map['message'] = Variable(message.value); + } + if (contactWillSendsReceipt.present) { + map['contact_will_sends_receipt'] = Variable( + contactWillSendsReceipt.value, + ); + } + if (willBeRetriedByMediaUpload.present) { + map['will_be_retried_by_media_upload'] = Variable( + willBeRetriedByMediaUpload.value, + ); + } + if (markForRetry.present) { + map['mark_for_retry'] = Variable(markForRetry.value); + } + if (markForRetryAfterAccepted.present) { + map['mark_for_retry_after_accepted'] = Variable( + markForRetryAfterAccepted.value, + ); + } + if (ackByServerAt.present) { + map['ack_by_server_at'] = Variable(ackByServerAt.value); + } + if (retryCount.present) { + map['retry_count'] = Variable(retryCount.value); + } + if (lastRetry.present) { + map['last_retry'] = Variable(lastRetry.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('ReceiptsCompanion(') + ..write('receiptId: $receiptId, ') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('message: $message, ') + ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') + ..write('willBeRetriedByMediaUpload: $willBeRetriedByMediaUpload, ') + ..write('markForRetry: $markForRetry, ') + ..write('markForRetryAfterAccepted: $markForRetryAfterAccepted, ') + ..write('ackByServerAt: $ackByServerAt, ') + ..write('retryCount: $retryCount, ') + ..write('lastRetry: $lastRetry, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class ReceivedReceipts extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + ReceivedReceipts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn receiptId = GeneratedColumn( + 'receipt_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [receiptId, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'received_receipts'; + @override + Set get $primaryKey => {receiptId}; + @override + ReceivedReceiptsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ReceivedReceiptsData( + receiptId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}receipt_id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + ReceivedReceipts createAlias(String alias) { + return ReceivedReceipts(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(receipt_id)']; + @override + bool get dontWriteConstraints => true; +} + +class ReceivedReceiptsData extends DataClass + implements Insertable { + final String receiptId; + final int createdAt; + const ReceivedReceiptsData({ + required this.receiptId, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['receipt_id'] = Variable(receiptId); + map['created_at'] = Variable(createdAt); + return map; + } + + ReceivedReceiptsCompanion toCompanion(bool nullToAbsent) { + return ReceivedReceiptsCompanion( + receiptId: Value(receiptId), + createdAt: Value(createdAt), + ); + } + + factory ReceivedReceiptsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ReceivedReceiptsData( + receiptId: serializer.fromJson(json['receiptId']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'receiptId': serializer.toJson(receiptId), + 'createdAt': serializer.toJson(createdAt), + }; + } + + ReceivedReceiptsData copyWith({String? receiptId, int? createdAt}) => + ReceivedReceiptsData( + receiptId: receiptId ?? this.receiptId, + createdAt: createdAt ?? this.createdAt, + ); + ReceivedReceiptsData copyWithCompanion(ReceivedReceiptsCompanion data) { + return ReceivedReceiptsData( + receiptId: data.receiptId.present ? data.receiptId.value : this.receiptId, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('ReceivedReceiptsData(') + ..write('receiptId: $receiptId, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(receiptId, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ReceivedReceiptsData && + other.receiptId == this.receiptId && + other.createdAt == this.createdAt); +} + +class ReceivedReceiptsCompanion extends UpdateCompanion { + final Value receiptId; + final Value createdAt; + final Value rowid; + const ReceivedReceiptsCompanion({ + this.receiptId = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + ReceivedReceiptsCompanion.insert({ + required String receiptId, + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : receiptId = Value(receiptId); + static Insertable custom({ + Expression? receiptId, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (receiptId != null) 'receipt_id': receiptId, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + ReceivedReceiptsCompanion copyWith({ + Value? receiptId, + Value? createdAt, + Value? rowid, + }) { + return ReceivedReceiptsCompanion( + receiptId: receiptId ?? this.receiptId, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (receiptId.present) { + map['receipt_id'] = Variable(receiptId.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('ReceivedReceiptsCompanion(') + ..write('receiptId: $receiptId, ') + ..write('createdAt: $createdAt, ') + ..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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn identityKey = + GeneratedColumn( + 'identity_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalIdentityKeyStores createAlias(String alias) { + return SignalIdentityKeyStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(device_id, name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalIdentityKeyStoresData extends DataClass + implements Insertable { + final int deviceId; + final String name; + final i2.Uint8List identityKey; + final int 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, + i2.Uint8List? identityKey, + int? 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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn preKey = + GeneratedColumn( + 'pre_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalPreKeyStores createAlias(String alias) { + return SignalPreKeyStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(pre_key_id)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalPreKeyStoresData extends DataClass + implements Insertable { + final int preKeyId; + final i2.Uint8List preKey; + final int 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, + i2.Uint8List? preKey, + int? 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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn senderKey = + GeneratedColumn( + 'sender_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + @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); + } + + @override + List get customConstraints => const ['PRIMARY KEY(sender_key_name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalSenderKeyStoresData extends DataClass + implements Insertable { + final String senderKeyName; + final i2.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, + i2.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 i2.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, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn sessionRecord = + GeneratedColumn( + 'session_record', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + 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.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + SignalSessionStores createAlias(String alias) { + return SignalSessionStores(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(device_id, name)']; + @override + bool get dontWriteConstraints => true; +} + +class SignalSessionStoresData extends DataClass + implements Insertable { + final int deviceId; + final String name; + final i2.Uint8List sessionRecord; + final int 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, + i2.Uint8List? sessionRecord, + int? 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 i2.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 MessageActions extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MessageActions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES messages(message_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn actionAt = GeneratedColumn( + 'action_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [messageId, contactId, type, actionAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'message_actions'; + @override + Set get $primaryKey => {messageId, contactId, type}; + @override + MessageActionsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MessageActionsData( + messageId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}message_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + actionAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}action_at'], + )!, + ); + } + + @override + MessageActions createAlias(String alias) { + return MessageActions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(message_id, contact_id, type)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class MessageActionsData extends DataClass + implements Insertable { + final String messageId; + final int contactId; + final String type; + final int actionAt; + const MessageActionsData({ + required this.messageId, + required this.contactId, + required this.type, + required this.actionAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['message_id'] = Variable(messageId); + map['contact_id'] = Variable(contactId); + map['type'] = Variable(type); + map['action_at'] = Variable(actionAt); + return map; + } + + MessageActionsCompanion toCompanion(bool nullToAbsent) { + return MessageActionsCompanion( + messageId: Value(messageId), + contactId: Value(contactId), + type: Value(type), + actionAt: Value(actionAt), + ); + } + + factory MessageActionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessageActionsData( + messageId: serializer.fromJson(json['messageId']), + contactId: serializer.fromJson(json['contactId']), + type: serializer.fromJson(json['type']), + actionAt: serializer.fromJson(json['actionAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'messageId': serializer.toJson(messageId), + 'contactId': serializer.toJson(contactId), + 'type': serializer.toJson(type), + 'actionAt': serializer.toJson(actionAt), + }; + } + + MessageActionsData copyWith({ + String? messageId, + int? contactId, + String? type, + int? actionAt, + }) => MessageActionsData( + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + ); + MessageActionsData copyWithCompanion(MessageActionsCompanion data) { + return MessageActionsData( + messageId: data.messageId.present ? data.messageId.value : this.messageId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + type: data.type.present ? data.type.value : this.type, + actionAt: data.actionAt.present ? data.actionAt.value : this.actionAt, + ); + } + + @override + String toString() { + return (StringBuffer('MessageActionsData(') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('actionAt: $actionAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(messageId, contactId, type, actionAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessageActionsData && + other.messageId == this.messageId && + other.contactId == this.contactId && + other.type == this.type && + other.actionAt == this.actionAt); +} + +class MessageActionsCompanion extends UpdateCompanion { + final Value messageId; + final Value contactId; + final Value type; + final Value actionAt; + final Value rowid; + const MessageActionsCompanion({ + this.messageId = const Value.absent(), + this.contactId = const Value.absent(), + this.type = const Value.absent(), + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + MessageActionsCompanion.insert({ + required String messageId, + required int contactId, + required String type, + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : messageId = Value(messageId), + contactId = Value(contactId), + type = Value(type); + static Insertable custom({ + Expression? messageId, + Expression? contactId, + Expression? type, + Expression? actionAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (messageId != null) 'message_id': messageId, + if (contactId != null) 'contact_id': contactId, + if (type != null) 'type': type, + if (actionAt != null) 'action_at': actionAt, + if (rowid != null) 'rowid': rowid, + }); + } + + MessageActionsCompanion copyWith({ + Value? messageId, + Value? contactId, + Value? type, + Value? actionAt, + Value? rowid, + }) { + return MessageActionsCompanion( + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (actionAt.present) { + map['action_at'] = Variable(actionAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessageActionsCompanion(') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('actionAt: $actionAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class GroupHistories extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + GroupHistories(this.attachedDatabase, [this._alias]); + late final GeneratedColumn groupHistoryId = GeneratedColumn( + 'group_history_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES "groups"(group_id)ON DELETE CASCADE', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)', + ); + late final GeneratedColumn affectedContactId = GeneratedColumn( + 'affected_contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn oldGroupName = GeneratedColumn( + 'old_group_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn newGroupName = GeneratedColumn( + 'new_group_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn newDeleteMessagesAfterMilliseconds = + GeneratedColumn( + 'new_delete_messages_after_milliseconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn actionAt = GeneratedColumn( + 'action_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [ + groupHistoryId, + groupId, + contactId, + affectedContactId, + oldGroupName, + newGroupName, + newDeleteMessagesAfterMilliseconds, + type, + actionAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'group_histories'; + @override + Set get $primaryKey => {groupHistoryId}; + @override + GroupHistoriesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupHistoriesData( + groupHistoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_history_id'], + )!, + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + affectedContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}affected_contact_id'], + ), + oldGroupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}old_group_name'], + ), + newGroupName: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}new_group_name'], + ), + newDeleteMessagesAfterMilliseconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}new_delete_messages_after_milliseconds'], + ), + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + actionAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}action_at'], + )!, + ); + } + + @override + GroupHistories createAlias(String alias) { + return GroupHistories(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(group_history_id)']; + @override + bool get dontWriteConstraints => true; +} + +class GroupHistoriesData extends DataClass + implements Insertable { + final String groupHistoryId; + final String groupId; + final int? contactId; + final int? affectedContactId; + final String? oldGroupName; + final String? newGroupName; + final int? newDeleteMessagesAfterMilliseconds; + final String type; + final int actionAt; + const GroupHistoriesData({ + required this.groupHistoryId, + required this.groupId, + this.contactId, + this.affectedContactId, + this.oldGroupName, + this.newGroupName, + this.newDeleteMessagesAfterMilliseconds, + required this.type, + required this.actionAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_history_id'] = Variable(groupHistoryId); + map['group_id'] = Variable(groupId); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + if (!nullToAbsent || affectedContactId != null) { + map['affected_contact_id'] = Variable(affectedContactId); + } + if (!nullToAbsent || oldGroupName != null) { + map['old_group_name'] = Variable(oldGroupName); + } + if (!nullToAbsent || newGroupName != null) { + map['new_group_name'] = Variable(newGroupName); + } + if (!nullToAbsent || newDeleteMessagesAfterMilliseconds != null) { + map['new_delete_messages_after_milliseconds'] = Variable( + newDeleteMessagesAfterMilliseconds, + ); + } + map['type'] = Variable(type); + map['action_at'] = Variable(actionAt); + return map; + } + + GroupHistoriesCompanion toCompanion(bool nullToAbsent) { + return GroupHistoriesCompanion( + groupHistoryId: Value(groupHistoryId), + groupId: Value(groupId), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + affectedContactId: affectedContactId == null && nullToAbsent + ? const Value.absent() + : Value(affectedContactId), + oldGroupName: oldGroupName == null && nullToAbsent + ? const Value.absent() + : Value(oldGroupName), + newGroupName: newGroupName == null && nullToAbsent + ? const Value.absent() + : Value(newGroupName), + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds == null && nullToAbsent + ? const Value.absent() + : Value(newDeleteMessagesAfterMilliseconds), + type: Value(type), + actionAt: Value(actionAt), + ); + } + + factory GroupHistoriesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupHistoriesData( + groupHistoryId: serializer.fromJson(json['groupHistoryId']), + groupId: serializer.fromJson(json['groupId']), + contactId: serializer.fromJson(json['contactId']), + affectedContactId: serializer.fromJson(json['affectedContactId']), + oldGroupName: serializer.fromJson(json['oldGroupName']), + newGroupName: serializer.fromJson(json['newGroupName']), + newDeleteMessagesAfterMilliseconds: serializer.fromJson( + json['newDeleteMessagesAfterMilliseconds'], + ), + type: serializer.fromJson(json['type']), + actionAt: serializer.fromJson(json['actionAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupHistoryId': serializer.toJson(groupHistoryId), + 'groupId': serializer.toJson(groupId), + 'contactId': serializer.toJson(contactId), + 'affectedContactId': serializer.toJson(affectedContactId), + 'oldGroupName': serializer.toJson(oldGroupName), + 'newGroupName': serializer.toJson(newGroupName), + 'newDeleteMessagesAfterMilliseconds': serializer.toJson( + newDeleteMessagesAfterMilliseconds, + ), + 'type': serializer.toJson(type), + 'actionAt': serializer.toJson(actionAt), + }; + } + + GroupHistoriesData copyWith({ + String? groupHistoryId, + String? groupId, + Value contactId = const Value.absent(), + Value affectedContactId = const Value.absent(), + Value oldGroupName = const Value.absent(), + Value newGroupName = const Value.absent(), + Value newDeleteMessagesAfterMilliseconds = const Value.absent(), + String? type, + int? actionAt, + }) => GroupHistoriesData( + groupHistoryId: groupHistoryId ?? this.groupHistoryId, + groupId: groupId ?? this.groupId, + contactId: contactId.present ? contactId.value : this.contactId, + affectedContactId: affectedContactId.present + ? affectedContactId.value + : this.affectedContactId, + oldGroupName: oldGroupName.present ? oldGroupName.value : this.oldGroupName, + newGroupName: newGroupName.present ? newGroupName.value : this.newGroupName, + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds.present + ? newDeleteMessagesAfterMilliseconds.value + : this.newDeleteMessagesAfterMilliseconds, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + ); + GroupHistoriesData copyWithCompanion(GroupHistoriesCompanion data) { + return GroupHistoriesData( + groupHistoryId: data.groupHistoryId.present + ? data.groupHistoryId.value + : this.groupHistoryId, + groupId: data.groupId.present ? data.groupId.value : this.groupId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + affectedContactId: data.affectedContactId.present + ? data.affectedContactId.value + : this.affectedContactId, + oldGroupName: data.oldGroupName.present + ? data.oldGroupName.value + : this.oldGroupName, + newGroupName: data.newGroupName.present + ? data.newGroupName.value + : this.newGroupName, + newDeleteMessagesAfterMilliseconds: + data.newDeleteMessagesAfterMilliseconds.present + ? data.newDeleteMessagesAfterMilliseconds.value + : this.newDeleteMessagesAfterMilliseconds, + type: data.type.present ? data.type.value : this.type, + actionAt: data.actionAt.present ? data.actionAt.value : this.actionAt, + ); + } + + @override + String toString() { + return (StringBuffer('GroupHistoriesData(') + ..write('groupHistoryId: $groupHistoryId, ') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('affectedContactId: $affectedContactId, ') + ..write('oldGroupName: $oldGroupName, ') + ..write('newGroupName: $newGroupName, ') + ..write( + 'newDeleteMessagesAfterMilliseconds: $newDeleteMessagesAfterMilliseconds, ', + ) + ..write('type: $type, ') + ..write('actionAt: $actionAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + groupHistoryId, + groupId, + contactId, + affectedContactId, + oldGroupName, + newGroupName, + newDeleteMessagesAfterMilliseconds, + type, + actionAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupHistoriesData && + other.groupHistoryId == this.groupHistoryId && + other.groupId == this.groupId && + other.contactId == this.contactId && + other.affectedContactId == this.affectedContactId && + other.oldGroupName == this.oldGroupName && + other.newGroupName == this.newGroupName && + other.newDeleteMessagesAfterMilliseconds == + this.newDeleteMessagesAfterMilliseconds && + other.type == this.type && + other.actionAt == this.actionAt); +} + +class GroupHistoriesCompanion extends UpdateCompanion { + final Value groupHistoryId; + final Value groupId; + final Value contactId; + final Value affectedContactId; + final Value oldGroupName; + final Value newGroupName; + final Value newDeleteMessagesAfterMilliseconds; + final Value type; + final Value actionAt; + final Value rowid; + const GroupHistoriesCompanion({ + this.groupHistoryId = const Value.absent(), + this.groupId = const Value.absent(), + this.contactId = const Value.absent(), + this.affectedContactId = const Value.absent(), + this.oldGroupName = const Value.absent(), + this.newGroupName = const Value.absent(), + this.newDeleteMessagesAfterMilliseconds = const Value.absent(), + this.type = const Value.absent(), + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupHistoriesCompanion.insert({ + required String groupHistoryId, + required String groupId, + this.contactId = const Value.absent(), + this.affectedContactId = const Value.absent(), + this.oldGroupName = const Value.absent(), + this.newGroupName = const Value.absent(), + this.newDeleteMessagesAfterMilliseconds = const Value.absent(), + required String type, + this.actionAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : groupHistoryId = Value(groupHistoryId), + groupId = Value(groupId), + type = Value(type); + static Insertable custom({ + Expression? groupHistoryId, + Expression? groupId, + Expression? contactId, + Expression? affectedContactId, + Expression? oldGroupName, + Expression? newGroupName, + Expression? newDeleteMessagesAfterMilliseconds, + Expression? type, + Expression? actionAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupHistoryId != null) 'group_history_id': groupHistoryId, + if (groupId != null) 'group_id': groupId, + if (contactId != null) 'contact_id': contactId, + if (affectedContactId != null) 'affected_contact_id': affectedContactId, + if (oldGroupName != null) 'old_group_name': oldGroupName, + if (newGroupName != null) 'new_group_name': newGroupName, + if (newDeleteMessagesAfterMilliseconds != null) + 'new_delete_messages_after_milliseconds': + newDeleteMessagesAfterMilliseconds, + if (type != null) 'type': type, + if (actionAt != null) 'action_at': actionAt, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupHistoriesCompanion copyWith({ + Value? groupHistoryId, + Value? groupId, + Value? contactId, + Value? affectedContactId, + Value? oldGroupName, + Value? newGroupName, + Value? newDeleteMessagesAfterMilliseconds, + Value? type, + Value? actionAt, + Value? rowid, + }) { + return GroupHistoriesCompanion( + groupHistoryId: groupHistoryId ?? this.groupHistoryId, + groupId: groupId ?? this.groupId, + contactId: contactId ?? this.contactId, + affectedContactId: affectedContactId ?? this.affectedContactId, + oldGroupName: oldGroupName ?? this.oldGroupName, + newGroupName: newGroupName ?? this.newGroupName, + newDeleteMessagesAfterMilliseconds: + newDeleteMessagesAfterMilliseconds ?? + this.newDeleteMessagesAfterMilliseconds, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupHistoryId.present) { + map['group_history_id'] = Variable(groupHistoryId.value); + } + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (affectedContactId.present) { + map['affected_contact_id'] = Variable(affectedContactId.value); + } + if (oldGroupName.present) { + map['old_group_name'] = Variable(oldGroupName.value); + } + if (newGroupName.present) { + map['new_group_name'] = Variable(newGroupName.value); + } + if (newDeleteMessagesAfterMilliseconds.present) { + map['new_delete_messages_after_milliseconds'] = Variable( + newDeleteMessagesAfterMilliseconds.value, + ); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (actionAt.present) { + map['action_at'] = Variable(actionAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GroupHistoriesCompanion(') + ..write('groupHistoryId: $groupHistoryId, ') + ..write('groupId: $groupId, ') + ..write('contactId: $contactId, ') + ..write('affectedContactId: $affectedContactId, ') + ..write('oldGroupName: $oldGroupName, ') + ..write('newGroupName: $newGroupName, ') + ..write( + 'newDeleteMessagesAfterMilliseconds: $newDeleteMessagesAfterMilliseconds, ', + ) + ..write('type: $type, ') + ..write('actionAt: $actionAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class KeyVerifications extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + KeyVerifications(this.attachedDatabase, [this._alias]); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [contactId, type, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'key_verifications'; + @override + Set get $primaryKey => {contactId}; + @override + KeyVerificationsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return KeyVerificationsData( + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + KeyVerifications createAlias(String alias) { + return KeyVerifications(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(contact_id)']; + @override + bool get dontWriteConstraints => true; +} + +class KeyVerificationsData extends DataClass + implements Insertable { + final int contactId; + final String type; + final int createdAt; + const KeyVerificationsData({ + required this.contactId, + required this.type, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['contact_id'] = Variable(contactId); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + return map; + } + + KeyVerificationsCompanion toCompanion(bool nullToAbsent) { + return KeyVerificationsCompanion( + contactId: Value(contactId), + type: Value(type), + createdAt: Value(createdAt), + ); + } + + factory KeyVerificationsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return KeyVerificationsData( + contactId: serializer.fromJson(json['contactId']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'contactId': serializer.toJson(contactId), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + }; + } + + KeyVerificationsData copyWith({ + int? contactId, + String? type, + int? createdAt, + }) => KeyVerificationsData( + contactId: contactId ?? this.contactId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + KeyVerificationsData copyWithCompanion(KeyVerificationsCompanion data) { + return KeyVerificationsData( + contactId: data.contactId.present ? data.contactId.value : this.contactId, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('KeyVerificationsData(') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(contactId, type, createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is KeyVerificationsData && + other.contactId == this.contactId && + other.type == this.type && + other.createdAt == this.createdAt); +} + +class KeyVerificationsCompanion extends UpdateCompanion { + final Value contactId; + final Value type; + final Value createdAt; + const KeyVerificationsCompanion({ + this.contactId = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + }); + KeyVerificationsCompanion.insert({ + this.contactId = const Value.absent(), + required String type, + this.createdAt = const Value.absent(), + }) : type = Value(type); + static Insertable custom({ + Expression? contactId, + Expression? type, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (contactId != null) 'contact_id': contactId, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + }); + } + + KeyVerificationsCompanion copyWith({ + Value? contactId, + Value? type, + Value? createdAt, + }) { + return KeyVerificationsCompanion( + contactId: contactId ?? this.contactId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('KeyVerificationsCompanion(') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class VerificationTokens extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + VerificationTokens(this.attachedDatabase, [this._alias]); + late final GeneratedColumn tokenId = GeneratedColumn( + 'token_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn token = + GeneratedColumn( + 'token', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT (CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER))', + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)', + ), + ); + @override + List get $columns => [tokenId, token, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'verification_tokens'; + @override + Set get $primaryKey => {tokenId}; + @override + VerificationTokensData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return VerificationTokensData( + tokenId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}token_id'], + )!, + token: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}token'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + VerificationTokens createAlias(String alias) { + return VerificationTokens(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class VerificationTokensData extends DataClass + implements Insertable { + final int tokenId; + final i2.Uint8List token; + final int createdAt; + const VerificationTokensData({ + required this.tokenId, + required this.token, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['token_id'] = Variable(tokenId); + map['token'] = Variable(token); + map['created_at'] = Variable(createdAt); + return map; + } + + VerificationTokensCompanion toCompanion(bool nullToAbsent) { + return VerificationTokensCompanion( + tokenId: Value(tokenId), + token: Value(token), + createdAt: Value(createdAt), + ); + } + + factory VerificationTokensData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return VerificationTokensData( + tokenId: serializer.fromJson(json['tokenId']), + token: serializer.fromJson(json['token']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'tokenId': serializer.toJson(tokenId), + 'token': serializer.toJson(token), + 'createdAt': serializer.toJson(createdAt), + }; + } + + VerificationTokensData copyWith({ + int? tokenId, + i2.Uint8List? token, + int? createdAt, + }) => VerificationTokensData( + tokenId: tokenId ?? this.tokenId, + token: token ?? this.token, + createdAt: createdAt ?? this.createdAt, + ); + VerificationTokensData copyWithCompanion(VerificationTokensCompanion data) { + return VerificationTokensData( + tokenId: data.tokenId.present ? data.tokenId.value : this.tokenId, + token: data.token.present ? data.token.value : this.token, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('VerificationTokensData(') + ..write('tokenId: $tokenId, ') + ..write('token: $token, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(tokenId, $driftBlobEquality.hash(token), createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is VerificationTokensData && + other.tokenId == this.tokenId && + $driftBlobEquality.equals(other.token, this.token) && + other.createdAt == this.createdAt); +} + +class VerificationTokensCompanion + extends UpdateCompanion { + final Value tokenId; + final Value token; + final Value createdAt; + const VerificationTokensCompanion({ + this.tokenId = const Value.absent(), + this.token = const Value.absent(), + this.createdAt = const Value.absent(), + }); + VerificationTokensCompanion.insert({ + this.tokenId = const Value.absent(), + required i2.Uint8List token, + this.createdAt = const Value.absent(), + }) : token = Value(token); + static Insertable custom({ + Expression? tokenId, + Expression? token, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (tokenId != null) 'token_id': tokenId, + if (token != null) 'token': token, + if (createdAt != null) 'created_at': createdAt, + }); + } + + VerificationTokensCompanion copyWith({ + Value? tokenId, + Value? token, + Value? createdAt, + }) { + return VerificationTokensCompanion( + tokenId: tokenId ?? this.tokenId, + token: token ?? this.token, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (tokenId.present) { + map['token_id'] = Variable(tokenId.value); + } + if (token.present) { + map['token'] = Variable(token.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('VerificationTokensCompanion(') + ..write('tokenId: $tokenId, ') + ..write('token: $token, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryAnnouncedUsers extends Table + with + TableInfo< + UserDiscoveryAnnouncedUsers, + UserDiscoveryAnnouncedUsersData + > { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryAnnouncedUsers(this.attachedDatabase, [this._alias]); + late final GeneratedColumn announcedUserId = GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn announcedPublicKey = + GeneratedColumn( + 'announced_public_key', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicId = GeneratedColumn( + 'public_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL UNIQUE', + ); + late final GeneratedColumn username = GeneratedColumn( + 'username', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn wasShownToTheUser = GeneratedColumn( + 'was_shown_to_the_user', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (was_shown_to_the_user IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn isHidden = GeneratedColumn( + 'is_hidden', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_hidden IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [ + announcedUserId, + announcedPublicKey, + publicId, + username, + wasShownToTheUser, + isHidden, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_announced_users'; + @override + Set get $primaryKey => {announcedUserId}; + @override + UserDiscoveryAnnouncedUsersData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryAnnouncedUsersData( + announcedUserId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}announced_user_id'], + )!, + announcedPublicKey: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}announced_public_key'], + )!, + publicId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_id'], + )!, + username: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}username'], + ), + wasShownToTheUser: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}was_shown_to_the_user'], + )!, + isHidden: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}is_hidden'], + )!, + ); + } + + @override + UserDiscoveryAnnouncedUsers createAlias(String alias) { + return UserDiscoveryAnnouncedUsers(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(announced_user_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryAnnouncedUsersData extends DataClass + implements Insertable { + final int announcedUserId; + final i2.Uint8List announcedPublicKey; + final int publicId; + final String? username; + final int wasShownToTheUser; + final int isHidden; + const UserDiscoveryAnnouncedUsersData({ + required this.announcedUserId, + required this.announcedPublicKey, + required this.publicId, + this.username, + required this.wasShownToTheUser, + required this.isHidden, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['announced_user_id'] = Variable(announcedUserId); + map['announced_public_key'] = Variable(announcedPublicKey); + map['public_id'] = Variable(publicId); + if (!nullToAbsent || username != null) { + map['username'] = Variable(username); + } + map['was_shown_to_the_user'] = Variable(wasShownToTheUser); + map['is_hidden'] = Variable(isHidden); + return map; + } + + UserDiscoveryAnnouncedUsersCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: Value(announcedUserId), + announcedPublicKey: Value(announcedPublicKey), + publicId: Value(publicId), + username: username == null && nullToAbsent + ? const Value.absent() + : Value(username), + wasShownToTheUser: Value(wasShownToTheUser), + isHidden: Value(isHidden), + ); + } + + factory UserDiscoveryAnnouncedUsersData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryAnnouncedUsersData( + announcedUserId: serializer.fromJson(json['announcedUserId']), + announcedPublicKey: serializer.fromJson( + json['announcedPublicKey'], + ), + publicId: serializer.fromJson(json['publicId']), + username: serializer.fromJson(json['username']), + wasShownToTheUser: serializer.fromJson(json['wasShownToTheUser']), + isHidden: serializer.fromJson(json['isHidden']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'announcedUserId': serializer.toJson(announcedUserId), + 'announcedPublicKey': serializer.toJson(announcedPublicKey), + 'publicId': serializer.toJson(publicId), + 'username': serializer.toJson(username), + 'wasShownToTheUser': serializer.toJson(wasShownToTheUser), + 'isHidden': serializer.toJson(isHidden), + }; + } + + UserDiscoveryAnnouncedUsersData copyWith({ + int? announcedUserId, + i2.Uint8List? announcedPublicKey, + int? publicId, + Value username = const Value.absent(), + int? wasShownToTheUser, + int? isHidden, + }) => UserDiscoveryAnnouncedUsersData( + announcedUserId: announcedUserId ?? this.announcedUserId, + announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, + publicId: publicId ?? this.publicId, + username: username.present ? username.value : this.username, + wasShownToTheUser: wasShownToTheUser ?? this.wasShownToTheUser, + isHidden: isHidden ?? this.isHidden, + ); + UserDiscoveryAnnouncedUsersData copyWithCompanion( + UserDiscoveryAnnouncedUsersCompanion data, + ) { + return UserDiscoveryAnnouncedUsersData( + announcedUserId: data.announcedUserId.present + ? data.announcedUserId.value + : this.announcedUserId, + announcedPublicKey: data.announcedPublicKey.present + ? data.announcedPublicKey.value + : this.announcedPublicKey, + publicId: data.publicId.present ? data.publicId.value : this.publicId, + username: data.username.present ? data.username.value : this.username, + wasShownToTheUser: data.wasShownToTheUser.present + ? data.wasShownToTheUser.value + : this.wasShownToTheUser, + isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryAnnouncedUsersData(') + ..write('announcedUserId: $announcedUserId, ') + ..write('announcedPublicKey: $announcedPublicKey, ') + ..write('publicId: $publicId, ') + ..write('username: $username, ') + ..write('wasShownToTheUser: $wasShownToTheUser, ') + ..write('isHidden: $isHidden') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + announcedUserId, + $driftBlobEquality.hash(announcedPublicKey), + publicId, + username, + wasShownToTheUser, + isHidden, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryAnnouncedUsersData && + other.announcedUserId == this.announcedUserId && + $driftBlobEquality.equals( + other.announcedPublicKey, + this.announcedPublicKey, + ) && + other.publicId == this.publicId && + other.username == this.username && + other.wasShownToTheUser == this.wasShownToTheUser && + other.isHidden == this.isHidden); +} + +class UserDiscoveryAnnouncedUsersCompanion + extends UpdateCompanion { + final Value announcedUserId; + final Value announcedPublicKey; + final Value publicId; + final Value username; + final Value wasShownToTheUser; + final Value isHidden; + const UserDiscoveryAnnouncedUsersCompanion({ + this.announcedUserId = const Value.absent(), + this.announcedPublicKey = const Value.absent(), + this.publicId = const Value.absent(), + this.username = const Value.absent(), + this.wasShownToTheUser = const Value.absent(), + this.isHidden = const Value.absent(), + }); + UserDiscoveryAnnouncedUsersCompanion.insert({ + this.announcedUserId = const Value.absent(), + required i2.Uint8List announcedPublicKey, + required int publicId, + this.username = const Value.absent(), + this.wasShownToTheUser = const Value.absent(), + this.isHidden = const Value.absent(), + }) : announcedPublicKey = Value(announcedPublicKey), + publicId = Value(publicId); + static Insertable custom({ + Expression? announcedUserId, + Expression? announcedPublicKey, + Expression? publicId, + Expression? username, + Expression? wasShownToTheUser, + Expression? isHidden, + }) { + return RawValuesInsertable({ + if (announcedUserId != null) 'announced_user_id': announcedUserId, + if (announcedPublicKey != null) + 'announced_public_key': announcedPublicKey, + if (publicId != null) 'public_id': publicId, + if (username != null) 'username': username, + if (wasShownToTheUser != null) 'was_shown_to_the_user': wasShownToTheUser, + if (isHidden != null) 'is_hidden': isHidden, + }); + } + + UserDiscoveryAnnouncedUsersCompanion copyWith({ + Value? announcedUserId, + Value? announcedPublicKey, + Value? publicId, + Value? username, + Value? wasShownToTheUser, + Value? isHidden, + }) { + return UserDiscoveryAnnouncedUsersCompanion( + announcedUserId: announcedUserId ?? this.announcedUserId, + announcedPublicKey: announcedPublicKey ?? this.announcedPublicKey, + publicId: publicId ?? this.publicId, + username: username ?? this.username, + wasShownToTheUser: wasShownToTheUser ?? this.wasShownToTheUser, + isHidden: isHidden ?? this.isHidden, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (announcedUserId.present) { + map['announced_user_id'] = Variable(announcedUserId.value); + } + if (announcedPublicKey.present) { + map['announced_public_key'] = Variable( + announcedPublicKey.value, + ); + } + if (publicId.present) { + map['public_id'] = Variable(publicId.value); + } + if (username.present) { + map['username'] = Variable(username.value); + } + if (wasShownToTheUser.present) { + map['was_shown_to_the_user'] = Variable(wasShownToTheUser.value); + } + if (isHidden.present) { + map['is_hidden'] = Variable(isHidden.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryAnnouncedUsersCompanion(') + ..write('announcedUserId: $announcedUserId, ') + ..write('announcedPublicKey: $announcedPublicKey, ') + ..write('publicId: $publicId, ') + ..write('username: $username, ') + ..write('wasShownToTheUser: $wasShownToTheUser, ') + ..write('isHidden: $isHidden') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryUserRelations extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryUserRelations(this.attachedDatabase, [this._alias]); + late final GeneratedColumn announcedUserId = GeneratedColumn( + 'announced_user_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES user_discovery_announced_users(announced_user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn fromContactId = GeneratedColumn( + 'from_contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn publicKeyVerifiedTimestamp = + GeneratedColumn( + 'public_key_verified_timestamp', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + announcedUserId, + fromContactId, + publicKeyVerifiedTimestamp, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_user_relations'; + @override + Set get $primaryKey => {announcedUserId, fromContactId}; + @override + UserDiscoveryUserRelationsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryUserRelationsData( + announcedUserId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}announced_user_id'], + )!, + fromContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}from_contact_id'], + )!, + publicKeyVerifiedTimestamp: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_key_verified_timestamp'], + ), + ); + } + + @override + UserDiscoveryUserRelations createAlias(String alias) { + return UserDiscoveryUserRelations(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(announced_user_id, from_contact_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryUserRelationsData extends DataClass + implements Insertable { + final int announcedUserId; + final int fromContactId; + final int? publicKeyVerifiedTimestamp; + const UserDiscoveryUserRelationsData({ + required this.announcedUserId, + required this.fromContactId, + this.publicKeyVerifiedTimestamp, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['announced_user_id'] = Variable(announcedUserId); + map['from_contact_id'] = Variable(fromContactId); + if (!nullToAbsent || publicKeyVerifiedTimestamp != null) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp, + ); + } + return map; + } + + UserDiscoveryUserRelationsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryUserRelationsCompanion( + announcedUserId: Value(announcedUserId), + fromContactId: Value(fromContactId), + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp == null && nullToAbsent + ? const Value.absent() + : Value(publicKeyVerifiedTimestamp), + ); + } + + factory UserDiscoveryUserRelationsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryUserRelationsData( + announcedUserId: serializer.fromJson(json['announcedUserId']), + fromContactId: serializer.fromJson(json['fromContactId']), + publicKeyVerifiedTimestamp: serializer.fromJson( + json['publicKeyVerifiedTimestamp'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'announcedUserId': serializer.toJson(announcedUserId), + 'fromContactId': serializer.toJson(fromContactId), + 'publicKeyVerifiedTimestamp': serializer.toJson( + publicKeyVerifiedTimestamp, + ), + }; + } + + UserDiscoveryUserRelationsData copyWith({ + int? announcedUserId, + int? fromContactId, + Value publicKeyVerifiedTimestamp = const Value.absent(), + }) => UserDiscoveryUserRelationsData( + announcedUserId: announcedUserId ?? this.announcedUserId, + fromContactId: fromContactId ?? this.fromContactId, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp.present + ? publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + UserDiscoveryUserRelationsData copyWithCompanion( + UserDiscoveryUserRelationsCompanion data, + ) { + return UserDiscoveryUserRelationsData( + announcedUserId: data.announcedUserId.present + ? data.announcedUserId.value + : this.announcedUserId, + fromContactId: data.fromContactId.present + ? data.fromContactId.value + : this.fromContactId, + publicKeyVerifiedTimestamp: data.publicKeyVerifiedTimestamp.present + ? data.publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryUserRelationsData(') + ..write('announcedUserId: $announcedUserId, ') + ..write('fromContactId: $fromContactId, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(announcedUserId, fromContactId, publicKeyVerifiedTimestamp); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryUserRelationsData && + other.announcedUserId == this.announcedUserId && + other.fromContactId == this.fromContactId && + other.publicKeyVerifiedTimestamp == this.publicKeyVerifiedTimestamp); +} + +class UserDiscoveryUserRelationsCompanion + extends UpdateCompanion { + final Value announcedUserId; + final Value fromContactId; + final Value publicKeyVerifiedTimestamp; + final Value rowid; + const UserDiscoveryUserRelationsCompanion({ + this.announcedUserId = const Value.absent(), + this.fromContactId = const Value.absent(), + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }); + UserDiscoveryUserRelationsCompanion.insert({ + required int announcedUserId, + required int fromContactId, + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }) : announcedUserId = Value(announcedUserId), + fromContactId = Value(fromContactId); + static Insertable custom({ + Expression? announcedUserId, + Expression? fromContactId, + Expression? publicKeyVerifiedTimestamp, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (announcedUserId != null) 'announced_user_id': announcedUserId, + if (fromContactId != null) 'from_contact_id': fromContactId, + if (publicKeyVerifiedTimestamp != null) + 'public_key_verified_timestamp': publicKeyVerifiedTimestamp, + if (rowid != null) 'rowid': rowid, + }); + } + + UserDiscoveryUserRelationsCompanion copyWith({ + Value? announcedUserId, + Value? fromContactId, + Value? publicKeyVerifiedTimestamp, + Value? rowid, + }) { + return UserDiscoveryUserRelationsCompanion( + announcedUserId: announcedUserId ?? this.announcedUserId, + fromContactId: fromContactId ?? this.fromContactId, + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp ?? this.publicKeyVerifiedTimestamp, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (announcedUserId.present) { + map['announced_user_id'] = Variable(announcedUserId.value); + } + if (fromContactId.present) { + map['from_contact_id'] = Variable(fromContactId.value); + } + if (publicKeyVerifiedTimestamp.present) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp.value, + ); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryUserRelationsCompanion(') + ..write('announcedUserId: $announcedUserId, ') + ..write('fromContactId: $fromContactId, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryOtherPromotions extends Table + with + TableInfo< + UserDiscoveryOtherPromotions, + UserDiscoveryOtherPromotionsData + > { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryOtherPromotions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn fromContactId = GeneratedColumn( + 'from_contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn promotionId = GeneratedColumn( + 'promotion_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicId = GeneratedColumn( + 'public_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn threshold = GeneratedColumn( + 'threshold', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn announcementShare = + GeneratedColumn( + 'announcement_share', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicKeyVerifiedTimestamp = + GeneratedColumn( + 'public_key_verified_timestamp', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + fromContactId, + promotionId, + publicId, + threshold, + announcementShare, + publicKeyVerifiedTimestamp, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_other_promotions'; + @override + Set get $primaryKey => {fromContactId, promotionId}; + @override + UserDiscoveryOtherPromotionsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryOtherPromotionsData( + fromContactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}from_contact_id'], + )!, + promotionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}promotion_id'], + )!, + publicId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_id'], + )!, + threshold: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}threshold'], + )!, + announcementShare: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}announcement_share'], + )!, + publicKeyVerifiedTimestamp: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}public_key_verified_timestamp'], + ), + ); + } + + @override + UserDiscoveryOtherPromotions createAlias(String alias) { + return UserDiscoveryOtherPromotions(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'PRIMARY KEY(from_contact_id, promotion_id)', + ]; + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryOtherPromotionsData extends DataClass + implements Insertable { + final int fromContactId; + final int promotionId; + final int publicId; + final int threshold; + final i2.Uint8List announcementShare; + final int? publicKeyVerifiedTimestamp; + const UserDiscoveryOtherPromotionsData({ + required this.fromContactId, + required this.promotionId, + required this.publicId, + required this.threshold, + required this.announcementShare, + this.publicKeyVerifiedTimestamp, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['from_contact_id'] = Variable(fromContactId); + map['promotion_id'] = Variable(promotionId); + map['public_id'] = Variable(publicId); + map['threshold'] = Variable(threshold); + map['announcement_share'] = Variable(announcementShare); + if (!nullToAbsent || publicKeyVerifiedTimestamp != null) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp, + ); + } + return map; + } + + UserDiscoveryOtherPromotionsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryOtherPromotionsCompanion( + fromContactId: Value(fromContactId), + promotionId: Value(promotionId), + publicId: Value(publicId), + threshold: Value(threshold), + announcementShare: Value(announcementShare), + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp == null && nullToAbsent + ? const Value.absent() + : Value(publicKeyVerifiedTimestamp), + ); + } + + factory UserDiscoveryOtherPromotionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryOtherPromotionsData( + fromContactId: serializer.fromJson(json['fromContactId']), + promotionId: serializer.fromJson(json['promotionId']), + publicId: serializer.fromJson(json['publicId']), + threshold: serializer.fromJson(json['threshold']), + announcementShare: serializer.fromJson( + json['announcementShare'], + ), + publicKeyVerifiedTimestamp: serializer.fromJson( + json['publicKeyVerifiedTimestamp'], + ), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'fromContactId': serializer.toJson(fromContactId), + 'promotionId': serializer.toJson(promotionId), + 'publicId': serializer.toJson(publicId), + 'threshold': serializer.toJson(threshold), + 'announcementShare': serializer.toJson(announcementShare), + 'publicKeyVerifiedTimestamp': serializer.toJson( + publicKeyVerifiedTimestamp, + ), + }; + } + + UserDiscoveryOtherPromotionsData copyWith({ + int? fromContactId, + int? promotionId, + int? publicId, + int? threshold, + i2.Uint8List? announcementShare, + Value publicKeyVerifiedTimestamp = const Value.absent(), + }) => UserDiscoveryOtherPromotionsData( + fromContactId: fromContactId ?? this.fromContactId, + promotionId: promotionId ?? this.promotionId, + publicId: publicId ?? this.publicId, + threshold: threshold ?? this.threshold, + announcementShare: announcementShare ?? this.announcementShare, + publicKeyVerifiedTimestamp: publicKeyVerifiedTimestamp.present + ? publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + UserDiscoveryOtherPromotionsData copyWithCompanion( + UserDiscoveryOtherPromotionsCompanion data, + ) { + return UserDiscoveryOtherPromotionsData( + fromContactId: data.fromContactId.present + ? data.fromContactId.value + : this.fromContactId, + promotionId: data.promotionId.present + ? data.promotionId.value + : this.promotionId, + publicId: data.publicId.present ? data.publicId.value : this.publicId, + threshold: data.threshold.present ? data.threshold.value : this.threshold, + announcementShare: data.announcementShare.present + ? data.announcementShare.value + : this.announcementShare, + publicKeyVerifiedTimestamp: data.publicKeyVerifiedTimestamp.present + ? data.publicKeyVerifiedTimestamp.value + : this.publicKeyVerifiedTimestamp, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOtherPromotionsData(') + ..write('fromContactId: $fromContactId, ') + ..write('promotionId: $promotionId, ') + ..write('publicId: $publicId, ') + ..write('threshold: $threshold, ') + ..write('announcementShare: $announcementShare, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + fromContactId, + promotionId, + publicId, + threshold, + $driftBlobEquality.hash(announcementShare), + publicKeyVerifiedTimestamp, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryOtherPromotionsData && + other.fromContactId == this.fromContactId && + other.promotionId == this.promotionId && + other.publicId == this.publicId && + other.threshold == this.threshold && + $driftBlobEquality.equals( + other.announcementShare, + this.announcementShare, + ) && + other.publicKeyVerifiedTimestamp == this.publicKeyVerifiedTimestamp); +} + +class UserDiscoveryOtherPromotionsCompanion + extends UpdateCompanion { + final Value fromContactId; + final Value promotionId; + final Value publicId; + final Value threshold; + final Value announcementShare; + final Value publicKeyVerifiedTimestamp; + final Value rowid; + const UserDiscoveryOtherPromotionsCompanion({ + this.fromContactId = const Value.absent(), + this.promotionId = const Value.absent(), + this.publicId = const Value.absent(), + this.threshold = const Value.absent(), + this.announcementShare = const Value.absent(), + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }); + UserDiscoveryOtherPromotionsCompanion.insert({ + required int fromContactId, + required int promotionId, + required int publicId, + required int threshold, + required i2.Uint8List announcementShare, + this.publicKeyVerifiedTimestamp = const Value.absent(), + this.rowid = const Value.absent(), + }) : fromContactId = Value(fromContactId), + promotionId = Value(promotionId), + publicId = Value(publicId), + threshold = Value(threshold), + announcementShare = Value(announcementShare); + static Insertable custom({ + Expression? fromContactId, + Expression? promotionId, + Expression? publicId, + Expression? threshold, + Expression? announcementShare, + Expression? publicKeyVerifiedTimestamp, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (fromContactId != null) 'from_contact_id': fromContactId, + if (promotionId != null) 'promotion_id': promotionId, + if (publicId != null) 'public_id': publicId, + if (threshold != null) 'threshold': threshold, + if (announcementShare != null) 'announcement_share': announcementShare, + if (publicKeyVerifiedTimestamp != null) + 'public_key_verified_timestamp': publicKeyVerifiedTimestamp, + if (rowid != null) 'rowid': rowid, + }); + } + + UserDiscoveryOtherPromotionsCompanion copyWith({ + Value? fromContactId, + Value? promotionId, + Value? publicId, + Value? threshold, + Value? announcementShare, + Value? publicKeyVerifiedTimestamp, + Value? rowid, + }) { + return UserDiscoveryOtherPromotionsCompanion( + fromContactId: fromContactId ?? this.fromContactId, + promotionId: promotionId ?? this.promotionId, + publicId: publicId ?? this.publicId, + threshold: threshold ?? this.threshold, + announcementShare: announcementShare ?? this.announcementShare, + publicKeyVerifiedTimestamp: + publicKeyVerifiedTimestamp ?? this.publicKeyVerifiedTimestamp, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (fromContactId.present) { + map['from_contact_id'] = Variable(fromContactId.value); + } + if (promotionId.present) { + map['promotion_id'] = Variable(promotionId.value); + } + if (publicId.present) { + map['public_id'] = Variable(publicId.value); + } + if (threshold.present) { + map['threshold'] = Variable(threshold.value); + } + if (announcementShare.present) { + map['announcement_share'] = Variable( + announcementShare.value, + ); + } + if (publicKeyVerifiedTimestamp.present) { + map['public_key_verified_timestamp'] = Variable( + publicKeyVerifiedTimestamp.value, + ); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOtherPromotionsCompanion(') + ..write('fromContactId: $fromContactId, ') + ..write('promotionId: $promotionId, ') + ..write('publicId: $publicId, ') + ..write('threshold: $threshold, ') + ..write('announcementShare: $announcementShare, ') + ..write('publicKeyVerifiedTimestamp: $publicKeyVerifiedTimestamp, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryOwnPromotions extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryOwnPromotions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn versionId = GeneratedColumn( + 'version_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: + 'NOT NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + late final GeneratedColumn promotion = + GeneratedColumn( + 'promotion', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + @override + List get $columns => [versionId, contactId, promotion]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_own_promotions'; + @override + Set get $primaryKey => {versionId}; + @override + UserDiscoveryOwnPromotionsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoveryOwnPromotionsData( + versionId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}version_id'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + )!, + promotion: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}promotion'], + )!, + ); + } + + @override + UserDiscoveryOwnPromotions createAlias(String alias) { + return UserDiscoveryOwnPromotions(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoveryOwnPromotionsData extends DataClass + implements Insertable { + final int versionId; + final int contactId; + final i2.Uint8List promotion; + const UserDiscoveryOwnPromotionsData({ + required this.versionId, + required this.contactId, + required this.promotion, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['version_id'] = Variable(versionId); + map['contact_id'] = Variable(contactId); + map['promotion'] = Variable(promotion); + return map; + } + + UserDiscoveryOwnPromotionsCompanion toCompanion(bool nullToAbsent) { + return UserDiscoveryOwnPromotionsCompanion( + versionId: Value(versionId), + contactId: Value(contactId), + promotion: Value(promotion), + ); + } + + factory UserDiscoveryOwnPromotionsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoveryOwnPromotionsData( + versionId: serializer.fromJson(json['versionId']), + contactId: serializer.fromJson(json['contactId']), + promotion: serializer.fromJson(json['promotion']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'versionId': serializer.toJson(versionId), + 'contactId': serializer.toJson(contactId), + 'promotion': serializer.toJson(promotion), + }; + } + + UserDiscoveryOwnPromotionsData copyWith({ + int? versionId, + int? contactId, + i2.Uint8List? promotion, + }) => UserDiscoveryOwnPromotionsData( + versionId: versionId ?? this.versionId, + contactId: contactId ?? this.contactId, + promotion: promotion ?? this.promotion, + ); + UserDiscoveryOwnPromotionsData copyWithCompanion( + UserDiscoveryOwnPromotionsCompanion data, + ) { + return UserDiscoveryOwnPromotionsData( + versionId: data.versionId.present ? data.versionId.value : this.versionId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + promotion: data.promotion.present ? data.promotion.value : this.promotion, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOwnPromotionsData(') + ..write('versionId: $versionId, ') + ..write('contactId: $contactId, ') + ..write('promotion: $promotion') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(versionId, contactId, $driftBlobEquality.hash(promotion)); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoveryOwnPromotionsData && + other.versionId == this.versionId && + other.contactId == this.contactId && + $driftBlobEquality.equals(other.promotion, this.promotion)); +} + +class UserDiscoveryOwnPromotionsCompanion + extends UpdateCompanion { + final Value versionId; + final Value contactId; + final Value promotion; + const UserDiscoveryOwnPromotionsCompanion({ + this.versionId = const Value.absent(), + this.contactId = const Value.absent(), + this.promotion = const Value.absent(), + }); + UserDiscoveryOwnPromotionsCompanion.insert({ + this.versionId = const Value.absent(), + required int contactId, + required i2.Uint8List promotion, + }) : contactId = Value(contactId), + promotion = Value(promotion); + static Insertable custom({ + Expression? versionId, + Expression? contactId, + Expression? promotion, + }) { + return RawValuesInsertable({ + if (versionId != null) 'version_id': versionId, + if (contactId != null) 'contact_id': contactId, + if (promotion != null) 'promotion': promotion, + }); + } + + UserDiscoveryOwnPromotionsCompanion copyWith({ + Value? versionId, + Value? contactId, + Value? promotion, + }) { + return UserDiscoveryOwnPromotionsCompanion( + versionId: versionId ?? this.versionId, + contactId: contactId ?? this.contactId, + promotion: promotion ?? this.promotion, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (versionId.present) { + map['version_id'] = Variable(versionId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (promotion.present) { + map['promotion'] = Variable(promotion.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoveryOwnPromotionsCompanion(') + ..write('versionId: $versionId, ') + ..write('contactId: $contactId, ') + ..write('promotion: $promotion') + ..write(')')) + .toString(); + } +} + +class UserDiscoveryShares extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserDiscoveryShares(this.attachedDatabase, [this._alias]); + late final GeneratedColumn shareId = GeneratedColumn( + 'share_id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT', + ); + late final GeneratedColumn share = + GeneratedColumn( + 'share', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL REFERENCES contacts(user_id)ON DELETE CASCADE', + ); + @override + List get $columns => [shareId, share, contactId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_discovery_shares'; + @override + Set get $primaryKey => {shareId}; + @override + UserDiscoverySharesData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserDiscoverySharesData( + shareId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}share_id'], + )!, + share: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}share'], + )!, + contactId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}contact_id'], + ), + ); + } + + @override + UserDiscoveryShares createAlias(String alias) { + return UserDiscoveryShares(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; +} + +class UserDiscoverySharesData extends DataClass + implements Insertable { + final int shareId; + final i2.Uint8List share; + final int? contactId; + const UserDiscoverySharesData({ + required this.shareId, + required this.share, + this.contactId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['share_id'] = Variable(shareId); + map['share'] = Variable(share); + if (!nullToAbsent || contactId != null) { + map['contact_id'] = Variable(contactId); + } + return map; + } + + UserDiscoverySharesCompanion toCompanion(bool nullToAbsent) { + return UserDiscoverySharesCompanion( + shareId: Value(shareId), + share: Value(share), + contactId: contactId == null && nullToAbsent + ? const Value.absent() + : Value(contactId), + ); + } + + factory UserDiscoverySharesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserDiscoverySharesData( + shareId: serializer.fromJson(json['shareId']), + share: serializer.fromJson(json['share']), + contactId: serializer.fromJson(json['contactId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'shareId': serializer.toJson(shareId), + 'share': serializer.toJson(share), + 'contactId': serializer.toJson(contactId), + }; + } + + UserDiscoverySharesData copyWith({ + int? shareId, + i2.Uint8List? share, + Value contactId = const Value.absent(), + }) => UserDiscoverySharesData( + shareId: shareId ?? this.shareId, + share: share ?? this.share, + contactId: contactId.present ? contactId.value : this.contactId, + ); + UserDiscoverySharesData copyWithCompanion(UserDiscoverySharesCompanion data) { + return UserDiscoverySharesData( + shareId: data.shareId.present ? data.shareId.value : this.shareId, + share: data.share.present ? data.share.value : this.share, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + ); + } + + @override + String toString() { + return (StringBuffer('UserDiscoverySharesData(') + ..write('shareId: $shareId, ') + ..write('share: $share, ') + ..write('contactId: $contactId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(shareId, $driftBlobEquality.hash(share), contactId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserDiscoverySharesData && + other.shareId == this.shareId && + $driftBlobEquality.equals(other.share, this.share) && + other.contactId == this.contactId); +} + +class UserDiscoverySharesCompanion + extends UpdateCompanion { + final Value shareId; + final Value share; + final Value contactId; + const UserDiscoverySharesCompanion({ + this.shareId = const Value.absent(), + this.share = const Value.absent(), + this.contactId = const Value.absent(), + }); + UserDiscoverySharesCompanion.insert({ + this.shareId = const Value.absent(), + required i2.Uint8List share, + this.contactId = const Value.absent(), + }) : share = Value(share); + static Insertable custom({ + Expression? shareId, + Expression? share, + Expression? contactId, + }) { + return RawValuesInsertable({ + if (shareId != null) 'share_id': shareId, + if (share != null) 'share': share, + if (contactId != null) 'contact_id': contactId, + }); + } + + UserDiscoverySharesCompanion copyWith({ + Value? shareId, + Value? share, + Value? contactId, + }) { + return UserDiscoverySharesCompanion( + shareId: shareId ?? this.shareId, + share: share ?? this.share, + contactId: contactId ?? this.contactId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (shareId.present) { + map['share_id'] = Variable(shareId.value); + } + if (share.present) { + map['share'] = Variable(share.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserDiscoverySharesCompanion(') + ..write('shareId: $shareId, ') + ..write('share: $share, ') + ..write('contactId: $contactId') + ..write(')')) + .toString(); + } +} + +class DatabaseAtV15 extends GeneratedDatabase { + DatabaseAtV15(QueryExecutor e) : super(e); + late final Contacts contacts = Contacts(this); + late final Groups groups = Groups(this); + late final MediaFiles mediaFiles = MediaFiles(this); + late final Messages messages = Messages(this); + late final MessageHistories messageHistories = MessageHistories(this); + late final Reactions reactions = Reactions(this); + late final GroupMembers groupMembers = GroupMembers(this); + late final Receipts receipts = Receipts(this); + late final ReceivedReceipts receivedReceipts = ReceivedReceipts(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 MessageActions messageActions = MessageActions(this); + late final GroupHistories groupHistories = GroupHistories(this); + late final KeyVerifications keyVerifications = KeyVerifications(this); + late final VerificationTokens verificationTokens = VerificationTokens(this); + late final UserDiscoveryAnnouncedUsers userDiscoveryAnnouncedUsers = + UserDiscoveryAnnouncedUsers(this); + late final UserDiscoveryUserRelations userDiscoveryUserRelations = + UserDiscoveryUserRelations(this); + late final UserDiscoveryOtherPromotions userDiscoveryOtherPromotions = + UserDiscoveryOtherPromotions(this); + late final UserDiscoveryOwnPromotions userDiscoveryOwnPromotions = + UserDiscoveryOwnPromotions(this); + late final UserDiscoveryShares userDiscoveryShares = UserDiscoveryShares( + this, + ); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + contacts, + groups, + mediaFiles, + messages, + messageHistories, + reactions, + groupMembers, + receipts, + receivedReceipts, + signalIdentityKeyStores, + signalPreKeyStores, + signalSenderKeyStores, + signalSessionStores, + messageActions, + groupHistories, + keyVerifications, + verificationTokens, + userDiscoveryAnnouncedUsers, + userDiscoveryUserRelations, + userDiscoveryOtherPromotions, + userDiscoveryOwnPromotions, + userDiscoveryShares, + ]; + @override + StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules([ + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('messages', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'media_files', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('messages', kind: UpdateKind.update)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('reactions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('reactions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_members', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('receipts', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('receipts', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'messages', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_actions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('message_actions', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'groups', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_histories', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('key_verifications', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'user_discovery_announced_users', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_user_relations', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_user_relations', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_other_promotions', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [ + TableUpdate('user_discovery_own_promotions', kind: UpdateKind.delete), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'contacts', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('user_discovery_shares', kind: UpdateKind.delete)], + ), + ]); + @override + int get schemaVersion => 15; +} From d9f9f7645ef32f0f6c0c0dd13c878feeaae0e10a Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 21 Apr 2026 02:15:31 +0200 Subject: [PATCH 22/86] replace globals with app environment --- lib/globals.dart | 18 +++++++++++++----- lib/main.dart | 15 ++++----------- lib/src/localization/translations | 2 +- .../callback_dispatcher.background.dart | 5 ++--- lib/src/services/backup/create.backup.dart | 10 ++++++---- lib/src/services/backup/restore.backup.dart | 2 +- .../services/mediafiles/mediafile.service.dart | 4 ++-- lib/src/utils/avatars.dart | 2 +- lib/src/utils/exclusive_access.dart | 2 +- lib/src/utils/keyvalue.dart | 2 +- lib/src/utils/log.dart | 10 +++++----- .../camera_preview_controller_view.dart | 2 +- .../main_camera_controller.dart | 13 +++++++------ .../zoom_selector.dart | 4 ++-- .../data_and_storage/export_media.view.dart | 2 +- 15 files changed, 48 insertions(+), 45 deletions(-) diff --git a/lib/globals.dart b/lib/globals.dart index f446d5a0..8c066fa9 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -1,17 +1,28 @@ import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/model/json/userdata.dart'; import 'package:twonly/src/services/api.service.dart'; import 'package:twonly/src/services/subscription.service.dart'; +class AppEnvironment { + static late final String cacheDir; + static late final String supportDir; + static late final List cameras; + + static Future init() async { + cacheDir = (await getApplicationCacheDirectory()).path; + supportDir = (await getApplicationSupportDirectory()).path; + cameras = await availableCameras(); + } +} + late ApiService apiService; // uses for background notification late TwonlyDB twonlyDB; -List gCameras = []; - // Cached UserData in the memory. Every time the user data is changed the `updateUserdata` function is called, // which will update this global variable. The variable is set in the main.dart and after the user has registered in the register.view.dart late UserData gUser; @@ -36,8 +47,5 @@ bool globalIsInBackgroundTask = false; bool globalAllowErrorTrackingViaSentry = false; bool globalGotMessageFromServer = false; -late String globalApplicationCacheDirectory; -late String globalApplicationSupportDirectory; - final GlobalKey globalRootScaffoldMessengerKey = GlobalKey(); diff --git a/lib/main.dart b/lib/main.dart index 98ff7781..e09651bf 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,11 +1,9 @@ import 'dart:async'; import 'dart:io'; -import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:twonly/app.dart'; @@ -35,10 +33,7 @@ void main() async { SentryWidgetsFlutterBinding.ensureInitialized(); await RustLib.init(); - - globalApplicationCacheDirectory = (await getApplicationCacheDirectory()).path; - globalApplicationSupportDirectory = - (await getApplicationSupportDirectory()).path; + await AppEnvironment.init(); initLogger(); @@ -46,8 +41,8 @@ void main() async { await bridge.initializeTwonlyFlutter( config: bridge.TwonlyConfig( - databasePath: '$globalApplicationSupportDirectory/twonly.sqlite', - dataDirectory: globalApplicationSupportDirectory, + databasePath: '${AppEnvironment.supportDir}/twonly.sqlite', + dataDirectory: AppEnvironment.supportDir, ), ); @@ -56,7 +51,7 @@ void main() async { var user = await getUser(); if (Platform.isIOS && user != null) { - final db = File('$globalApplicationSupportDirectory/twonly.sqlite'); + final db = File('${AppEnvironment.supportDir}/twonly.sqlite'); if (!db.existsSync()) { Log.error('[twonly] IOS: App was removed and then reinstalled again...'); await const FlutterSecureStorage().deleteAll(); @@ -92,8 +87,6 @@ void main() async { unawaited(setupPushNotification()); - gCameras = await availableCameras(); - apiService = ApiService(); twonlyDB = TwonlyDB(); diff --git a/lib/src/localization/translations b/lib/src/localization/translations index 0029f698..e1ac9e6c 160000 --- a/lib/src/localization/translations +++ b/lib/src/localization/translations @@ -1 +1 @@ -Subproject commit 0029f698ea3deb47dedc4ee1f37e5688d1f83f9b +Subproject commit e1ac9e6c476f82819063a8087af4d42acc1167d4 diff --git a/lib/src/services/background/callback_dispatcher.background.dart b/lib/src/services/background/callback_dispatcher.background.dart index a1460266..e3828add 100644 --- a/lib/src/services/background/callback_dispatcher.background.dart +++ b/lib/src/services/background/callback_dispatcher.background.dart @@ -62,9 +62,8 @@ Future initBackgroundExecution() async { } SentryWidgetsFlutterBinding.ensureInitialized(); - globalApplicationCacheDirectory = (await getApplicationCacheDirectory()).path; - globalApplicationSupportDirectory = - (await getApplicationSupportDirectory()).path; + AppEnvironment.cacheDir = (await getApplicationCacheDirectory()).path; + AppEnvironment.supportDir = (await getApplicationSupportDirectory()).path; initLogger(); diff --git a/lib/src/services/backup/create.backup.dart b/lib/src/services/backup/create.backup.dart index 97b74ed8..a03c7e6f 100644 --- a/lib/src/services/backup/create.backup.dart +++ b/lib/src/services/backup/create.backup.dart @@ -41,9 +41,9 @@ Future performTwonlySafeBackup({bool force = false}) async { Log.info('Starting new twonly Backup!'); - final baseDir = globalApplicationSupportDirectory; - - final backupDir = Directory(join(baseDir, 'backup_twonly_safe/')); + final backupDir = Directory( + join(AppEnvironment.supportDir, 'backup_twonly_safe/'), + ); await backupDir.create(recursive: true); final backupDatabaseFile = File(join(backupDir.path, 'twonly.backup.sqlite')); @@ -53,7 +53,9 @@ Future performTwonlySafeBackup({bool force = false}) async { ); // copy database - final originalDatabase = File(join(baseDir, 'twonly.sqlite')); + final originalDatabase = File( + join(AppEnvironment.supportDir, 'twonly.sqlite'), + ); await originalDatabase.copy(backupDatabaseFile.path); driftRuntimeOptions.dontWarnAboutMultipleDatabases = true; diff --git a/lib/src/services/backup/restore.backup.dart b/lib/src/services/backup/restore.backup.dart index 006d43fe..099bb000 100644 --- a/lib/src/services/backup/restore.backup.dart +++ b/lib/src/services/backup/restore.backup.dart @@ -90,7 +90,7 @@ Future handleBackupData( ); final originalDatabase = File( - join(globalApplicationSupportDirectory, 'twonly.sqlite'), + join(AppEnvironment.supportDir, 'twonly.sqlite'), ); await originalDatabase.writeAsBytes(backupContent.twonlyDatabase); diff --git a/lib/src/services/mediafiles/mediafile.service.dart b/lib/src/services/mediafiles/mediafile.service.dart index 6fb18271..1e5424ca 100644 --- a/lib/src/services/mediafiles/mediafile.service.dart +++ b/lib/src/services/mediafiles/mediafile.service.dart @@ -27,7 +27,7 @@ class MediaFileService { try { final tempDirectory = MediaFileService.buildDirectoryPath( 'tmp', - globalApplicationSupportDirectory, + AppEnvironment.supportDir, ); final files = tempDirectory.listSync(); @@ -307,7 +307,7 @@ class MediaFileService { } final mediaBaseDir = buildDirectoryPath( directory, - globalApplicationSupportDirectory, + AppEnvironment.supportDir, ); return File( join(mediaBaseDir.path, '${mediaFile.mediaId}$namePrefix.$extension'), diff --git a/lib/src/utils/avatars.dart b/lib/src/utils/avatars.dart index d1fcd694..a2648694 100644 --- a/lib/src/utils/avatars.dart +++ b/lib/src/utils/avatars.dart @@ -37,7 +37,7 @@ Future createPushAvatars({int? forceForUserId}) async { File avatarPNGFile(int contactId) { final avatarsDirectory = Directory( - '$globalApplicationCacheDirectory/avatars', + '${AppEnvironment.cacheDir}/avatars', ); if (!avatarsDirectory.existsSync()) { diff --git a/lib/src/utils/exclusive_access.dart b/lib/src/utils/exclusive_access.dart index d2a4253a..fb64a397 100644 --- a/lib/src/utils/exclusive_access.dart +++ b/lib/src/utils/exclusive_access.dart @@ -8,7 +8,7 @@ Future exclusiveAccess({ required Future Function() action, required Mutex mutex, }) async { - final lockFile = File('$globalApplicationSupportDirectory/$lockName.lock'); + final lockFile = File('${AppEnvironment.supportDir}/$lockName.lock'); return mutex.protect(() async { var lockAcquired = false; diff --git a/lib/src/utils/keyvalue.dart b/lib/src/utils/keyvalue.dart index 10e62f30..f970691b 100644 --- a/lib/src/utils/keyvalue.dart +++ b/lib/src/utils/keyvalue.dart @@ -5,7 +5,7 @@ import 'package:twonly/src/utils/log.dart'; class KeyValueStore { static Future _getFilePath(String key) async { - return File('$globalApplicationSupportDirectory/keyvalue/$key.json'); + return File('${AppEnvironment.supportDir}/keyvalue/$key.json'); } static Future delete(String key) async { diff --git a/lib/src/utils/log.dart b/lib/src/utils/log.dart index 29281db3..a8be4bc3 100644 --- a/lib/src/utils/log.dart +++ b/lib/src/utils/log.dart @@ -72,7 +72,7 @@ class Log { Future loadLogFile() async { return _protectFileAccess(() async { - final logFile = File('$globalApplicationSupportDirectory/app.log'); + final logFile = File('${AppEnvironment.supportDir}/app.log'); if (logFile.existsSync()) { return logFile.readAsString(); @@ -84,7 +84,7 @@ Future loadLogFile() async { Future readLast1000Lines() async { return _protectFileAccess(() async { - final file = File('$globalApplicationSupportDirectory/app.log'); + final file = File('${AppEnvironment.supportDir}/app.log'); if (!file.existsSync()) return ''; final all = await file.readAsLines(); final start = all.length > 1000 ? all.length - 1000 : 0; @@ -103,7 +103,7 @@ Future _protectFileAccess(Future Function() action) async { } Future _writeLogToFile(LogRecord record) async { - final logFile = File('$globalApplicationSupportDirectory/app.log'); + final logFile = File('${AppEnvironment.supportDir}/app.log'); final logMessage = '${clock.now().toString().split(".")[0]} ${record.level.name} [twonly] ${record.loggerName} > ${record.message}\n'; @@ -127,7 +127,7 @@ Future _writeLogToFile(LogRecord record) async { Future cleanLogFile() async { return _protectFileAccess(() async { - final logFile = File('$globalApplicationSupportDirectory/app.log'); + final logFile = File('${AppEnvironment.supportDir}/app.log'); if (!logFile.existsSync()) { return; @@ -162,7 +162,7 @@ Future cleanLogFile() async { Future deleteLogFile() async { return _protectFileAccess(() async { - final logFile = File('$globalApplicationSupportDirectory/app.log'); + final logFile = File('${AppEnvironment.supportDir}/app.log'); if (logFile.existsSync()) { await logFile.delete(); diff --git a/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart b/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart index bc9d0fb7..76d7ef7d 100644 --- a/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart +++ b/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart @@ -592,7 +592,7 @@ class _CameraPreviewViewState extends State { @override Widget build(BuildContext context) { - if (mc.selectedCameraDetails.cameraId >= gCameras.length || + if (mc.selectedCameraDetails.cameraId >= AppEnvironment.cameras.length || mc.cameraController == null) { return Container(); } diff --git a/lib/src/views/camera/camera_preview_components/main_camera_controller.dart b/lib/src/views/camera/camera_preview_components/main_camera_controller.dart index 2cc6357f..b4fc0997 100644 --- a/lib/src/views/camera/camera_preview_components/main_camera_controller.dart +++ b/lib/src/views/camera/camera_preview_components/main_camera_controller.dart @@ -105,16 +105,17 @@ class MainCameraController { initCameraStarted = true; var cameraId = sCameraId; - if (cameraId >= gCameras.length) { + if (cameraId >= AppEnvironment.cameras.length) { Log.warn( - 'Trying to select a non existing camera $cameraId >= ${gCameras.length}', + 'Trying to select a non existing camera $cameraId >= ${AppEnvironment.cameras.length}', ); return; } if (init) { - for (; cameraId < gCameras.length; cameraId++) { - if (gCameras[cameraId].lensDirection == CameraLensDirection.back) { + for (; cameraId < AppEnvironment.cameras.length; cameraId++) { + if (AppEnvironment.cameras[cameraId].lensDirection == + CameraLensDirection.back) { break; } } @@ -124,7 +125,7 @@ class MainCameraController { if (cameraController == null) { cameraController = CameraController( - gCameras[cameraId], + AppEnvironment.cameras[cameraId], ResolutionPreset.high, enableAudio: await Permission.microphone.isGranted, imageFormatGroup: Platform.isAndroid @@ -150,7 +151,7 @@ class MainCameraController { selectedCameraDetails.scaleFactor = 1; await cameraController?.setZoomLevel(1); - await cameraController?.setDescription(gCameras[cameraId]); + await cameraController?.setDescription(AppEnvironment.cameras[cameraId]); try { if (!isVideoRecording) { await cameraController?.startImageStream(_processCameraImage); diff --git a/lib/src/views/camera/camera_preview_components/zoom_selector.dart b/lib/src/views/camera/camera_preview_components/zoom_selector.dart index ab7a5eb1..07450e07 100644 --- a/lib/src/views/camera/camera_preview_components/zoom_selector.dart +++ b/lib/src/views/camera/camera_preview_components/zoom_selector.dart @@ -51,11 +51,11 @@ class _CameraZoomButtonsState extends State { Future initAsync() async { showWideAngleZoom = (await widget.controller.getMinZoomLevel()) < 1; - var index = gCameras.indexWhere( + var index = AppEnvironment.cameras.indexWhere( (t) => t.lensType == CameraLensType.ultraWide, ); if (index == -1) { - index = gCameras.indexWhere( + index = AppEnvironment.cameras.indexWhere( (t) => t.lensType == CameraLensType.wide, ); } diff --git a/lib/src/views/settings/data_and_storage/export_media.view.dart b/lib/src/views/settings/data_and_storage/export_media.view.dart index 9c3426a2..f5e3aeca 100644 --- a/lib/src/views/settings/data_and_storage/export_media.view.dart +++ b/lib/src/views/settings/data_and_storage/export_media.view.dart @@ -48,7 +48,7 @@ class _ExportMediaViewState extends State { Directory _mediaFolder() { final dir = MediaFileService.buildDirectoryPath( 'stored', - globalApplicationSupportDirectory, + AppEnvironment.supportDir, ); if (!dir.existsSync()) dir.createSync(recursive: true); return dir; From bd012a363e12f3aab613560f5657dd8f26040a38 Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 21 Apr 2026 02:18:24 +0200 Subject: [PATCH 23/86] replace global callback with broadcast --- lib/app.dart | 5 ----- lib/globals.dart | 2 -- lib/src/providers/purchases.provider.dart | 4 ++++ lib/src/services/api.service.dart | 5 ++++- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index 0576e6fd..7699fcf2 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -43,10 +43,6 @@ class _AppState extends State with WidgetsBindingObserver { await setUserPlan(); }; - globalCallbackUpdatePlan = (plan) { - context.read().updatePlan(plan); - }; - unawaited(initAsync()); } @@ -86,7 +82,6 @@ class _AppState extends State with WidgetsBindingObserver { void dispose() { WidgetsBinding.instance.removeObserver(this); globalCallbackConnectionState = ({required isConnected}) {}; - globalCallbackUpdatePlan = (planId) {}; super.dispose(); } diff --git a/lib/globals.dart b/lib/globals.dart index 8c066fa9..a44d104d 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -4,7 +4,6 @@ import 'package:path_provider/path_provider.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/model/json/userdata.dart'; import 'package:twonly/src/services/api.service.dart'; -import 'package:twonly/src/services/subscription.service.dart'; class AppEnvironment { static late final String cacheDir; @@ -38,7 +37,6 @@ void Function({required bool isConnected}) globalCallbackConnectionState = }) {}; void Function() globalCallbackAppIsOutdated = () {}; void Function() globalCallbackNewDeviceRegistered = () {}; -void Function(SubscriptionPlan plan) globalCallbackUpdatePlan = (plan) {}; Map globalUserDataChangedCallBack = {}; diff --git a/lib/src/providers/purchases.provider.dart b/lib/src/providers/purchases.provider.dart index 25cf1508..71e8c04b 100644 --- a/lib/src/providers/purchases.provider.dart +++ b/lib/src/providers/purchases.provider.dart @@ -38,6 +38,8 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin { onError: _updateStreamOnError, ); + _planSub = apiService.onPlanUpdated.listen(updatePlan); + loadPurchases(); } @@ -48,6 +50,7 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin { late StreamSubscription> _subscription; final InAppPurchase iapConnection = IAPConnection.instance; + late StreamSubscription _planSub; bool _userTriggeredBuyButton = false; void updatePlan(SubscriptionPlan newPlan) { @@ -225,6 +228,7 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin { @override void dispose() { + _planSub.cancel(); _subscription.cancel(); super.dispose(); } diff --git a/lib/src/services/api.service.dart b/lib/src/services/api.service.dart index 45bedd86..e0c62fd4 100644 --- a/lib/src/services/api.service.dart +++ b/lib/src/services/api.service.dart @@ -58,6 +58,9 @@ class ApiService { // final String apiHost = kReleaseMode ? 'api.twonly.eu' : 'dev.twonly.eu'; final String apiSecure = kReleaseMode ? 's' : ''; + final _planUpdateController = StreamController.broadcast(); + Stream get onPlanUpdated => _planUpdateController.stream; + bool appIsOutdated = false; bool isAuthenticated = false; @@ -333,7 +336,7 @@ class ApiService { user.subscriptionPlan = authenticated.plan; return user; }); - globalCallbackUpdatePlan(planFromString(authenticated.plan)); + _planUpdateController.add(planFromString(authenticated.plan)); // this was triggered by apiService.ipaPurchase, so call the onAuthenticated again if (isAuthenticated) { From 715774bd7fba126ab7bdc540a72aa0c92084b4d2 Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 21 Apr 2026 02:24:47 +0200 Subject: [PATCH 24/86] remove global connection state --- lib/app.dart | 23 ++++------------------ lib/globals.dart | 4 ---- lib/src/providers/connection.provider.dart | 15 ++++++++++++++ lib/src/providers/purchases.provider.dart | 8 ++++++++ lib/src/services/api.service.dart | 9 ++++++--- 5 files changed, 33 insertions(+), 26 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index 7699fcf2..e6091da9 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -4,7 +4,6 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/localization/generated/app_localizations.dart'; -import 'package:twonly/src/providers/connection.provider.dart'; import 'package:twonly/src/providers/purchases.provider.dart'; import 'package:twonly/src/providers/routing.provider.dart'; import 'package:twonly/src/providers/settings.provider.dart'; @@ -36,29 +35,16 @@ class _AppState extends State with WidgetsBindingObserver { globalIsAppInBackground = false; WidgetsBinding.instance.addObserver(this); - globalCallbackConnectionState = ({required isConnected}) async { - await context.read().updateConnectionState( - isConnected, - ); - await setUserPlan(); - }; - unawaited(initAsync()); } - Future setUserPlan() async { + Future initAsync() async { final user = await getUser(); if (user != null && mounted) { - if (mounted) { - context.read().updatePlan( - planFromString(user.subscriptionPlan), - ); - } + context.read().updatePlan( + planFromString(user.subscriptionPlan), + ); } - } - - Future initAsync() async { - await setUserPlan(); await apiService.connect(); await apiService.listenToNetworkChanges(); } @@ -81,7 +67,6 @@ class _AppState extends State with WidgetsBindingObserver { @override void dispose() { WidgetsBinding.instance.removeObserver(this); - globalCallbackConnectionState = ({required isConnected}) {}; super.dispose(); } diff --git a/lib/globals.dart b/lib/globals.dart index a44d104d..68b756a1 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -31,10 +31,6 @@ late UserData gUser; // App widget. // This callback called by the apiProvider -void Function({required bool isConnected}) globalCallbackConnectionState = - ({ - required isConnected, - }) {}; void Function() globalCallbackAppIsOutdated = () {}; void Function() globalCallbackNewDeviceRegistered = () {}; diff --git a/lib/src/providers/connection.provider.dart b/lib/src/providers/connection.provider.dart index 1b004aeb..d81b3d07 100644 --- a/lib/src/providers/connection.provider.dart +++ b/lib/src/providers/connection.provider.dart @@ -1,8 +1,23 @@ +import 'dart:async'; import 'package:flutter/foundation.dart'; +import 'package:twonly/globals.dart'; class CustomChangeProvider with ChangeNotifier, DiagnosticableTreeMixin { + CustomChangeProvider() { + _connSub = apiService.onConnectionStateUpdated.listen( + updateConnectionState, + ); + } bool _isConnected = false; bool get isConnected => _isConnected; + late StreamSubscription _connSub; + + @override + void dispose() { + _connSub.cancel(); + super.dispose(); + } + Future updateConnectionState(bool update) async { _isConnected = update; notifyListeners(); diff --git a/lib/src/providers/purchases.provider.dart b/lib/src/providers/purchases.provider.dart index 71e8c04b..c71685c1 100644 --- a/lib/src/providers/purchases.provider.dart +++ b/lib/src/providers/purchases.provider.dart @@ -39,6 +39,12 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin { ); _planSub = apiService.onPlanUpdated.listen(updatePlan); + _connSub = apiService.onConnectionStateUpdated.listen((_) async { + final user = await getUser(); + if (user != null) { + updatePlan(planFromString(user.subscriptionPlan)); + } + }); loadPurchases(); } @@ -51,6 +57,7 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin { final InAppPurchase iapConnection = IAPConnection.instance; late StreamSubscription _planSub; + late StreamSubscription _connSub; bool _userTriggeredBuyButton = false; void updatePlan(SubscriptionPlan newPlan) { @@ -229,6 +236,7 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin { @override void dispose() { _planSub.cancel(); + _connSub.cancel(); _subscription.cancel(); super.dispose(); } diff --git a/lib/src/services/api.service.dart b/lib/src/services/api.service.dart index e0c62fd4..7e47f6f2 100644 --- a/lib/src/services/api.service.dart +++ b/lib/src/services/api.service.dart @@ -61,6 +61,9 @@ class ApiService { final _planUpdateController = StreamController.broadcast(); Stream get onPlanUpdated => _planUpdateController.stream; + final _connectionStateController = StreamController.broadcast(); + Stream get onConnectionStateUpdated => _connectionStateController.stream; + bool appIsOutdated = false; bool isAuthenticated = false; @@ -92,7 +95,7 @@ class ApiService { // Function is called after the user is authenticated at the server Future onAuthenticated() async { await initFCMAfterAuthenticated(); - globalCallbackConnectionState(isConnected: true); + _connectionStateController.add(true); if (globalIsInBackgroundTask) { await retransmitRawBytes(); @@ -125,13 +128,13 @@ class ApiService { Future onConnected() async { await authenticate(); _reconnectionDelay = 1; - globalCallbackConnectionState(isConnected: true); + _connectionStateController.add(true); } Future onClosed() async { _channel = null; isAuthenticated = false; - globalCallbackConnectionState(isConnected: false); + _connectionStateController.add(false); await twonlyDB.mediaFilesDao.resetPendingDownloadState(); await startReconnectionTimer(); } From e945e30991a4a792aca732626c1cb9e3b7618091 Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 21 Apr 2026 02:40:12 +0200 Subject: [PATCH 25/86] rename global variables into app state --- lib/app.dart | 8 ++-- lib/globals.dart | 32 ++++++++-------- lib/main.dart | 2 +- lib/src/services/api.service.dart | 22 +++++++---- .../api/mediafiles/upload.service.dart | 4 +- lib/src/services/api/server_messages.dart | 2 +- .../callback_dispatcher.background.dart | 6 +-- .../notifications/fcm.notifications.dart | 2 +- lib/src/utils/log.dart | 2 +- lib/src/utils/storage.dart | 9 +---- .../main_camera_controller.dart | 4 +- lib/src/views/components/app_outdated.dart | 37 ++++++++++++------- .../components/avatar_icon.component.dart | 27 +++++++------- 13 files changed, 82 insertions(+), 75 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index e6091da9..eb9a749f 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -32,7 +32,7 @@ class _AppState extends State with WidgetsBindingObserver { @override void initState() { super.initState(); - globalIsAppInBackground = false; + AppState.isAppInBackground = false; WidgetsBinding.instance.addObserver(this); unawaited(initAsync()); @@ -54,13 +54,13 @@ class _AppState extends State with WidgetsBindingObserver { super.didChangeAppLifecycleState(state); if (state == AppLifecycleState.resumed) { if (wasPaused) { - globalIsAppInBackground = false; + AppState.isAppInBackground = false; twonlyDB.markUpdated(); unawaited(apiService.connect()); } } else if (state == AppLifecycleState.paused) { wasPaused = true; - globalIsAppInBackground = true; + AppState.isAppInBackground = true; } } @@ -77,7 +77,7 @@ class _AppState extends State with WidgetsBindingObserver { builder: (context, child) { return MaterialApp.router( routerConfig: routerProvider, - scaffoldMessengerKey: globalRootScaffoldMessengerKey, + scaffoldMessengerKey: AppGlobalKeys.scaffoldMessengerKey, localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, diff --git a/lib/globals.dart b/lib/globals.dart index 68b756a1..fc2035e9 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; @@ -17,6 +19,18 @@ class AppEnvironment { } } +class AppState { + static bool isAppInBackground = true; + static bool isInBackgroundTask = false; + static bool allowErrorTrackingViaSentry = false; + static bool gotMessageFromServer = false; +} + +class AppGlobalKeys { + static final GlobalKey scaffoldMessengerKey = + GlobalKey(); +} + late ApiService apiService; // uses for background notification @@ -26,20 +40,4 @@ late TwonlyDB twonlyDB; // which will update this global variable. The variable is set in the main.dart and after the user has registered in the register.view.dart late UserData gUser; -// The following global function can be called from anywhere to update -// the UI when something changed. The callbacks will be set by -// App widget. - -// This callback called by the apiProvider -void Function() globalCallbackAppIsOutdated = () {}; -void Function() globalCallbackNewDeviceRegistered = () {}; - -Map globalUserDataChangedCallBack = {}; - -bool globalIsAppInBackground = true; -bool globalIsInBackgroundTask = false; -bool globalAllowErrorTrackingViaSentry = false; -bool globalGotMessageFromServer = false; - -final GlobalKey globalRootScaffoldMessengerKey = - GlobalKey(); +final userDataUpdateController = StreamController.broadcast(); diff --git a/lib/main.dart b/lib/main.dart index e09651bf..80e9addd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -63,7 +63,7 @@ void main() async { gUser = user; if (user.allowErrorTrackingViaSentry) { - globalAllowErrorTrackingViaSentry = true; + AppState.allowErrorTrackingViaSentry = true; await SentryFlutter.init( (options) => options ..dsn = diff --git a/lib/src/services/api.service.dart b/lib/src/services/api.service.dart index 7e47f6f2..b217a254 100644 --- a/lib/src/services/api.service.dart +++ b/lib/src/services/api.service.dart @@ -64,6 +64,12 @@ class ApiService { final _connectionStateController = StreamController.broadcast(); Stream get onConnectionStateUpdated => _connectionStateController.stream; + final _appOutdatedController = StreamController.broadcast(); + Stream get onAppOutdated => _appOutdatedController.stream; + + final _newDeviceRegisteredController = StreamController.broadcast(); + Stream get onNewDeviceRegistered => _newDeviceRegisteredController.stream; + bool appIsOutdated = false; bool isAuthenticated = false; @@ -97,12 +103,12 @@ class ApiService { await initFCMAfterAuthenticated(); _connectionStateController.add(true); - if (globalIsInBackgroundTask) { + if (AppState.isInBackgroundTask) { await retransmitRawBytes(); await retransmitAllMessages(); await reuploadMediaFiles(); await tryDownloadAllMediaFiles(); - } else if (!globalIsAppInBackground) { + } else if (!AppState.isAppInBackground) { unawaited(retransmitRawBytes()); unawaited(retransmitAllMessages()); unawaited(tryDownloadAllMediaFiles()); @@ -140,7 +146,7 @@ class ApiService { } Future startReconnectionTimer() async { - if (globalIsInBackgroundTask) return; + if (AppState.isInBackgroundTask) return; if (reconnectionTimer?.isActive ?? false) { return; } @@ -148,7 +154,7 @@ class ApiService { reconnectionTimer = Timer(Duration(seconds: _reconnectionDelay), () async { reconnectionTimer = null; // only try to reconnect in case the app is in the foreground - if (!globalIsAppInBackground) { + if (!AppState.isAppInBackground) { await connect(); } }); @@ -353,14 +359,14 @@ class ApiService { Log.warn('Got error from server: ${res.error}'); } if (res.error == ErrorCode.AppVersionOutdated) { - globalCallbackAppIsOutdated(); + _appOutdatedController.add(null); Log.warn('App Version is OUTDATED.'); appIsOutdated = true; await close(() {}); return Result.error(ErrorCode.InternalError); } if (res.error == ErrorCode.NewDeviceRegistered) { - globalCallbackNewDeviceRegistered(); + _newDeviceRegisteredController.add(null); Log.warn( 'Device is disabled, as a newer device restore twonly Backup.', ); @@ -416,7 +422,7 @@ class ApiService { ..userId = Int64(userId) ..appVersion = (await PackageInfo.fromPlatform()).version ..deviceId = Int64(user.deviceId) - ..inBackground = globalIsInBackgroundTask + ..inBackground = AppState.isInBackgroundTask ..authToken = base64Decode(apiAuthToken); final handshake = Handshake()..authenticate = authenticate; @@ -427,7 +433,7 @@ class ApiService { if (result.isSuccess) { Log.info('websocket is authenticated'); isAuthenticated = true; - if (globalIsInBackgroundTask) { + if (AppState.isInBackgroundTask) { await onAuthenticated(); } else { unawaited(onAuthenticated()); diff --git a/lib/src/services/api/mediafiles/upload.service.dart b/lib/src/services/api/mediafiles/upload.service.dart index db485966..b45eb2a1 100644 --- a/lib/src/services/api/mediafiles/upload.service.dart +++ b/lib/src/services/api/mediafiles/upload.service.dart @@ -593,9 +593,9 @@ Future _uploadUploadRequest(MediaFileService media) async { final connectivityResult = await Connectivity().checkConnectivity(); - if (globalIsInBackgroundTask || + if (AppState.isInBackgroundTask || !connectivityResult.contains(ConnectivityResult.mobile) && - !connectivityResult.contains(ConnectivityResult.wifi)) { + !connectivityResult.contains(ConnectivityResult.wifi)) { // no internet, directly put it into the background... await FileDownloader().enqueue(task); await media.setUploadState(UploadState.backgroundUploadTaskStarted); diff --git a/lib/src/services/api/server_messages.dart b/lib/src/services/api/server_messages.dart index afd6b17b..2a1113c3 100644 --- a/lib/src/services/api/server_messages.dart +++ b/lib/src/services/api/server_messages.dart @@ -66,7 +66,7 @@ Future handleServerMessage(server.ServerToClient msg) async { ..response = response; await apiService.sendResponse(ClientToServer()..v0 = v0); - globalGotMessageFromServer = true; + AppState.gotMessageFromServer = true; }); } diff --git a/lib/src/services/background/callback_dispatcher.background.dart b/lib/src/services/background/callback_dispatcher.background.dart index e3828add..bfa87bce 100644 --- a/lib/src/services/background/callback_dispatcher.background.dart +++ b/lib/src/services/background/callback_dispatcher.background.dart @@ -73,7 +73,7 @@ Future initBackgroundExecution() async { twonlyDB = TwonlyDB(); apiService = ApiService(); - globalIsInBackgroundTask = true; + AppState.isInBackgroundTask = true; _isInitialized = true; return true; @@ -124,7 +124,7 @@ Future handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async { return; } - while (!globalGotMessageFromServer) { + while (!AppState.gotMessageFromServer) { if (stopwatch.elapsed.inSeconds >= 15) { Log.info('No new message from the server after 15 seconds.'); break; @@ -132,7 +132,7 @@ Future handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async { await Future.delayed(const Duration(milliseconds: 500)); } - if (globalGotMessageFromServer) { + if (AppState.gotMessageFromServer) { Log.info('Received a server message from the server.'); } diff --git a/lib/src/services/notifications/fcm.notifications.dart b/lib/src/services/notifications/fcm.notifications.dart index 89b70e4d..2ae14392 100644 --- a/lib/src/services/notifications/fcm.notifications.dart +++ b/lib/src/services/notifications/fcm.notifications.dart @@ -139,7 +139,7 @@ Future handleRemoteMessage(RemoteMessage message) async { if (!Platform.isAndroid) { Log.error('Got message in Dart while on iOS'); } - if (message.notification != null && globalIsAppInBackground) { + if (message.notification != null && AppState.isAppInBackground) { Log.error( 'Got notification but app is in background, so the SDK already have shown the message.', ); diff --git a/lib/src/utils/log.dart b/lib/src/utils/log.dart index a8be4bc3..70c92f98 100644 --- a/lib/src/utils/log.dart +++ b/lib/src/utils/log.dart @@ -41,7 +41,7 @@ class Log { StackTrace? stackTrace, ]) { final message = filterLogMessage('$messageInput'); - if (globalAllowErrorTrackingViaSentry) { + if (AppState.allowErrorTrackingViaSentry) { try { throw Exception(message); } catch (exception, stackTrace) { diff --git a/lib/src/utils/storage.dart b/lib/src/utils/storage.dart index 6d89be2c..60f3c15d 100644 --- a/lib/src/utils/storage.dart +++ b/lib/src/utils/storage.dart @@ -72,13 +72,8 @@ Future updateUserdata( gUser = updated; return updated; }); - try { - for (final callBack in globalUserDataChangedCallBack.values) { - callBack(); - } - } catch (e) { - Log.error(e); - } + userDataUpdateController.add(null); + return userData; } diff --git a/lib/src/views/camera/camera_preview_components/main_camera_controller.dart b/lib/src/views/camera/camera_preview_components/main_camera_controller.dart index b4fc0997..de80dba4 100644 --- a/lib/src/views/camera/camera_preview_components/main_camera_controller.dart +++ b/lib/src/views/camera/camera_preview_components/main_camera_controller.dart @@ -379,10 +379,10 @@ class MainCameraController { } await HapticFeedback.heavyImpact(); if (verificationOk) { - globalRootScaffoldMessengerKey.currentState?.showSnackBar( + AppGlobalKeys.scaffoldMessengerKey.currentState?.showSnackBar( SnackBar( content: Text( - globalRootScaffoldMessengerKey.currentContext?.lang + AppGlobalKeys.scaffoldMessengerKey.currentContext?.lang .verifiedPublicKey( getContactDisplayName(contact), ) ?? diff --git a/lib/src/views/components/app_outdated.dart b/lib/src/views/components/app_outdated.dart index ac50807a..efa2aac5 100644 --- a/lib/src/views/components/app_outdated.dart +++ b/lib/src/views/components/app_outdated.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -16,29 +17,37 @@ class AppOutdated extends StatefulWidget { class _AppOutdatedState extends State { bool appIsOutdated = false; bool newDeviceRegistered = false; + + late StreamSubscription _subOutdated; + late StreamSubscription _subNewDevice; @override void dispose() { - globalCallbackAppIsOutdated = () {}; - globalCallbackNewDeviceRegistered = () {}; + _subOutdated.cancel(); + _subNewDevice.cancel(); super.dispose(); } @override void initState() { - globalCallbackAppIsOutdated = () async { - await context.read().updateConnectionState(false); - setState(() { - appIsOutdated = true; - }); - }; - globalCallbackNewDeviceRegistered = () async { - await context.read().updateConnectionState(false); - setState(() { - newDeviceRegistered = true; - }); - }; super.initState(); + _subOutdated = apiService.onAppOutdated.listen((_) async { + if (mounted) { + await context.read().updateConnectionState(false); + setState(() { + appIsOutdated = true; + }); + } + }); + + _subNewDevice = apiService.onNewDeviceRegistered.listen((_) async { + if (mounted) { + await context.read().updateConnectionState(false); + setState(() { + newDeviceRegistered = true; + }); + } + }); } @override diff --git a/lib/src/views/components/avatar_icon.component.dart b/lib/src/views/components/avatar_icon.component.dart index f16e86cc..3ece858e 100644 --- a/lib/src/views/components/avatar_icon.component.dart +++ b/lib/src/views/components/avatar_icon.component.dart @@ -28,12 +28,12 @@ class AvatarIcon extends StatefulWidget { class _AvatarIconState extends State { List _avatarContacts = []; - String? _globalUserDataCallBackId; String? _avatarSvg; StreamSubscription>? groupStream; StreamSubscription>? contactsStream; StreamSubscription? contactStream; + StreamSubscription? _userDataSub; @override void initState() { @@ -46,9 +46,7 @@ class _AvatarIconState extends State { groupStream?.cancel(); contactStream?.cancel(); contactsStream?.cancel(); - if (_globalUserDataCallBackId != null) { - globalUserDataChangedCallBack.remove(_globalUserDataCallBackId); - } + _userDataSub?.cancel(); super.dispose(); } @@ -95,16 +93,17 @@ class _AvatarIconState extends State { setState(() {}); }); } else if (widget.myAvatar) { - _globalUserDataCallBackId = 'avatar_${getRandomString(10)}'; - globalUserDataChangedCallBack[_globalUserDataCallBackId!] = () { - setState(() { - if (gUser.avatarSvg != null) { - _avatarSvg = gUser.avatarSvg; - } else { - _avatarContacts = []; - } - }); - }; + _userDataSub = userDataUpdateController.stream.listen((_) { + if (mounted) { + setState(() { + if (gUser.avatarSvg != null) { + _avatarSvg = gUser.avatarSvg; + } else { + _avatarContacts = []; + } + }); + } + }); if (gUser.avatarSvg != null) { _avatarSvg = gUser.avatarSvg; } From 3d35615136d82e38e1b320745570a901312f97b5 Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 21 Apr 2026 03:34:52 +0200 Subject: [PATCH 26/86] refactor global user variable --- lib/app.dart | 6 +- lib/globals.dart | 11 +- lib/main.dart | 12 +- lib/src/database/daos/contacts.dao.dart | 2 +- lib/src/database/daos/groups.dao.dart | 4 +- lib/src/providers/purchases.provider.dart | 3 +- lib/src/services/api.service.dart | 14 +- .../api/client2client/groups.c2c.dart | 2 +- .../api/client2client/user_discovery.c2c.dart | 8 +- .../api/mediafiles/download.service.dart | 2 +- .../api/mediafiles/upload.service.dart | 2 +- lib/src/services/api/messages.dart | 16 +- lib/src/services/api/server_messages.dart | 4 +- .../callback_dispatcher.background.dart | 4 +- lib/src/services/backup/common.backup.dart | 48 +-- lib/src/services/backup/create.backup.dart | 37 +-- lib/src/services/backup/restore.backup.dart | 3 +- lib/src/services/flame.service.dart | 5 +- lib/src/services/group.services.dart | 18 +- lib/src/services/intent/links.intent.dart | 4 +- .../mediafiles/mediafile.service.dart | 2 +- .../notifications/fcm.notifications.dart | 11 +- lib/src/services/signal/identity.signal.dart | 21 +- lib/src/services/subscription.service.dart | 6 - lib/src/services/user_discovery.service.dart | 14 +- lib/src/utils/avatars.dart | 6 +- lib/src/utils/qr.dart | 4 +- lib/src/utils/storage.dart | 23 +- .../camera_preview_controller_view.dart | 8 +- .../main_camera_controller.dart | 4 +- .../share_image_contact_selection.view.dart | 2 +- .../views/camera/share_image_editor.view.dart | 3 +- lib/src/views/chats/add_new_user.view.dart | 2 +- lib/src/views/chats/chat_list.view.dart | 20 +- lib/src/views/chats/chat_messages.view.dart | 4 +- .../entries/chat_contacts.entry.dart | 4 +- .../message_input.dart | 2 +- .../reaction_buttons.component.dart | 4 +- .../components/avatar_icon.component.dart | 14 +- lib/src/views/components/flame.dart | 2 +- .../components/max_flame_list_title.dart | 8 +- lib/src/views/contact/contact.view.dart | 8 +- lib/src/views/groups/group.view.dart | 2 +- lib/src/views/home.view.dart | 2 +- .../memories/memories_photo_slider.view.dart | 2 +- lib/src/views/onboarding/register.view.dart | 2 +- lib/src/views/public_profile.view.dart | 6 +- lib/src/views/settings/appearance.view.dart | 97 +++--- .../views/settings/backup/backup.view.dart | 303 +++++++++--------- .../settings/backup/backup_server.view.dart | 10 +- .../settings/chat/chat_reactions.view.dart | 6 +- .../views/settings/data_and_storage.view.dart | 172 +++++----- .../settings/developer/developer.view.dart | 166 +++++----- .../views/settings/help/changelog.view.dart | 68 ++-- lib/src/views/settings/help/help.view.dart | 222 ++++++------- lib/src/views/settings/privacy.view.dart | 12 +- .../settings/privacy/user_discovery.view.dart | 11 +- .../user_discovery_disabled.component.dart | 5 +- .../user_discovery_enabled.component.dart | 11 +- .../user_discovery_settings.view.dart | 21 +- .../settings/profile/modify_avatar.view.dart | 12 +- .../views/settings/profile/profile.view.dart | 206 ++++++------ .../views/settings/settings_main.view.dart | 8 +- .../subscription/subscription.view.dart | 2 +- .../subscription.view.dart | 5 +- .../user_study_data_collection.dart | 12 +- .../user_study_questionnaire.view.dart | 3 +- .../user_study/user_study_welcome.view.dart | 7 +- 68 files changed, 864 insertions(+), 886 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index eb9a749f..4e4bb61b 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -131,9 +131,9 @@ class _AppMainWidgetState extends State { if (_isUserCreated) { if (_isTwonlyLocked) { // do not change in case twonly was already unlocked at some point - _isTwonlyLocked = gUser.screenLockEnabled; + _isTwonlyLocked = AppSession.currentUser.screenLockEnabled; } - if (gUser.appVersion < 62) { + if (AppSession.currentUser.appVersion < 62) { _showDatabaseMigration = true; } } @@ -176,7 +176,7 @@ class _AppMainWidgetState extends State { _isTwonlyLocked = false; }), ); - } else if (gUser.twonlySafeBackup == null && !_skipBackup) { + } else if (AppSession.currentUser.twonlySafeBackup == null && !_skipBackup) { child = SetupBackupView( callBack: () { _skipBackup = true; diff --git a/lib/globals.dart b/lib/globals.dart index fc2035e9..c1a3c02b 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -38,6 +38,13 @@ late TwonlyDB twonlyDB; // Cached UserData in the memory. Every time the user data is changed the `updateUserdata` function is called, // which will update this global variable. The variable is set in the main.dart and after the user has registered in the register.view.dart -late UserData gUser; +class AppSession { + static late UserData currentUser; -final userDataUpdateController = StreamController.broadcast(); + static final _userDataUpdateController = StreamController.broadcast(); + static Stream get onUserUpdated => _userDataUpdateController.stream; + + static void triggerUserUpdate() { + _userDataUpdateController.add(null); + } +} diff --git a/lib/main.dart b/lib/main.dart index 80e9addd..b48acf75 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -60,7 +60,7 @@ void main() async { } if (user != null) { - gUser = user; + AppSession.currentUser = user; if (user.allowErrorTrackingViaSentry) { AppState.allowErrorTrackingViaSentry = true; @@ -91,20 +91,18 @@ void main() async { twonlyDB = TwonlyDB(); if (user != null) { - if (gUser.appVersion < 90) { + if (AppSession.currentUser.appVersion < 90) { // BUG: Requested media files for reupload where not reuploaded because the wrong state... await twonlyDB.mediaFilesDao.updateAllRetransmissionUploadingState(); - await updateUserdata((u) { + await updateUser((u) { u.appVersion = 90; - return u; }); } - if (gUser.appVersion < 91) { + if (AppSession.currentUser.appVersion < 91) { // BUG: Requested media files for reupload where not reuploaded because the wrong state... await makeMigrationToVersion91(); - await updateUserdata((u) { + await updateUser((u) { u.appVersion = 91; - return u; }); } } diff --git a/lib/src/database/daos/contacts.dao.dart b/lib/src/database/daos/contacts.dao.dart index 2a37990e..9b34b3ef 100644 --- a/lib/src/database/daos/contacts.dao.dart +++ b/lib/src/database/daos/contacts.dao.dart @@ -140,7 +140,7 @@ class ContactsDao extends DatabaseAccessor with _$ContactsDaoMixin { t.userDiscoveryVersion.isNotNull() & t.userDiscoveryExcluded.equals(false) & t.mediaSendCounter.isBiggerOrEqualValue( - gUser.minimumRequiredImagesExchanged, + AppSession.currentUser.minimumRequiredImagesExchanged, ), )) .watch(); diff --git a/lib/src/database/daos/groups.dao.dart b/lib/src/database/daos/groups.dao.dart index 7f408d2d..a66ccfcd 100644 --- a/lib/src/database/daos/groups.dao.dart +++ b/lib/src/database/daos/groups.dao.dart @@ -113,7 +113,7 @@ class GroupsDao extends DatabaseAccessor with _$GroupsDaoMixin { int contactId, GroupsCompanion group, ) async { - final groupIdDirectChat = getUUIDforDirectChat(contactId, gUser.userId); + final groupIdDirectChat = getUUIDforDirectChat(contactId, AppSession.currentUser.userId); final insertGroup = group.copyWith( groupId: Value(groupIdDirectChat), isDirectChat: const Value(true), @@ -209,7 +209,7 @@ class GroupsDao extends DatabaseAccessor with _$GroupsDaoMixin { } Stream watchDirectChat(int contactId) { - final groupId = getUUIDforDirectChat(contactId, gUser.userId); + final groupId = getUUIDforDirectChat(contactId, AppSession.currentUser.userId); return (select( groups, )..where((t) => t.groupId.equals(groupId))).watchSingleOrNull(); diff --git a/lib/src/providers/purchases.provider.dart b/lib/src/providers/purchases.provider.dart index c71685c1..fb2f7c86 100644 --- a/lib/src/providers/purchases.provider.dart +++ b/lib/src/providers/purchases.provider.dart @@ -174,9 +174,8 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin { // an ok authenticated which is processed in the apiProvider... if (res.isSuccess) { if (Platform.isAndroid) { - await updateUserdata((u) { + await updateUser((u) { u.subscriptionPlanIdStore = purchaseDetails.productID; - return u; }); } } diff --git a/lib/src/services/api.service.dart b/lib/src/services/api.service.dart index b217a254..d3c245d9 100644 --- a/lib/src/services/api.service.dart +++ b/lib/src/services/api.service.dart @@ -62,13 +62,15 @@ class ApiService { Stream get onPlanUpdated => _planUpdateController.stream; final _connectionStateController = StreamController.broadcast(); - Stream get onConnectionStateUpdated => _connectionStateController.stream; + Stream get onConnectionStateUpdated => + _connectionStateController.stream; final _appOutdatedController = StreamController.broadcast(); Stream get onAppOutdated => _appOutdatedController.stream; final _newDeviceRegisteredController = StreamController.broadcast(); - Stream get onNewDeviceRegistered => _newDeviceRegisteredController.stream; + Stream get onNewDeviceRegistered => + _newDeviceRegisteredController.stream; bool appIsOutdated = false; bool isAuthenticated = false; @@ -124,7 +126,7 @@ class ApiService { unawaited(UserDiscoveryService.checkForNewAnnouncedUsers()); - if (gUser.userStudyParticipantsToken != null) { + if (AppSession.currentUser.userStudyParticipantsToken != null) { // In case the user participates in the user study, call the handler after authenticated, to be sure there is a internet connection unawaited(handleUserStudyUpload()); } @@ -341,9 +343,8 @@ class ApiService { final ok = res.value as server.Response_Ok; if (ok.hasAuthenticated()) { final authenticated = ok.authenticated; - await updateUserdata((user) { + await updateUser((user) { user.subscriptionPlan = authenticated.plan; - return user; }); _planUpdateController.add(planFromString(authenticated.plan)); @@ -782,9 +783,8 @@ class ApiService { Future loadPlanBalance({bool useCache = true}) async { final ballance = await getPlanBallance(); if (ballance != null) { - await updateUserdata((u) { + await updateUser((u) { u.lastPlanBallance = ballance.writeToJson(); - return u; }); return ballance; } diff --git a/lib/src/services/api/client2client/groups.c2c.dart b/lib/src/services/api/client2client/groups.c2c.dart index 8c88bac6..1193b4cf 100644 --- a/lib/src/services/api/client2client/groups.c2c.dart +++ b/lib/src/services/api/client2client/groups.c2c.dart @@ -161,7 +161,7 @@ Future handleGroupUpdate( case GroupActionType.demoteToMember: int? affectedContactId = update.affectedContactId.toInt(); - if (affectedContactId == gUser.userId) { + if (affectedContactId == AppSession.currentUser.userId) { affectedContactId = null; if (actionType == GroupActionType.removedMember) { // Oh no, I just got removed from the group... diff --git a/lib/src/services/api/client2client/user_discovery.c2c.dart b/lib/src/services/api/client2client/user_discovery.c2c.dart index e61fd465..d265b825 100644 --- a/lib/src/services/api/client2client/user_discovery.c2c.dart +++ b/lib/src/services/api/client2client/user_discovery.c2c.dart @@ -34,17 +34,17 @@ Future handleUserDiscoveryRequest( ) async { Log.info('Got a user discovery request'); - if (!gUser.isUserDiscoveryEnabled) { + if (!AppSession.currentUser.isUserDiscoveryEnabled) { Log.warn('Got a user discovery request while it is disabled'); return; } final contact = await twonlyDB.contactsDao.getContactById(fromUserId); if (contact == null) return; - if (contact.mediaSendCounter < gUser.minimumRequiredImagesExchanged || + if (contact.mediaSendCounter < AppSession.currentUser.minimumRequiredImagesExchanged || contact.userDiscoveryExcluded) { Log.warn( - 'Got a request to update user discovery, but mediaSendCounter (${contact.mediaSendCounter}) < ${gUser.minimumRequiredImagesExchanged} or user is excluded ${contact.userDiscoveryExcluded}', + 'Got a request to update user discovery, but mediaSendCounter (${contact.mediaSendCounter}) < ${AppSession.currentUser.minimumRequiredImagesExchanged} or user is excluded ${contact.userDiscoveryExcluded}', ); return; } @@ -72,7 +72,7 @@ Future handleUserDiscoveryUpdate( int fromUserId, EncryptedContent_UserDiscoveryUpdate update, ) async { - if (!gUser.isUserDiscoveryEnabled) { + if (!AppSession.currentUser.isUserDiscoveryEnabled) { Log.warn('Got a user discovery update while it is disabled'); return; } diff --git a/lib/src/services/api/mediafiles/download.service.dart b/lib/src/services/api/mediafiles/download.service.dart index 28a2a670..31e57eeb 100644 --- a/lib/src/services/api/mediafiles/download.service.dart +++ b/lib/src/services/api/mediafiles/download.service.dart @@ -96,7 +96,7 @@ Future isAllowedToDownload(MediaType type) async { } final connectivityResult = await Connectivity().checkConnectivity(); - final options = gUser.autoDownloadOptions ?? defaultAutoDownloadOptions; + final options = AppSession.currentUser.autoDownloadOptions ?? defaultAutoDownloadOptions; if (connectivityResult.contains(ConnectivityResult.mobile)) { if (type == MediaType.video) { diff --git a/lib/src/services/api/mediafiles/upload.service.dart b/lib/src/services/api/mediafiles/upload.service.dart index b45eb2a1..4629d26a 100644 --- a/lib/src/services/api/mediafiles/upload.service.dart +++ b/lib/src/services/api/mediafiles/upload.service.dart @@ -357,7 +357,7 @@ Future startBackgroundMediaUpload(MediaFileService mediaService) async { // if the user has enabled auto storing and the file // was send with unlimited counter not in twonly-Mode then store the file - if (gUser.autoStoreAllSendUnlimitedMediaFiles && + if (AppSession.currentUser.autoStoreAllSendUnlimitedMediaFiles && !mediaService.mediaFile.requiresAuthentication && !mediaService.storedPath.existsSync() && mediaService.mediaFile.displayLimitInMilliseconds == null) { diff --git a/lib/src/services/api/messages.dart b/lib/src/services/api/messages.dart index 52129f42..cad90fc5 100644 --- a/lib/src/services/api/messages.dart +++ b/lib/src/services/api/messages.dart @@ -345,12 +345,12 @@ Future<(Uint8List, Uint8List?)?> sendCipherText( return null; } } - encryptedContent.senderProfileCounter = Int64(gUser.avatarCounter); + encryptedContent.senderProfileCounter = Int64(AppSession.currentUser.avatarCounter); - if (gUser.isUserDiscoveryEnabled && messageId != null) { + if (AppSession.currentUser.isUserDiscoveryEnabled && messageId != null) { final contact = await twonlyDB.contactsDao.getContactById(contactId); if (contact != null && - contact.mediaSendCounter >= gUser.minimumRequiredImagesExchanged && + contact.mediaSendCounter >= AppSession.currentUser.minimumRequiredImagesExchanged && !contact.userDiscoveryExcluded) { final version = await UserDiscoveryService.getCurrentVersion(); if (version != null) { @@ -406,7 +406,7 @@ Future<(Uint8List, Uint8List?)?> sendCipherText( } Future sendTypingIndication(String groupId, bool isTyping) async { - if (!gUser.typingIndicators) return; + if (!AppSession.currentUser.typingIndicators) return; await sendCipherTextToGroup( groupId, pb.EncryptedContent( @@ -462,15 +462,15 @@ Future notifyContactAboutOpeningMessage( Future sendContactMyProfileData(int contactId) async { List? avatarSvgCompressed; - if (gUser.avatarSvg != null) { - avatarSvgCompressed = gzip.encode(utf8.encode(gUser.avatarSvg!)); + if (AppSession.currentUser.avatarSvg != null) { + avatarSvgCompressed = gzip.encode(utf8.encode(AppSession.currentUser.avatarSvg!)); } final encryptedContent = pb.EncryptedContent( contactUpdate: pb.EncryptedContent_ContactUpdate( type: pb.EncryptedContent_ContactUpdate_Type.UPDATE, avatarSvgCompressed: avatarSvgCompressed, - displayName: gUser.displayName, - username: gUser.username, + displayName: AppSession.currentUser.displayName, + username: AppSession.currentUser.username, ), ); await sendCipherText(contactId, encryptedContent); diff --git a/lib/src/services/api/server_messages.dart b/lib/src/services/api/server_messages.dart index 2a1113c3..4b176870 100644 --- a/lib/src/services/api/server_messages.dart +++ b/lib/src/services/api/server_messages.dart @@ -263,7 +263,7 @@ Future<(EncryptedContent?, PlaintextContent?)> handleEncryptedMessage( await twonlyDB.receiptsDao.markMessagesForRetry(fromUserId); final senderProfileCounter = await checkForProfileUpdate(fromUserId, content); - if (gUser.isUserDiscoveryEnabled && content.hasSenderUserDiscoveryVersion()) { + if (AppSession.currentUser.isUserDiscoveryEnabled && content.hasSenderUserDiscoveryVersion()) { await checkForUserDiscoveryChanges( fromUserId, content.senderUserDiscoveryVersion, @@ -351,7 +351,7 @@ Future<(EncryptedContent?, PlaintextContent?)> handleEncryptedMessage( /// Verify that the user is (still) in that group... if (!await twonlyDB.groupsDao.isContactInGroup(fromUserId, content.groupId)) { - if (getUUIDforDirectChat(gUser.userId, fromUserId) == content.groupId) { + if (getUUIDforDirectChat(AppSession.currentUser.userId, fromUserId) == content.groupId) { final contact = await twonlyDB.contactsDao .getContactByUserId(fromUserId) .getSingleOrNull(); diff --git a/lib/src/services/background/callback_dispatcher.background.dart b/lib/src/services/background/callback_dispatcher.background.dart index bfa87bce..b271cbde 100644 --- a/lib/src/services/background/callback_dispatcher.background.dart +++ b/lib/src/services/background/callback_dispatcher.background.dart @@ -57,7 +57,7 @@ Future initBackgroundExecution() async { // stay alive for multiple hours between task executions final user = await getUser(); if (user == null) return false; - gUser = user; + AppSession.currentUser = user; return true; } @@ -69,7 +69,7 @@ Future initBackgroundExecution() async { final user = await getUser(); if (user == null) return false; - gUser = user; + AppSession.currentUser = user; twonlyDB = TwonlyDB(); apiService = ApiService(); diff --git a/lib/src/services/backup/common.backup.dart b/lib/src/services/backup/common.backup.dart index 9617954b..4fc9080b 100644 --- a/lib/src/services/backup/common.backup.dart +++ b/lib/src/services/backup/common.backup.dart @@ -13,34 +13,35 @@ import 'package:twonly/src/utils/storage.dart'; Future enableTwonlySafe(String password) async { final (backupId, encryptionKey) = await getMasterKey( password, - gUser.username, + AppSession.currentUser.username, ); - await updateUserdata((user) { + await updateUser((user) { user.twonlySafeBackup = TwonlySafeBackup( encryptionKey: encryptionKey, backupId: backupId, ); - return user; }); unawaited(performTwonlySafeBackup(force: true)); } Future removeTwonlySafeFromServer() async { - final serverUrl = await getTwonlySafeBackupUrl(); - if (serverUrl != null) { - try { - final response = await http.delete( - Uri.parse(serverUrl), - headers: { - 'Content-Type': 'application/json', // Set the content type if needed - // Add any other headers if required - }, - ); - Log.info('Download deleted with: ${response.statusCode}'); - } catch (e) { - Log.error('Could not connect upload the backup.'); - } + final serverUrl = getTwonlySafeBackupUrl(); + if (serverUrl == null) { + Log.error('Could not remove twonly safe as serverUrl is null'); + return; + } + try { + final response = await http.delete( + Uri.parse(serverUrl), + headers: { + 'Content-Type': 'application/json', // Set the content type if needed + // Add any other headers if required + }, + ); + Log.info('Download deleted with: ${response.statusCode}'); + } catch (e) { + Log.error('Could not connect upload the backup.'); } } @@ -63,19 +64,18 @@ Future<(Uint8List, Uint8List)> getMasterKey( return (key.sublist(0, 32), key.sublist(32, 64)); } -Future getTwonlySafeBackupUrl() async { - final user = await getUser(); - if (user == null || user.twonlySafeBackup == null) return null; +String? getTwonlySafeBackupUrl() { + if (AppSession.currentUser.twonlySafeBackup == null) return null; return getTwonlySafeBackupUrlFromServer( - user.twonlySafeBackup!.backupId, - user.backupServer, + AppSession.currentUser.twonlySafeBackup!.backupId, + AppSession.currentUser.backupServer, ); } -Future getTwonlySafeBackupUrlFromServer( +String? getTwonlySafeBackupUrlFromServer( List backupId, BackupServer? backupServer, -) async { +) { var backupServerUrl = 'https://safe.twonly.eu/'; if (backupServer != null) { diff --git a/lib/src/services/backup/create.backup.dart b/lib/src/services/backup/create.backup.dart index a03c7e6f..6a5e6421 100644 --- a/lib/src/services/backup/create.backup.dart +++ b/lib/src/services/backup/create.backup.dart @@ -19,20 +19,20 @@ import 'package:twonly/src/services/backup/common.backup.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/storage.dart'; -import 'package:twonly/src/views/settings/backup/backup.view.dart'; Future performTwonlySafeBackup({bool force = false}) async { - if (gUser.twonlySafeBackup == null) { + if (AppSession.currentUser.twonlySafeBackup == null) { return; } - if (gUser.twonlySafeBackup!.backupUploadState == + if (AppSession.currentUser.twonlySafeBackup!.backupUploadState == LastBackupUploadState.pending) { Log.warn('Backup upload is already pending.'); return; } - final lastUpdateTime = gUser.twonlySafeBackup!.lastBackupDone; + final lastUpdateTime = + AppSession.currentUser.twonlySafeBackup!.lastBackupDone; if (!force && lastUpdateTime != null) { if (lastUpdateTime.isAfter(clock.now().subtract(const Duration(days: 1)))) { return; @@ -120,8 +120,8 @@ Future performTwonlySafeBackup({bool force = false}) async { final backupHash = uint8ListToHex((await Sha256().hash(backupBytes)).bytes); - if (gUser.twonlySafeBackup!.lastBackupDone == null || - gUser.twonlySafeBackup!.lastBackupDone!.isAfter( + if (AppSession.currentUser.twonlySafeBackup!.lastBackupDone == null || + AppSession.currentUser.twonlySafeBackup!.lastBackupDone!.isAfter( clock.now().subtract(const Duration(days: 90)), )) { force = true; @@ -149,7 +149,9 @@ Future performTwonlySafeBackup({bool force = false}) async { final secretBox = await chacha20.encrypt( backupBytes, - secretKey: SecretKey(gUser.twonlySafeBackup!.encryptionKey), + secretKey: SecretKey( + AppSession.currentUser.twonlySafeBackup!.encryptionKey, + ), nonce: nonce, ); @@ -171,12 +173,12 @@ Future performTwonlySafeBackup({bool force = false}) async { 'Create twonly Backup with a size of ${encryptedBackupBytes.length} bytes.', ); - if (gUser.backupServer != null) { - if (encryptedBackupBytes.length > gUser.backupServer!.maxBackupBytes) { + if (AppSession.currentUser.backupServer != null) { + if (encryptedBackupBytes.length > + AppSession.currentUser.backupServer!.maxBackupBytes) { Log.error('Backup is to big for the alternative backup server.'); - await updateUserdata((user) { + await updateUser((user) { user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.failed; - return user; }); return; } @@ -186,7 +188,7 @@ Future performTwonlySafeBackup({bool force = false}) async { taskId: 'backup', file: encryptedBackupBytesFile, httpRequestMethod: 'PUT', - url: (await getTwonlySafeBackupUrl())!, + url: getTwonlySafeBackupUrl()!, post: 'binary', retries: 2, headers: { @@ -195,13 +197,11 @@ Future performTwonlySafeBackup({bool force = false}) async { ); if (await FileDownloader().enqueue(task)) { Log.info('Starting upload from twonly Backup.'); - await updateUserdata((user) { + await updateUser((user) { user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.pending; user.twonlySafeBackup!.lastBackupDone = clock.now(); user.twonlySafeBackup!.lastBackupSize = encryptedBackupBytes.length; - return user; }); - gUpdateBackupView(); } else { Log.error('Error starting UploadTask for twonly Backup.'); } @@ -210,26 +210,23 @@ Future performTwonlySafeBackup({bool force = false}) async { Future handleBackupStatusUpdate(TaskStatusUpdate update) async { if (update.status == TaskStatus.failed || update.status == TaskStatus.canceled) { - await updateUserdata((user) { + await updateUser((user) { if (user.twonlySafeBackup != null) { user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.failed; } - return user; }); } else if (update.status == TaskStatus.complete) { Log.info( 'twonly Backup uploaded with status code ${update.responseStatusCode}', ); - await updateUserdata((user) { + await updateUser((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/backup/restore.backup.dart b/lib/src/services/backup/restore.backup.dart index 099bb000..2ec13760 100644 --- a/lib/src/services/backup/restore.backup.dart +++ b/lib/src/services/backup/restore.backup.dart @@ -110,8 +110,7 @@ Future handleBackupData( key: SecureStorageKeys.userData, value: secureStorage[SecureStorageKeys.userData] as String, ); - await updateUserdata((u) { + await updateUser((u) { u.deviceId += 1; - return u; }); } diff --git a/lib/src/services/flame.service.dart b/lib/src/services/flame.service.dart index a7172ce1..dcba381b 100644 --- a/lib/src/services/flame.service.dart +++ b/lib/src/services/flame.service.dart @@ -17,10 +17,9 @@ Future syncFlameCounters({String? forceForGroup}) async { (x) => x.totalMediaCounter == maxMessageCounter, ); - if (gUser.myBestFriendGroupId != bestFriend.groupId) { - await updateUserdata((user) { + if (AppSession.currentUser.myBestFriendGroupId != bestFriend.groupId) { + await updateUser((user) { user.myBestFriendGroupId = bestFriend.groupId; - return user; }); } diff --git a/lib/src/services/group.services.dart b/lib/src/services/group.services.dart index 7a64777a..4ed4d399 100644 --- a/lib/src/services/group.services.dart +++ b/lib/src/services/group.services.dart @@ -42,8 +42,8 @@ Future createNewGroup(String groupName, List members) async { final memberIds = members.map((x) => Int64(x.userId)).toList(); final groupState = EncryptedGroupState( - memberIds: [Int64(gUser.userId)] + memberIds, - adminIds: [Int64(gUser.userId)], + memberIds: [Int64(AppSession.currentUser.userId)] + memberIds, + adminIds: [Int64(AppSession.currentUser.userId)], groupName: groupName, deleteMessagesAfterMilliseconds: Int64( defaultDeleteMessagesAfterMilliseconds, @@ -283,9 +283,9 @@ Future<(int, EncryptedGroupState)?> fetchGroupState(Group group) async { final myPubKey = keyPair.getPublicKey().serialize().toList(); if (listEquals(appendedPubKey, myPubKey)) { - adminIds.remove(Int64(gUser.userId)); + adminIds.remove(Int64(AppSession.currentUser.userId)); memberIds.remove( - Int64(gUser.userId), + Int64(AppSession.currentUser.userId), ); // -> Will remove the user later... } else { Log.info('A non admin left the group!!!'); @@ -303,7 +303,7 @@ Future<(int, EncryptedGroupState)?> fetchGroupState(Group group) async { } } - if (!memberIds.contains(Int64(gUser.userId))) { + if (!memberIds.contains(Int64(AppSession.currentUser.userId))) { // OH no, I am no longer a member of this group... // Return from the group... await twonlyDB.groupsDao.updateGroup( @@ -316,7 +316,7 @@ Future<(int, EncryptedGroupState)?> fetchGroupState(Group group) async { } final isGroupAdmin = - adminIds.firstWhereOrNull((t) => t.toInt() == gUser.userId) != null; + adminIds.firstWhereOrNull((t) => t.toInt() == AppSession.currentUser.userId) != null; if (!listEquals(memberIds, encryptedGroupState.memberIds)) { if (isGroupAdmin) { @@ -368,7 +368,7 @@ Future<(int, EncryptedGroupState)?> fetchGroupState(Group group) async { // First find and insert NEW members for (final memberId in memberIds) { - if (memberId == Int64(gUser.userId)) { + if (memberId == Int64(AppSession.currentUser.userId)) { continue; } if (currentGroupMembers.any((t) => t.contactId == memberId.toInt())) { @@ -838,7 +838,7 @@ Future removeMemberFromGroup( groupId: Value(group.groupId), type: const Value(GroupActionType.removedMember), affectedContactId: Value( - removeContactId == gUser.userId ? null : removeContactId, + removeContactId == AppSession.currentUser.userId ? null : removeContactId, ), ), ); @@ -945,7 +945,7 @@ Future leaveAsNonAdminFromGroup(Group group) async { EncryptedContent( groupUpdate: EncryptedContent_GroupUpdate( groupActionType: groupActionType.name, - affectedContactId: Int64(gUser.userId), + affectedContactId: Int64(AppSession.currentUser.userId), ), ), ); diff --git a/lib/src/services/intent/links.intent.dart b/lib/src/services/intent/links.intent.dart index 03d70db1..a71504eb 100644 --- a/lib/src/services/intent/links.intent.dart +++ b/lib/src/services/intent/links.intent.dart @@ -32,7 +32,7 @@ Future handleIntentUrl(BuildContext context, Uri uri) async { if (!context.mounted) return false; - if (username == gUser.username) { + if (username == AppSession.currentUser.username) { await context.push(Routes.settingsPublicProfile); return true; } @@ -115,7 +115,7 @@ Future handleIntentMediaFile( final newMediaService = await initializeMediaUpload( type, - gUser.defaultShowTime, + AppSession.currentUser.defaultShowTime, ); if (newMediaService == null) { Log.error('Could not create new media file for intent shared file'); diff --git a/lib/src/services/mediafiles/mediafile.service.dart b/lib/src/services/mediafiles/mediafile.service.dart index 1e5424ca..92d1b1f9 100644 --- a/lib/src/services/mediafiles/mediafile.service.dart +++ b/lib/src/services/mediafiles/mediafile.service.dart @@ -237,7 +237,7 @@ class MediaFileService { } if (tempPath.existsSync()) { await tempPath.copy(storedPath.path); - if (gUser.storeMediaFilesInGallery) { + if (AppSession.currentUser.storeMediaFilesInGallery) { if (mediaFile.type == MediaType.video) { await saveVideoToGallery(storedPath.path); } else { diff --git a/lib/src/services/notifications/fcm.notifications.dart b/lib/src/services/notifications/fcm.notifications.dart index 2ae14392..0d5d9098 100644 --- a/lib/src/services/notifications/fcm.notifications.dart +++ b/lib/src/services/notifications/fcm.notifications.dart @@ -48,9 +48,8 @@ Future checkForTokenUpdates() async { if (storedToken == null || fcmToken != storedToken) { Log.info('Got new FCM TOKEN.'); await storage.write(key: SecureStorageKeys.googleFcm, value: fcmToken); - await updateUserdata((u) { + await updateUser((u) { u.updateFCMToken = true; - return u; }); } @@ -61,9 +60,8 @@ Future checkForTokenUpdates() async { key: SecureStorageKeys.googleFcm, value: fcmToken, ); - await updateUserdata((u) { + await updateUser((u) { u.updateFCMToken = true; - return u; }); }) .onError((err) { @@ -75,16 +73,15 @@ Future checkForTokenUpdates() async { } Future initFCMAfterAuthenticated({bool force = false}) async { - if (gUser.updateFCMToken || force) { + if (AppSession.currentUser.updateFCMToken || force) { const storage = FlutterSecureStorage(); final storedToken = await storage.read(key: SecureStorageKeys.googleFcm); if (storedToken != null) { final res = await apiService.updateFCMToken(storedToken); if (res.isSuccess) { Log.info('Uploaded new FCM token!'); - await updateUserdata((u) { + await updateUser((u) { u.updateFCMToken = false; - return u; }); } else { Log.error('Could not update FCM token!'); diff --git a/lib/src/services/signal/identity.signal.dart b/lib/src/services/signal/identity.signal.dart index a9692dac..3c41e054 100644 --- a/lib/src/services/signal/identity.signal.dart +++ b/lib/src/services/signal/identity.signal.dart @@ -20,11 +20,12 @@ Future getSignalIdentityKeyPair() async { // This function runs after the clients authenticated with the server. // It then checks if it should update a new session key Future signalHandleNewServerConnection() async { - if (gUser.signalLastSignedPreKeyUpdated != null) { + if (AppSession.currentUser.signalLastSignedPreKeyUpdated != null) { final fortyEightHoursAgo = clock.now().subtract(const Duration(hours: 48)); - final isYoungerThan48Hours = (gUser.signalLastSignedPreKeyUpdated!).isAfter( - fortyEightHoursAgo, - ); + final isYoungerThan48Hours = + (AppSession.currentUser.signalLastSignedPreKeyUpdated!).isAfter( + fortyEightHoursAgo, + ); if (isYoungerThan48Hours) { // The key does live for 48 hours then it expires and a new key is generated. return; @@ -35,9 +36,8 @@ Future signalHandleNewServerConnection() async { Log.error('could not generate a new signed pre key!'); return; } - await updateUserdata((user) { + await updateUser((user) { user.signalLastSignedPreKeyUpdated = clock.now(); - return user; }); final res = await apiService.updateSignedPreKey( signedPreKey.id, @@ -46,9 +46,8 @@ Future signalHandleNewServerConnection() async { ); if (res.isError) { Log.error('could not update the signed pre key: ${res.error}'); - await updateUserdata((user) { + await updateUser((user) { user.signalLastSignedPreKeyUpdated = null; - return user; }); } else { Log.info('updated signed pre key'); @@ -60,10 +59,9 @@ Future> signalGetPreKeys() async { if (user == null) return []; final start = user.currentPreKeyIndexStart; - await updateUserdata((user) { + await updateUser((user) { user.currentPreKeyIndexStart = (user.currentPreKeyIndexStart + 200) % maxValue; - return user; }); final preKeys = generatePreKeys(start, 200); final signalStore = await getSignalStore(); @@ -138,9 +136,8 @@ Future _getNewSignalSignedPreKey() async { } final signedPreKeyId = user.currentSignedPreKeyIndexStart; - await updateUserdata((user) { + await updateUser((user) { user.currentSignedPreKeyIndexStart += 1; - return user; }); final signedPreKey = generateSignedPreKey( diff --git a/lib/src/services/subscription.service.dart b/lib/src/services/subscription.service.dart index 27b50cc3..cd115e43 100644 --- a/lib/src/services/subscription.service.dart +++ b/lib/src/services/subscription.service.dart @@ -1,7 +1,5 @@ // ignore_for_file: constant_identifier_names -import 'package:twonly/globals.dart'; - enum SubscriptionPlan { Free, Tester, @@ -41,7 +39,3 @@ SubscriptionPlan planFromString(String value) { } return SubscriptionPlan.Free; } - -SubscriptionPlan getCurrentPlan() { - return planFromString(gUser.subscriptionPlan); -} diff --git a/lib/src/services/user_discovery.service.dart b/lib/src/services/user_discovery.service.dart index a944db0d..e69a405c 100644 --- a/lib/src/services/user_discovery.service.dart +++ b/lib/src/services/user_discovery.service.dart @@ -53,15 +53,14 @@ class UserDiscoveryService { try { await FlutterUserDiscovery.initializeOrUpdate( threshold: threshold, - userId: gUser.userId, + userId: AppSession.currentUser.userId, publicKey: await getUserPublicKey(), ); - await updateUserdata((u) { - u + await updateUser( + (u) => u ..isUserDiscoveryEnabled = true - ..minimumRequiredImagesExchanged = minimumRequiredImagesExchanged; - return u; - }); + ..minimumRequiredImagesExchanged = minimumRequiredImagesExchanged, + ); } catch (e) { Log.error(e); } @@ -142,9 +141,8 @@ class UserDiscoveryService { } static Future disable() async { - await updateUserdata((u) { + await updateUser((u) { u.isUserDiscoveryEnabled = false; - return u; }); } } diff --git a/lib/src/utils/avatars.dart b/lib/src/utils/avatars.dart index a2648694..f31b611c 100644 --- a/lib/src/utils/avatars.dart +++ b/lib/src/utils/avatars.dart @@ -47,13 +47,13 @@ File avatarPNGFile(int contactId) { } Future getUserAvatar() async { - if (gUser.avatarSvg == null) { + if (AppSession.currentUser.avatarSvg == null) { final data = await rootBundle.load('assets/images/default_avatar.png'); return data.buffer.asUint8List(); } final pictureInfo = await vg.loadPicture( - SvgStringLoader(gUser.avatarSvg!), + SvgStringLoader(AppSession.currentUser.avatarSvg!), null, ); @@ -62,7 +62,7 @@ Future getUserAvatar() async { final byteData = await image.toByteData(format: ui.ImageByteFormat.png); final pngBytes = byteData!.buffer.asUint8List(); - final file = avatarPNGFile(gUser.userId)..writeAsBytesSync(pngBytes); + final file = avatarPNGFile(AppSession.currentUser.userId)..writeAsBytesSync(pngBytes); pictureInfo.picture.dispose(); return file.readAsBytesSync(); diff --git a/lib/src/utils/qr.dart b/lib/src/utils/qr.dart index ceb6c401..ad315b73 100644 --- a/lib/src/utils/qr.dart +++ b/lib/src/utils/qr.dart @@ -17,8 +17,8 @@ Future getProfileQrCodeData() async { final signedPreKey = (await signalStore.loadSignedPreKeys())[0]; final publicProfile = PublicProfile( - userId: Int64(gUser.userId), - username: gUser.username, + userId: Int64(AppSession.currentUser.userId), + username: AppSession.currentUser.username, publicIdentityKey: (await signalStore.getIdentityKeyPair()) .getPublicKey() .serialize(), diff --git a/lib/src/utils/storage.dart b/lib/src/utils/storage.dart index 60f3c15d..f7e35e75 100644 --- a/lib/src/utils/storage.dart +++ b/lib/src/utils/storage.dart @@ -16,7 +16,7 @@ Future isUserCreated() async { if (user == null) { return false; } - gUser = user; + AppSession.currentUser = user; return true; } @@ -43,9 +43,8 @@ Future updateUsersPlan( ) async { context.read().plan = plan; - await updateUserdata((user) { + await updateUser((user) { user.subscriptionPlan = plan.name; - return user; }); if (!context.mounted) return; @@ -54,27 +53,25 @@ Future updateUsersPlan( Mutex updateProtection = Mutex(); -Future updateUserdata( - UserData Function(UserData userData) updateUser, +Future updateUser( + void Function(UserData userData) updateUser, ) async { - final userData = await updateProtection.protect(() async { + await updateProtection.protect(() async { final user = await getUser(); - if (user == null) return null; + if (user == null) return; if (user.defaultShowTime == 999999) { // This was the old version for infinity -> change it to null user.defaultShowTime = null; } - final updated = updateUser(user); + updateUser(user); await const FlutterSecureStorage().write( key: SecureStorageKeys.userData, - value: jsonEncode(updated), + value: jsonEncode(user), ); - gUser = updated; - return updated; + AppSession.currentUser = user; }); - userDataUpdateController.add(null); - return userData; + AppSession.triggerUserUpdate(); } Future deleteLocalUserData() async { diff --git a/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart b/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart index 76d7ef7d..94708969 100644 --- a/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart +++ b/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart @@ -208,10 +208,10 @@ class _CameraPreviewViewState extends State { Future initAsync() async { _hasAudioPermission = await Permission.microphone.isGranted; - if (!_hasAudioPermission && !gUser.requestedAudioPermission) { - await updateUserdata((u) { + if (!_hasAudioPermission && + !AppSession.currentUser.requestedAudioPermission) { + await updateUser((u) { u.requestedAudioPermission = true; - return u; }); await requestMicrophonePermission(); } @@ -321,7 +321,7 @@ class _CameraPreviewViewState extends State { ((videoFilePath != null) ? MediaType.video : MediaType.image); final mediaFileService = await initializeMediaUpload( type, - gUser.defaultShowTime, + AppSession.currentUser.defaultShowTime, isDraftMedia: true, ); if (!mounted) return true; diff --git a/lib/src/views/camera/camera_preview_components/main_camera_controller.dart b/lib/src/views/camera/camera_preview_components/main_camera_controller.dart index de80dba4..df4cf309 100644 --- a/lib/src/views/camera/camera_preview_components/main_camera_controller.dart +++ b/lib/src/views/camera/camera_preview_components/main_camera_controller.dart @@ -135,7 +135,7 @@ class MainCameraController { await cameraController?.initialize(); await cameraController?.startImageStream(_processCameraImage); await cameraController?.setZoomLevel(selectedCameraDetails.scaleFactor); - if (gUser.videoStabilizationEnabled && !kDebugMode) { + if (AppSession.currentUser.videoStabilizationEnabled && !kDebugMode) { await cameraController?.setVideoStabilizationMode( VideoStabilizationMode.level1, ); @@ -395,7 +395,7 @@ class MainCameraController { } } } else { - if (profile.username != gUser.username) { + if (profile.username != AppSession.currentUser.username) { if (scannedNewProfiles[profile.userId.toInt()] == null) { await HapticFeedback.heavyImpact(); scannedNewProfiles[profile.userId.toInt()] = ScannedNewProfile( diff --git a/lib/src/views/camera/share_image_contact_selection.view.dart b/lib/src/views/camera/share_image_contact_selection.view.dart index b4505f09..78e2ca73 100644 --- a/lib/src/views/camera/share_image_contact_selection.view.dart +++ b/lib/src/views/camera/share_image_contact_selection.view.dart @@ -254,7 +254,7 @@ class _ShareImageView extends State { children: [ if (widget.mediaFileService.mediaFile.type == MediaType.image && _screenshotImage?.image != null && - gUser.showShowImagePreviewWhenSending) + AppSession.currentUser.showShowImagePreviewWhenSending) SizedBox( height: 100, width: 100 * 9 / 16, diff --git a/lib/src/views/camera/share_image_editor.view.dart b/lib/src/views/camera/share_image_editor.view.dart index 6f9e96ec..f7ce1c9a 100644 --- a/lib/src/views/camera/share_image_editor.view.dart +++ b/lib/src/views/camera/share_image_editor.view.dart @@ -158,9 +158,8 @@ class _ShareImageEditorView extends State { if (!mounted) return; setState(() {}); if (storeAsDefault) { - await updateUserdata((user) { + await updateUser((user) { user.defaultShowTime = maxShowTime; - return user; }); } } diff --git a/lib/src/views/chats/add_new_user.view.dart b/lib/src/views/chats/add_new_user.view.dart index 4ce086f8..50a378bf 100644 --- a/lib/src/views/chats/add_new_user.view.dart +++ b/lib/src/views/chats/add_new_user.view.dart @@ -92,7 +92,7 @@ class _SearchUsernameView extends State { } Future _requestNewUserByUsername(String username) async { - if (gUser.username == username) return; + if (AppSession.currentUser.username == username) return; setState(() { _isLoading = true; diff --git a/lib/src/views/chats/chat_list.view.dart b/lib/src/views/chats/chat_list.view.dart index dda5cf72..e6b248a2 100644 --- a/lib/src/views/chats/chat_list.view.dart +++ b/lib/src/views/chats/chat_list.view.dart @@ -27,6 +27,7 @@ class ChatListView extends StatefulWidget { } class _ChatListViewState extends State { + StreamSubscription? _userSub; late StreamSubscription> _contactsSub; List _groupsNotPinned = []; List _groupsPinned = []; @@ -43,6 +44,9 @@ class _ChatListViewState extends State { @override void initState() { initAsync(); + _userSub = AppSession.onUserUpdated.listen((_) { + if (mounted) setState(() {}); + }); super.initState(); } @@ -85,11 +89,11 @@ class _ChatListViewState extends State { Sha256().hash, changeLog.codeUnits, )).bytes; - if (!gUser.hideChangeLog && - gUser.lastChangeLogHash.toString() != changeLogHash.toString()) { - await updateUserdata((u) { + if (!AppSession.currentUser.hideChangeLog && + AppSession.currentUser.lastChangeLogHash.toString() != + changeLogHash.toString()) { + await updateUser((u) { u.lastChangeLogHash = changeLogHash; - return u; }); if (!mounted) return; // only show changelog to people who already have contacts @@ -109,6 +113,7 @@ class _ChatListViewState extends State { _contactsSub.cancel(); _countContactRequestStream.cancel(); _countAnnouncedStream.cancel(); + _userSub?.cancel(); super.dispose(); } @@ -122,9 +127,7 @@ class _ChatListViewState extends State { ConnectionStatusBadge( child: GestureDetector( onTap: () async { - await context.push(Routes.settingsProfile); - if (!mounted) return; - setState(() {}); // gUser has updated + context.push(Routes.settingsProfile); }, child: AvatarIcon( myAvatar: true, @@ -199,8 +202,7 @@ class _ChatListViewState extends State { IconButton( onPressed: () async { - await context.push(Routes.settings); - if (mounted) setState(() {}); // gUser may has changed... + context.push(Routes.settings); }, icon: const FaIcon(FontAwesomeIcons.gear, size: 19), ), diff --git a/lib/src/views/chats/chat_messages.view.dart b/lib/src/views/chats/chat_messages.view.dart index 8b30c0bd..463a1622 100644 --- a/lib/src/views/chats/chat_messages.view.dart +++ b/lib/src/views/chats/chat_messages.view.dart @@ -122,7 +122,7 @@ class _ChatMessagesViewState extends State { _receiverDeletedAccount = groupContacts.first.accountDeleted; } - if (gUser.typingIndicators) { + if (AppSession.currentUser.typingIndicators) { unawaited(sendTypingIndication(widget.groupId, false)); _nextTypingIndicator = Timer.periodic(const Duration(seconds: 4), ( _, @@ -287,7 +287,7 @@ class _ChatMessagesViewState extends State { itemScrollController: itemScrollController, itemBuilder: (context, i) { if (i == 0) { - return gUser.typingIndicators + return AppSession.currentUser.typingIndicators ? TypingIndicator(group: group) : Container(); } diff --git a/lib/src/views/chats/chat_messages_components/entries/chat_contacts.entry.dart b/lib/src/views/chats/chat_messages_components/entries/chat_contacts.entry.dart index fa346998..2243cea9 100644 --- a/lib/src/views/chats/chat_messages_components/entries/chat_contacts.entry.dart +++ b/lib/src/views/chats/chat_messages_components/entries/chat_contacts.entry.dart @@ -102,7 +102,7 @@ class _ContactRowState extends State<_ContactRow> { bool _isLoading = false; Future _onContactClick(bool isAdded) async { - if (widget.contact.userId.toInt() == gUser.userId) { + if (widget.contact.userId.toInt() == AppSession.currentUser.userId) { await context.push(Routes.settingsProfile); return; } @@ -162,7 +162,7 @@ class _ContactRowState extends State<_ContactRow> { final contactInDb = snapshot.data; final isAdded = contactInDb != null || - widget.contact.userId.toInt() == gUser.userId; + widget.contact.userId.toInt() == AppSession.currentUser.userId; return GestureDetector( onTap: _isLoading ? null : () => _onContactClick(isAdded), diff --git a/lib/src/views/chats/chat_messages_components/message_input.dart b/lib/src/views/chats/chat_messages_components/message_input.dart index 8b19a12a..5ad205af 100644 --- a/lib/src/views/chats/chat_messages_components/message_input.dart +++ b/lib/src/views/chats/chat_messages_components/message_input.dart @@ -72,7 +72,7 @@ class _MessageInputState extends State { _textFieldController.text = widget.group.draftMessage!; } widget.textFieldFocus.addListener(_handleTextFocusChange); - if (gUser.typingIndicators) { + if (AppSession.currentUser.typingIndicators) { _nextTypingIndicator = Timer.periodic(const Duration(seconds: 1), ( _, ) async { diff --git a/lib/src/views/chats/media_viewer_components/reaction_buttons.component.dart b/lib/src/views/chats/media_viewer_components/reaction_buttons.component.dart index 342fbf10..74bb167e 100644 --- a/lib/src/views/chats/media_viewer_components/reaction_buttons.component.dart +++ b/lib/src/views/chats/media_viewer_components/reaction_buttons.component.dart @@ -50,8 +50,8 @@ class _ReactionButtonsState extends State { } Future initAsync() async { - if (gUser.preSelectedEmojies != null) { - selectedEmojis = gUser.preSelectedEmojies!; + if (AppSession.currentUser.preSelectedEmojies != null) { + selectedEmojis = AppSession.currentUser.preSelectedEmojies!; } setState(() {}); } diff --git a/lib/src/views/components/avatar_icon.component.dart b/lib/src/views/components/avatar_icon.component.dart index 3ece858e..122f2e9d 100644 --- a/lib/src/views/components/avatar_icon.component.dart +++ b/lib/src/views/components/avatar_icon.component.dart @@ -33,7 +33,7 @@ class _AvatarIconState extends State { StreamSubscription>? groupStream; StreamSubscription>? contactsStream; StreamSubscription? contactStream; - StreamSubscription? _userDataSub; + StreamSubscription? _userSub; @override void initState() { @@ -46,7 +46,7 @@ class _AvatarIconState extends State { groupStream?.cancel(); contactStream?.cancel(); contactsStream?.cancel(); - _userDataSub?.cancel(); + _userSub?.cancel(); super.dispose(); } @@ -93,19 +93,19 @@ class _AvatarIconState extends State { setState(() {}); }); } else if (widget.myAvatar) { - _userDataSub = userDataUpdateController.stream.listen((_) { + _userSub = AppSession.onUserUpdated.listen((_) { if (mounted) { setState(() { - if (gUser.avatarSvg != null) { - _avatarSvg = gUser.avatarSvg; + if (AppSession.currentUser.avatarSvg != null) { + _avatarSvg = AppSession.currentUser.avatarSvg; } else { _avatarContacts = []; } }); } }); - if (gUser.avatarSvg != null) { - _avatarSvg = gUser.avatarSvg; + if (AppSession.currentUser.avatarSvg != null) { + _avatarSvg = AppSession.currentUser.avatarSvg; } } else if (widget.contactId != null) { contactStream = twonlyDB.contactsDao diff --git a/lib/src/views/components/flame.dart b/lib/src/views/components/flame.dart index 07dae00c..1ea1ff17 100644 --- a/lib/src/views/components/flame.dart +++ b/lib/src/views/components/flame.dart @@ -48,7 +48,7 @@ class _FlameCounterWidgetState extends State { } if (groupId != null && group != null) { isBestFriend = - gUser.myBestFriendGroupId == groupId && group.alsoBestFriend; + AppSession.currentUser.myBestFriendGroupId == groupId && group.alsoBestFriend; final stream = twonlyDB.groupsDao.watchFlameCounter(groupId); flameCounterSub = stream.listen((counter) { if (mounted) { diff --git a/lib/src/views/components/max_flame_list_title.dart b/lib/src/views/components/max_flame_list_title.dart index a214b462..af2c41b4 100644 --- a/lib/src/views/components/max_flame_list_title.dart +++ b/lib/src/views/components/max_flame_list_title.dart @@ -38,7 +38,10 @@ class _MaxFlameListTitleState extends State { @override void initState() { - _groupId = getUUIDforDirectChat(widget.contactId, gUser.userId); + _groupId = getUUIDforDirectChat( + widget.contactId, + AppSession.currentUser.userId, + ); final stream = twonlyDB.groupsDao.watchGroup(_groupId); _groupSub = stream.listen((update) { if (mounted) setState(() => _group = update); @@ -53,7 +56,8 @@ class _MaxFlameListTitleState extends State { } Future _restoreFlames() async { - if (!isUserAllowed(getCurrentPlan(), PremiumFeatures.RestoreFlames) && + final currentPlan = planFromString(AppSession.currentUser.subscriptionPlan); + if (!isUserAllowed(currentPlan, PremiumFeatures.RestoreFlames) && kReleaseMode) { await context.push(Routes.settingsSubscription); return; diff --git a/lib/src/views/contact/contact.view.dart b/lib/src/views/contact/contact.view.dart index b438b604..882eb3a8 100644 --- a/lib/src/views/contact/contact.view.dart +++ b/lib/src/views/contact/contact.view.dart @@ -204,7 +204,7 @@ class _ContactViewState extends State { }, ), SelectChatDeletionTimeListTitle( - groupId: getUUIDforDirectChat(widget.userId, gUser.userId), + groupId: getUUIDforDirectChat(widget.userId, AppSession.currentUser.userId), ), const Divider(), MaxFlameListTitle( @@ -222,17 +222,17 @@ class _ContactViewState extends State { setState(() {}); }, ), - if (gUser.isUserDiscoveryEnabled) + if (AppSession.currentUser.isUserDiscoveryEnabled) BetterListTile( icon: FontAwesomeIcons.usersViewfinder, text: context.lang.userDiscoverySettingsTitle, subtitle: !contact.userDiscoveryExcluded && contact.mediaSendCounter < - gUser.minimumRequiredImagesExchanged + AppSession.currentUser.minimumRequiredImagesExchanged ? Text( context.lang.contactUserDiscoveryImagesLeft( - gUser.minimumRequiredImagesExchanged - + AppSession.currentUser.minimumRequiredImagesExchanged - contact.mediaSendCounter, getContactDisplayName(contact), ), diff --git a/lib/src/views/groups/group.view.dart b/lib/src/views/groups/group.view.dart index abee84b1..884df911 100644 --- a/lib/src/views/groups/group.view.dart +++ b/lib/src/views/groups/group.view.dart @@ -142,7 +142,7 @@ class _GroupViewState extends State { success = await removeMemberFromGroup( _group!, keyPair.getPublicKey().serialize(), - gUser.userId, + AppSession.currentUser.userId, ); } else { success = await leaveAsNonAdminFromGroup(_group!); diff --git a/lib/src/views/home.view.dart b/lib/src/views/home.view.dart index 8d5b889c..3638cfec 100644 --- a/lib/src/views/home.view.dart +++ b/lib/src/views/home.view.dart @@ -135,7 +135,7 @@ class HomeViewState extends State { _mainCameraController.setSharedLinkForPreview, ); WidgetsBinding.instance.addPostFrameCallback((_) { - if (widget.initialPage == 1 && !gUser.startWithCameraOpen || + if (widget.initialPage == 1 && !AppSession.currentUser.startWithCameraOpen || widget.initialPage == 0) { globalUpdateOfHomeViewPageIndex(0); } diff --git a/lib/src/views/memories/memories_photo_slider.view.dart b/lib/src/views/memories/memories_photo_slider.view.dart index a44dbecd..85ebf4fb 100644 --- a/lib/src/views/memories/memories_photo_slider.view.dart +++ b/lib/src/views/memories/memories_photo_slider.view.dart @@ -98,7 +98,7 @@ class _MemoriesPhotoSliderViewState extends State { final newMediaService = await initializeMediaUpload( orgMediaService.mediaFile.type, - gUser.defaultShowTime, + AppSession.currentUser.defaultShowTime, ); if (newMediaService == null) { Log.error('Could not create new mediaFIle'); diff --git a/lib/src/views/onboarding/register.view.dart b/lib/src/views/onboarding/register.view.dart index 86f6dcd8..c0f9b831 100644 --- a/lib/src/views/onboarding/register.view.dart +++ b/lib/src/views/onboarding/register.view.dart @@ -142,7 +142,7 @@ class _RegisterViewState extends State { value: jsonEncode(userData), ); - gUser = userData; + AppSession.currentUser = userData; await apiService.authenticate(); widget.callbackOnSuccess(); diff --git a/lib/src/views/public_profile.view.dart b/lib/src/views/public_profile.view.dart index a2bb355d..091b672e 100644 --- a/lib/src/views/public_profile.view.dart +++ b/lib/src/views/public_profile.view.dart @@ -107,7 +107,7 @@ class _PublicProfileViewState extends State { ), const SizedBox(height: 20), Text( - gUser.username, + AppSession.currentUser.username, style: const TextStyle(fontSize: 24), ), const SizedBox(height: 20), @@ -126,11 +126,11 @@ class _PublicProfileViewState extends State { text: context.lang.shareYourProfile, subtitle: (_publicKey == null) ? null - : Text('https://me.twonly.eu/${gUser.username}'), + : Text('https://me.twonly.eu/${AppSession.currentUser.username}'), onTap: () { final params = ShareParams( text: - 'https://me.twonly.eu/${gUser.username}#${base64Url.encode(_publicKey!)}', + 'https://me.twonly.eu/${AppSession.currentUser.username}#${base64Url.encode(_publicKey!)}', ); SharePlus.instance.share(params); }, diff --git a/lib/src/views/settings/appearance.view.dart b/lib/src/views/settings/appearance.view.dart index a23be18b..e396755e 100644 --- a/lib/src/views/settings/appearance.view.dart +++ b/lib/src/views/settings/appearance.view.dart @@ -73,32 +73,20 @@ class _AppearanceViewState extends State { } Future toggleShowFeedbackIcon() async { - await updateUserdata((u) { + await updateUser((u) { u.showFeedbackShortcut = !u.showFeedbackShortcut; - return u; - }); - setState(() { - // gUser }); } Future toggleStartWithCameraOpen() async { - await updateUserdata((u) { + await updateUser((u) { u.startWithCameraOpen = !u.startWithCameraOpen; - return u; - }); - setState(() { - // gUser }); } Future toggleShowImagePreviewWhenSending() async { - await updateUserdata((u) { + await updateUser((u) { u.showShowImagePreviewWhenSending = !u.showShowImagePreviewWhenSending; - return u; - }); - setState(() { - // gUser }); } @@ -109,43 +97,48 @@ class _AppearanceViewState extends State { appBar: AppBar( title: Text(context.lang.settingsAppearance), ), - body: ListView( - children: [ - ListTile( - title: Text(context.lang.settingsAppearanceTheme), - subtitle: Text( - selectedTheme.name, - style: const TextStyle(color: Colors.grey), - ), - onTap: () async { - await _showSelectThemeMode(context); - }, - ), - ListTile( - title: Text(context.lang.contactUsShortcut), - onTap: toggleShowFeedbackIcon, - trailing: Switch( - value: !gUser.showFeedbackShortcut, - onChanged: (a) => toggleShowFeedbackIcon(), - ), - ), - ListTile( - title: Text(context.lang.startWithCameraOpen), - onTap: toggleStartWithCameraOpen, - trailing: Switch( - value: gUser.startWithCameraOpen, - onChanged: (a) => toggleStartWithCameraOpen(), - ), - ), - ListTile( - title: Text(context.lang.showImagePreviewWhenSending), - onTap: toggleShowImagePreviewWhenSending, - trailing: Switch( - value: gUser.showShowImagePreviewWhenSending, - onChanged: (a) => toggleShowImagePreviewWhenSending(), - ), - ), - ], + body: StreamBuilder( + stream: AppSession.onUserUpdated, + builder: (context, snapshot) { + return ListView( + children: [ + ListTile( + title: Text(context.lang.settingsAppearanceTheme), + subtitle: Text( + selectedTheme.name, + style: const TextStyle(color: Colors.grey), + ), + onTap: () async { + await _showSelectThemeMode(context); + }, + ), + ListTile( + title: Text(context.lang.contactUsShortcut), + onTap: toggleShowFeedbackIcon, + trailing: Switch( + value: !AppSession.currentUser.showFeedbackShortcut, + onChanged: (a) => toggleShowFeedbackIcon(), + ), + ), + ListTile( + title: Text(context.lang.startWithCameraOpen), + onTap: toggleStartWithCameraOpen, + trailing: Switch( + value: AppSession.currentUser.startWithCameraOpen, + onChanged: (a) => toggleStartWithCameraOpen(), + ), + ), + ListTile( + title: Text(context.lang.showImagePreviewWhenSending), + onTap: toggleShowImagePreviewWhenSending, + trailing: Switch( + value: AppSession.currentUser.showShowImagePreviewWhenSending, + onChanged: (a) => toggleShowImagePreviewWhenSending(), + ), + ), + ], + ); + }, ), ); } diff --git a/lib/src/views/settings/backup/backup.view.dart b/lib/src/views/settings/backup/backup.view.dart index 95e4f314..5f55ed45 100644 --- a/lib/src/views/settings/backup/backup.view.dart +++ b/lib/src/views/settings/backup/backup.view.dart @@ -8,8 +8,6 @@ import 'package:twonly/src/model/json/userdata.dart'; import 'package:twonly/src/services/backup/create.backup.dart'; import 'package:twonly/src/utils/misc.dart'; -void Function() gUpdateBackupView = () {}; - class BackupView extends StatefulWidget { const BackupView({super.key}); @@ -34,18 +32,9 @@ class _BackupViewState extends State { void initState() { super.initState(); unawaited(initAsync()); - gUpdateBackupView = initAsync; } - @override - void dispose() { - gUpdateBackupView = () {}; - super.dispose(); - } - - Future initAsync() async { - setState(() {}); - } + Future initAsync() async {} String backupStatus(LastBackupUploadState status) { switch (status) { @@ -62,156 +51,170 @@ class _BackupViewState extends State { Future changeTwonlySafePassword() async { await context.push(Routes.settingsBackupSetup, extra: true); - setState(() { - // gUser was updated - }); } @override Widget build(BuildContext context) { - final backupServer = gUser.backupServer ?? defaultBackupServer; - return Scaffold( - appBar: AppBar( - title: Text(context.lang.settingsBackup), - ), - body: PageView( - controller: pageController, - onPageChanged: (index) { - setState(() { - activePageIdx = index; - }); - }, - children: [ - BackupOption( - title: 'twonly Backup', - description: context.lang.backupTwonlySafeDesc, - bottomButton: FilledButton( - onPressed: changeTwonlySafePassword, - child: Text(context.lang.backupChangePassword), - ), - child: (gUser.twonlySafeBackup == null) - ? null - : Column( - children: [ - Table( - defaultVerticalAlignment: - TableCellVerticalAlignment.middle, + return StreamBuilder( + stream: AppSession.onUserUpdated, + builder: (context, _) { + final backupServer = + AppSession.currentUser.backupServer ?? defaultBackupServer; + return Scaffold( + appBar: AppBar( + title: Text(context.lang.settingsBackup), + ), + body: PageView( + controller: pageController, + onPageChanged: (index) { + setState(() { + activePageIdx = index; + }); + }, + children: [ + BackupOption( + title: 'twonly Backup', + description: context.lang.backupTwonlySafeDesc, + bottomButton: FilledButton( + onPressed: changeTwonlySafePassword, + child: Text(context.lang.backupChangePassword), + ), + child: (AppSession.currentUser.twonlySafeBackup == null) + ? null + : Column( children: [ - ...[ - ( - context.lang.backupServer, - (backupServer.serverUrl.contains('@')) - ? backupServer.serverUrl.split('@')[1] - : backupServer.serverUrl.replaceAll( - 'https://', - '', - ), - ), - ( - context.lang.backupMaxBackupSize, - formatBytes(backupServer.maxBackupBytes), - ), - ( - context.lang.backupStorageRetention, - '${backupServer.retentionDays} Days', - ), - ( - context.lang.backupLastBackupDate, - formatDateTime( - context, - gUser.twonlySafeBackup!.lastBackupDone, - ), - ), - ( - context.lang.backupLastBackupSize, - formatBytes( - gUser.twonlySafeBackup!.lastBackupSize, - ), - ), - ( - context.lang.backupLastBackupResult, - backupStatus( - gUser.twonlySafeBackup!.backupUploadState, - ), - ), - ].map((pair) { - return TableRow( - children: [ - TableCell( - // padding: EdgeInsets.all(4), - child: Text(pair.$1), + Table( + defaultVerticalAlignment: + TableCellVerticalAlignment.middle, + children: [ + ...[ + ( + context.lang.backupServer, + (backupServer.serverUrl.contains('@')) + ? backupServer.serverUrl.split('@')[1] + : backupServer.serverUrl.replaceAll( + 'https://', + '', + ), ), - TableCell( - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 4, - ), - child: Text( - pair.$2, - textAlign: TextAlign.right, - ), + ( + context.lang.backupMaxBackupSize, + formatBytes(backupServer.maxBackupBytes), + ), + ( + context.lang.backupStorageRetention, + '${backupServer.retentionDays} Days', + ), + ( + context.lang.backupLastBackupDate, + formatDateTime( + context, + AppSession + .currentUser + .twonlySafeBackup! + .lastBackupDone, ), ), - ], - ); - }), + ( + context.lang.backupLastBackupSize, + formatBytes( + AppSession + .currentUser + .twonlySafeBackup! + .lastBackupSize, + ), + ), + ( + context.lang.backupLastBackupResult, + backupStatus( + AppSession + .currentUser + .twonlySafeBackup! + .backupUploadState, + ), + ), + ].map((pair) { + return TableRow( + children: [ + TableCell( + // padding: EdgeInsets.all(4), + child: Text(pair.$1), + ), + TableCell( + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 4, + ), + child: Text( + pair.$2, + textAlign: TextAlign.right, + ), + ), + ), + ], + ); + }), + ], + ), + const SizedBox(height: 10), + OutlinedButton( + onPressed: isLoading + ? null + : () async { + setState(() { + isLoading = true; + }); + await performTwonlySafeBackup(force: true); + setState(() { + isLoading = false; + }); + }, + child: Text(context.lang.backupTwonlySaveNow), + ), ], ), - const SizedBox(height: 10), - OutlinedButton( - onPressed: isLoading - ? null - : () async { - setState(() { - isLoading = true; - }); - await performTwonlySafeBackup(force: true); - setState(() { - isLoading = false; - }); - }, - child: Text(context.lang.backupTwonlySaveNow), - ), - ], - ), + ), + BackupOption( + title: '${context.lang.backupData} (Coming Soon)', + description: context.lang.backupDataDesc, + ), + ], ), - BackupOption( - title: '${context.lang.backupData} (Coming Soon)', - description: context.lang.backupDataDesc, + bottomNavigationBar: BottomNavigationBar( + showSelectedLabels: true, + showUnselectedLabels: true, + unselectedIconTheme: IconThemeData( + color: Theme.of( + context, + ).colorScheme.inverseSurface.withAlpha(150), + ), + selectedIconTheme: IconThemeData( + color: Theme.of(context).colorScheme.inverseSurface, + ), + items: [ + const BottomNavigationBarItem( + icon: FaIcon(FontAwesomeIcons.vault, size: 17), + label: 'twonly Backup', + ), + BottomNavigationBarItem( + icon: const FaIcon(Icons.archive_outlined, size: 17), + label: context.lang.backupData, + ), + ], + onTap: (index) async { + activePageIdx = index; + await pageController.animateToPage( + index, + duration: const Duration(milliseconds: 100), + curve: Curves.bounceIn, + ); + if (mounted) setState(() {}); + }, + currentIndex: activePageIdx, + // ), ), - ], - ), - bottomNavigationBar: BottomNavigationBar( - showSelectedLabels: true, - showUnselectedLabels: true, - unselectedIconTheme: IconThemeData( - color: Theme.of(context).colorScheme.inverseSurface.withAlpha(150), - ), - selectedIconTheme: IconThemeData( - color: Theme.of(context).colorScheme.inverseSurface, - ), - items: [ - const BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.vault, size: 17), - label: 'twonly Backup', - ), - BottomNavigationBarItem( - icon: const FaIcon(Icons.archive_outlined, size: 17), - label: context.lang.backupData, - ), - ], - onTap: (index) async { - activePageIdx = index; - await pageController.animateToPage( - index, - duration: const Duration(milliseconds: 100), - curve: Curves.bounceIn, - ); - if (mounted) setState(() {}); - }, - currentIndex: activePageIdx, - // ), - ), + ); + }, ); } } diff --git a/lib/src/views/settings/backup/backup_server.view.dart b/lib/src/views/settings/backup/backup_server.view.dart index de780810..433a1214 100644 --- a/lib/src/views/settings/backup/backup_server.view.dart +++ b/lib/src/views/settings/backup/backup_server.view.dart @@ -31,8 +31,8 @@ class _BackupServerViewState extends State { } Future initAsync() async { - if (gUser.backupServer != null) { - final uri = Uri.parse(gUser.backupServer!.serverUrl); + if (AppSession.currentUser.backupServer != null) { + final uri = Uri.parse(AppSession.currentUser.backupServer!.serverUrl); // remove user auth data final serverUrl = Uri( scheme: uri.scheme, @@ -79,9 +79,8 @@ class _BackupServerViewState extends State { retentionDays: data['retentionDays']! as int, maxBackupBytes: data['maxBackupBytes']! as int, ); - await updateUserdata((user) { + await updateUser((user) { user.backupServer = backupServer; - return user; }); if (mounted) Navigator.pop(context, backupServer); } else { @@ -166,9 +165,8 @@ class _BackupServerViewState extends State { Center( child: OutlinedButton( onPressed: () async { - await updateUserdata((user) { + await updateUser((user) { user.backupServer = null; - return user; }); if (context.mounted) Navigator.pop(context); }, diff --git a/lib/src/views/settings/chat/chat_reactions.view.dart b/lib/src/views/settings/chat/chat_reactions.view.dart index 6adae922..a58778e9 100644 --- a/lib/src/views/settings/chat/chat_reactions.view.dart +++ b/lib/src/views/settings/chat/chat_reactions.view.dart @@ -38,9 +38,8 @@ class _ChatReactionSelectionView extends State { } else { if (selectedEmojis.length < 12) { selectedEmojis.add(emoji); - await updateUserdata((user) { + await updateUser((user) { user.preSelectedEmojies = selectedEmojis; - return user; }); } else { ScaffoldMessenger.of(context).showSnackBar( @@ -99,9 +98,8 @@ class _ChatReactionSelectionView extends State { 6, ); setState(() {}); - await updateUserdata((user) { + await updateUser((user) { user.preSelectedEmojies = selectedEmojis; - return user; }); }, child: const Icon(Icons.settings_backup_restore_rounded), diff --git a/lib/src/views/settings/data_and_storage.view.dart b/lib/src/views/settings/data_and_storage.view.dart index 7043785a..96b590b1 100644 --- a/lib/src/views/settings/data_and_storage.view.dart +++ b/lib/src/views/settings/data_and_storage.view.dart @@ -27,110 +27,121 @@ class _DataAndStorageViewState extends State { builder: (context) { return AutoDownloadOptionsDialog( autoDownloadOptions: - gUser.autoDownloadOptions ?? defaultAutoDownloadOptions, + AppSession.currentUser.autoDownloadOptions ?? + defaultAutoDownloadOptions, connectionMode: connectionMode, - onUpdate: () async { - setState(() {}); - }, + onUpdate: () {}, ); }, ); } Future toggleStoreInGallery() async { - await updateUserdata((u) { + await updateUser((u) { u.storeMediaFilesInGallery = !u.storeMediaFilesInGallery; - return u; }); - setState(() {}); } Future toggleAutoStoreMediaFiles() async { - await updateUserdata((u) { + await updateUser((u) { u.autoStoreAllSendUnlimitedMediaFiles = !u.autoStoreAllSendUnlimitedMediaFiles; - return u; }); - setState(() {}); } @override Widget build(BuildContext context) { - final autoDownloadOptions = - gUser.autoDownloadOptions ?? defaultAutoDownloadOptions; return Scaffold( appBar: AppBar( title: Text(context.lang.settingsStorageData), ), - body: ListView( - children: [ - ListTile( - title: Text(context.lang.settingsStorageDataStoreInGTitle), - subtitle: Text(context.lang.settingsStorageDataStoreInGSubtitle), - onTap: toggleStoreInGallery, - trailing: Switch( - value: gUser.storeMediaFilesInGallery, - onChanged: (a) => toggleStoreInGallery(), - ), - ), - ListTile( - title: Text(context.lang.autoStoreAllSendUnlimitedMediaFiles), - subtitle: Text( - context.lang.autoStoreAllSendUnlimitedMediaFilesSubtitle, - style: const TextStyle(fontSize: 9), - ), - onTap: toggleAutoStoreMediaFiles, - trailing: Switch( - value: gUser.autoStoreAllSendUnlimitedMediaFiles, - onChanged: (a) => toggleAutoStoreMediaFiles(), - ), - ), - if (Platform.isAndroid) - ListTile( - title: Text( - context.lang.exportMemories, + body: StreamBuilder( + stream: AppSession.onUserUpdated, + builder: (context, _) { + final autoDownloadOptions = + AppSession.currentUser.autoDownloadOptions ?? + defaultAutoDownloadOptions; + return ListView( + children: [ + ListTile( + title: Text(context.lang.settingsStorageDataStoreInGTitle), + subtitle: Text( + context.lang.settingsStorageDataStoreInGSubtitle, + ), + onTap: toggleStoreInGallery, + trailing: Switch( + value: AppSession.currentUser.storeMediaFilesInGallery, + onChanged: (a) => toggleStoreInGallery(), + ), ), - onTap: () => context.push(Routes.settingsStorageExport), - ), - if (Platform.isAndroid) - ListTile( - title: Text( - context.lang.importMemories, + ListTile( + title: Text(context.lang.autoStoreAllSendUnlimitedMediaFiles), + subtitle: Text( + context.lang.autoStoreAllSendUnlimitedMediaFilesSubtitle, + style: const TextStyle(fontSize: 9), + ), + onTap: toggleAutoStoreMediaFiles, + trailing: Switch( + value: AppSession + .currentUser + .autoStoreAllSendUnlimitedMediaFiles, + onChanged: (a) => toggleAutoStoreMediaFiles(), + ), ), - onTap: () => context.push(Routes.settingsStorageImport), - ), - const Divider(), - ListTile( - title: Text( - context.lang.settingsStorageDataMediaAutoDownload, - style: const TextStyle(fontSize: 13), - ), - ), - ListTile( - title: Text(context.lang.settingsStorageDataAutoDownMobile), - subtitle: Text( - autoDownloadOptions[ConnectivityResult.mobile.name]! - .where((e) => e != 'audio') - .join(', '), - style: const TextStyle(color: Colors.grey), - ), - onTap: () async { - await showAutoDownloadOptions(context, ConnectivityResult.mobile); - }, - ), - ListTile( - title: Text(context.lang.settingsStorageDataAutoDownWifi), - subtitle: Text( - autoDownloadOptions[ConnectivityResult.wifi.name]! - .where((e) => e != 'audio') - .join(', '), - style: const TextStyle(color: Colors.grey), - ), - onTap: () async { - await showAutoDownloadOptions(context, ConnectivityResult.wifi); - }, - ), - ], + if (Platform.isAndroid) + ListTile( + title: Text( + context.lang.exportMemories, + ), + onTap: () => context.push(Routes.settingsStorageExport), + ), + if (Platform.isAndroid) + ListTile( + title: Text( + context.lang.importMemories, + ), + onTap: () => context.push(Routes.settingsStorageImport), + ), + const Divider(), + ListTile( + title: Text( + context.lang.settingsStorageDataMediaAutoDownload, + style: const TextStyle(fontSize: 13), + ), + ), + ListTile( + title: Text(context.lang.settingsStorageDataAutoDownMobile), + subtitle: Text( + autoDownloadOptions[ConnectivityResult.mobile.name]! + .where((e) => e != 'audio') + .join(', '), + style: const TextStyle(color: Colors.grey), + ), + onTap: () async { + await showAutoDownloadOptions( + context, + ConnectivityResult.mobile, + ); + }, + ), + ListTile( + title: Text(context.lang.settingsStorageDataAutoDownWifi), + subtitle: Text( + autoDownloadOptions[ConnectivityResult.wifi.name]! + .where((e) => e != 'audio') + .join(', '), + style: const TextStyle(color: Colors.grey), + ), + onTap: () async { + await showAutoDownloadOptions( + context, + ConnectivityResult.wifi, + ); + }, + ), + ], + ); + }, ), ); } @@ -215,9 +226,8 @@ class _AutoDownloadOptionsDialogState extends State { // Call the onUpdate callback to notify the parent widget - await updateUserdata((u) { + await updateUser((u) { u.autoDownloadOptions = autoDownloadOptions; - return u; }); widget.onUpdate(); diff --git a/lib/src/views/settings/developer/developer.view.dart b/lib/src/views/settings/developer/developer.view.dart index a9d3ca57..00486e14 100644 --- a/lib/src/views/settings/developer/developer.view.dart +++ b/lib/src/views/settings/developer/developer.view.dart @@ -26,19 +26,13 @@ class _DeveloperSettingsViewState extends State { } Future toggleDeveloperSettings() async { - await updateUserdata((u) { - u.isDeveloper = !u.isDeveloper; - return u; - }); - setState(() {}); + await updateUser((u) => u.isDeveloper = !u.isDeveloper); } Future toggleVideoStabilization() async { - await updateUserdata((u) { - u.videoStabilizationEnabled = !u.videoStabilizationEnabled; - return u; - }); - setState(() {}); + await updateUser( + (u) => u.videoStabilizationEnabled = !u.videoStabilizationEnabled, + ); } @override @@ -47,80 +41,86 @@ class _DeveloperSettingsViewState extends State { appBar: AppBar( title: const Text('Developer Settings'), ), - body: ListView( - children: [ - ListTile( - title: const Text('Show Developer Settings'), - onTap: toggleDeveloperSettings, - trailing: Switch( - value: gUser.isDeveloper, - onChanged: (a) => toggleDeveloperSettings(), - ), - ), - ListTile( - title: const Text('Show Retransmission Database'), - onTap: () => - context.push(Routes.settingsDeveloperRetransmissionDatabase), - ), - ListTile( - title: const Text('Toggle Video Stabilization'), - onTap: toggleVideoStabilization, - trailing: Switch( - value: gUser.videoStabilizationEnabled, - onChanged: (a) => toggleVideoStabilization(), - ), - ), - ListTile( - title: const Text('Delete all (!) app data'), - onTap: () async { - final ok = await showAlertDialog( - context, - 'Sure?', - 'If you do not have a backup, you have to register with a new account.', - ); - if (ok) { - await deleteLocalUserData(); - await Restart.restartApp( - notificationTitle: 'Account successfully deleted', - notificationBody: 'Click here to open the app again', - forceKill: true, - ); - } - }, - ), - ListTile( - title: const Text('Reduce flames'), - onTap: () => context.push(Routes.settingsDeveloperReduceFlames), - ), - if (!kReleaseMode) - ListTile( - title: const Text('Make it possible to reset flames'), - onTap: () async { - final chats = await twonlyDB.groupsDao.getAllDirectChats(); - - for (final chat in chats) { - await twonlyDB.groupsDao.updateGroup( - chat.groupId, - GroupsCompanion( - flameCounter: const Value(0), - maxFlameCounter: const Value(365), - lastFlameCounterChange: Value(clock.now()), - maxFlameCounterFrom: Value( - clock.now().subtract(const Duration(days: 1)), - ), - ), + body: StreamBuilder( + stream: AppSession.onUserUpdated, + builder: (context, _) { + return ListView( + children: [ + ListTile( + title: const Text('Show Developer Settings'), + onTap: toggleDeveloperSettings, + trailing: Switch( + value: AppSession.currentUser.isDeveloper, + onChanged: (_) => toggleDeveloperSettings(), + ), + ), + ListTile( + title: const Text('Show Retransmission Database'), + onTap: () => context.push( + Routes.settingsDeveloperRetransmissionDatabase, + ), + ), + ListTile( + title: const Text('Toggle Video Stabilization'), + onTap: toggleVideoStabilization, + trailing: Switch( + value: AppSession.currentUser.videoStabilizationEnabled, + onChanged: (a) => toggleVideoStabilization(), + ), + ), + ListTile( + title: const Text('Delete all (!) app data'), + onTap: () async { + final ok = await showAlertDialog( + context, + 'Sure?', + 'If you do not have a backup, you have to register with a new account.', ); - } - await HapticFeedback.heavyImpact(); - }, - ), - if (!kReleaseMode) - ListTile( - title: const Text('Automated Testing'), - onTap: () => - context.push(Routes.settingsDeveloperAutomatedTesting), - ), - ], + if (ok) { + await deleteLocalUserData(); + await Restart.restartApp( + notificationTitle: 'Account successfully deleted', + notificationBody: 'Click here to open the app again', + forceKill: true, + ); + } + }, + ), + ListTile( + title: const Text('Reduce flames'), + onTap: () => context.push(Routes.settingsDeveloperReduceFlames), + ), + if (!kReleaseMode) + ListTile( + title: const Text('Make it possible to reset flames'), + onTap: () async { + final chats = await twonlyDB.groupsDao.getAllDirectChats(); + + for (final chat in chats) { + await twonlyDB.groupsDao.updateGroup( + chat.groupId, + GroupsCompanion( + flameCounter: const Value(0), + maxFlameCounter: const Value(365), + lastFlameCounterChange: Value(clock.now()), + maxFlameCounterFrom: Value( + clock.now().subtract(const Duration(days: 1)), + ), + ), + ); + } + await HapticFeedback.heavyImpact(); + }, + ), + if (!kReleaseMode) + ListTile( + title: const Text('Automated Testing'), + onTap: () => + context.push(Routes.settingsDeveloperAutomatedTesting), + ), + ], + ); + }, ), ); } diff --git a/lib/src/views/settings/help/changelog.view.dart b/lib/src/views/settings/help/changelog.view.dart index bd2402f7..57bb0d17 100644 --- a/lib/src/views/settings/help/changelog.view.dart +++ b/lib/src/views/settings/help/changelog.view.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:twonly/globals.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/storage.dart'; @@ -73,7 +74,6 @@ class ChangeLogView extends StatefulWidget { class _ChangeLogViewState extends State { String changeLog = ''; - bool hideChangeLog = false; @override void initState() { @@ -87,49 +87,41 @@ class _ChangeLogViewState extends State { Future initAsync() async { changeLog = await rootBundle.loadString('CHANGELOG.md'); - final user = await getUser(); - if (user != null) { - hideChangeLog = user.hideChangeLog; - } - setState(() {}); - } - - Future _toggleAutoOpen(bool value) async { - await updateUserdata((u) { - u.hideChangeLog = !hideChangeLog; - return u; - }); - setState(() { - hideChangeLog = !value; - }); + if (mounted) setState(() {}); } @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Changelog'), - ), - body: SafeArea( - child: Padding( - padding: const EdgeInsets.all(8), - child: ListView( - children: parseMarkdown(context, changeLog), + return StreamBuilder( + stream: AppSession.onUserUpdated, + builder: (context, _) { + return Scaffold( + appBar: AppBar( + title: const Text('Changelog'), ), - ), - ), - bottomNavigationBar: BottomAppBar( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(context.lang.openChangeLog), - Switch( - value: !hideChangeLog, - onChanged: _toggleAutoOpen, + body: SafeArea( + child: Padding( + padding: const EdgeInsets.all(8), + child: ListView( + children: parseMarkdown(context, changeLog), + ), ), - ], - ), - ), + ), + bottomNavigationBar: BottomAppBar( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(context.lang.openChangeLog), + Switch( + value: !AppSession.currentUser.hideChangeLog, + onChanged: (_) => + updateUser((u) => u.hideChangeLog = !u.hideChangeLog), + ), + ], + ), + ), + ); + }, ); } } diff --git a/lib/src/views/settings/help/help.view.dart b/lib/src/views/settings/help/help.view.dart index 19b671e2..8bbb177d 100644 --- a/lib/src/views/settings/help/help.view.dart +++ b/lib/src/views/settings/help/help.view.dart @@ -19,11 +19,9 @@ class HelpView extends StatefulWidget { class _HelpViewState extends State { Future toggleAllowErrorTrackingViaSentry() async { - await updateUserdata((u) { - u.allowErrorTrackingViaSentry = !u.allowErrorTrackingViaSentry; - return u; - }); - setState(() {}); + await updateUser( + (u) => u.allowErrorTrackingViaSentry = !u.allowErrorTrackingViaSentry, + ); } @override @@ -32,111 +30,115 @@ class _HelpViewState extends State { appBar: AppBar( title: Text(context.lang.settingsHelp), ), - body: ListView( - children: [ - ListTile( - title: Text(context.lang.settingsHelpFAQ), - onTap: () => context.push(Routes.settingsHelpFaq), - ), - ListTile( - title: Text(context.lang.settingsHelpContactUs), - onTap: () => context.push(Routes.settingsHelpContactUs), - ), - const Divider(), - ListTile( - title: Text(context.lang.allowErrorTracking), - subtitle: Text( - context.lang.allowErrorTrackingSubtitle, - style: const TextStyle(fontSize: 10), - ), - onTap: toggleAllowErrorTrackingViaSentry, - trailing: Switch( - value: gUser.allowErrorTrackingViaSentry, - onChanged: (a) => toggleAllowErrorTrackingViaSentry(), - ), - ), - ListTile( - title: Text(context.lang.settingsHelpDiagnostics), - onTap: () => context.push(Routes.settingsHelpDiagnostics), - ), - const Divider(), - if (gUser.userStudyParticipantsToken == null || kDebugMode) - ListTile( - title: const Text('Teilnahme an Nutzerstudie'), - onTap: () => context.push(Routes.settingsHelpUserStudy), - ), - FutureBuilder( - future: PackageInfo.fromPlatform(), - builder: (context, snap) { - if (snap.hasData) { - return ListTile( - title: Text(context.lang.settingsHelpVersion), - subtitle: Text(snap.data!.version), - ); - } else { - return Container(); - } - }, - ), - ListTile( - title: Text(context.lang.settingsHelpLicenses), - onTap: () => showLicensePage(context: context), - ), - ListTile( - title: Text(context.lang.settingsHelpCredits), - onTap: () => context.push(Routes.settingsHelpCredits), - ), - ListTile( - title: const Text('Changelog'), - onTap: () => context.push(Routes.settingsHelpChangelog), - ), - ListTile( - title: const Text('Open Source'), - onTap: () => launchUrl( - Uri.parse('https://github.com/twonlyapp/twonly-app'), - ), - trailing: const FaIcon( - FontAwesomeIcons.arrowUpRightFromSquare, - size: 15, - ), - ), - ListTile( - title: Text(context.lang.settingsHelpImprint), - onTap: () => launchUrl(Uri.parse('https://twonly.eu/de/legal/')), - trailing: const FaIcon( - FontAwesomeIcons.arrowUpRightFromSquare, - size: 15, - ), - ), - ListTile( - title: Text(context.lang.settingsHelpTerms), - onTap: () => - launchUrl(Uri.parse('https://twonly.eu/de/legal/agb.html')), - trailing: const FaIcon( - FontAwesomeIcons.arrowUpRightFromSquare, - size: 15, - ), - ), - ListTile( - onLongPress: () async { - final okay = await showAlertDialog( - context, - 'Developer Settings', - 'Do you want to enable the developer settings?', - ); - if (okay) { - await updateUserdata((u) { - u.isDeveloper = true; - return u; - }); - } - }, - title: const Text( - 'Copyright twonly', - style: TextStyle(color: Colors.grey, fontSize: 13), - ), - ), - ], + body: StreamBuilder( + stream: AppSession.onUserUpdated, + builder: (context, _) { + return ListView( + children: [ + ListTile( + title: Text(context.lang.settingsHelpFAQ), + onTap: () => context.push(Routes.settingsHelpFaq), + ), + ListTile( + title: Text(context.lang.settingsHelpContactUs), + onTap: () => context.push(Routes.settingsHelpContactUs), + ), + const Divider(), + ListTile( + title: Text(context.lang.allowErrorTracking), + subtitle: Text( + context.lang.allowErrorTrackingSubtitle, + style: const TextStyle(fontSize: 10), + ), + onTap: toggleAllowErrorTrackingViaSentry, + trailing: Switch( + value: AppSession.currentUser.allowErrorTrackingViaSentry, + onChanged: (a) => toggleAllowErrorTrackingViaSentry(), + ), + ), + ListTile( + title: Text(context.lang.settingsHelpDiagnostics), + onTap: () => context.push(Routes.settingsHelpDiagnostics), + ), + const Divider(), + if (AppSession.currentUser.userStudyParticipantsToken == null || + kDebugMode) + ListTile( + title: const Text('Teilnahme an Nutzerstudie'), + onTap: () => context.push(Routes.settingsHelpUserStudy), + ), + FutureBuilder( + future: PackageInfo.fromPlatform(), + builder: (context, snap) { + if (snap.hasData) { + return ListTile( + title: Text(context.lang.settingsHelpVersion), + subtitle: Text(snap.data!.version), + ); + } else { + return Container(); + } + }, + ), + ListTile( + title: Text(context.lang.settingsHelpLicenses), + onTap: () => showLicensePage(context: context), + ), + ListTile( + title: Text(context.lang.settingsHelpCredits), + onTap: () => context.push(Routes.settingsHelpCredits), + ), + ListTile( + title: const Text('Changelog'), + onTap: () => context.push(Routes.settingsHelpChangelog), + ), + ListTile( + title: const Text('Open Source'), + onTap: () => launchUrl( + Uri.parse('https://github.com/twonlyapp/twonly-app'), + ), + trailing: const FaIcon( + FontAwesomeIcons.arrowUpRightFromSquare, + size: 15, + ), + ), + ListTile( + title: Text(context.lang.settingsHelpImprint), + onTap: () => + launchUrl(Uri.parse('https://twonly.eu/de/legal/')), + trailing: const FaIcon( + FontAwesomeIcons.arrowUpRightFromSquare, + size: 15, + ), + ), + ListTile( + title: Text(context.lang.settingsHelpTerms), + onTap: () => + launchUrl(Uri.parse('https://twonly.eu/de/legal/agb.html')), + trailing: const FaIcon( + FontAwesomeIcons.arrowUpRightFromSquare, + size: 15, + ), + ), + ListTile( + onLongPress: () async { + final okay = await showAlertDialog( + context, + 'Developer Settings', + 'Do you want to enable the developer settings?', + ); + if (okay) { + await updateUser((u) => u.isDeveloper = true); + } + }, + title: const Text( + 'Copyright twonly', + style: TextStyle(color: Colors.grey, fontSize: 13), + ), + ), + ], + ); + }, ), ); } diff --git a/lib/src/views/settings/privacy.view.dart b/lib/src/views/settings/privacy.view.dart index 89a92209..5bac16c5 100644 --- a/lib/src/views/settings/privacy.view.dart +++ b/lib/src/views/settings/privacy.view.dart @@ -20,22 +20,20 @@ class _PrivacyViewState extends State { Future toggleAuthRequirementOnStartup() async { final isAuth = await authenticateUser( - gUser.screenLockEnabled + AppSession.currentUser.screenLockEnabled ? context.lang.settingsScreenLockAuthMessageDisable : context.lang.settingsScreenLockAuthMessageEnable, ); if (!isAuth) return; - await updateUserdata((u) { + await updateUser((u) { u.screenLockEnabled = !u.screenLockEnabled; - return u; }); setState(() {}); } Future toggleTypingIndicators() async { - await updateUserdata((u) { + await updateUser((u) { u.typingIndicators = !u.typingIndicators; - return u; }); setState(() {}); } @@ -86,7 +84,7 @@ class _PrivacyViewState extends State { subtitle: Text(context.lang.settingsTypingIndicationSubtitle), onTap: toggleTypingIndicators, trailing: Switch( - value: gUser.typingIndicators, + value: AppSession.currentUser.typingIndicators, onChanged: (a) => toggleTypingIndicators(), ), ), @@ -96,7 +94,7 @@ class _PrivacyViewState extends State { subtitle: Text(context.lang.settingsScreenLockSubtitle), onTap: toggleAuthRequirementOnStartup, trailing: Switch( - value: gUser.screenLockEnabled, + value: AppSession.currentUser.screenLockEnabled, onChanged: (a) => toggleAuthRequirementOnStartup(), ), ), diff --git a/lib/src/views/settings/privacy/user_discovery.view.dart b/lib/src/views/settings/privacy/user_discovery.view.dart index 93f9323a..0d910063 100644 --- a/lib/src/views/settings/privacy/user_discovery.view.dart +++ b/lib/src/views/settings/privacy/user_discovery.view.dart @@ -18,9 +18,14 @@ class _UserDiscoverySettingsViewState extends State { appBar: AppBar( title: const Text('Freunde finden'), ), - body: gUser.isUserDiscoveryEnabled - ? UserDiscoveryEnabledComponent(onUpdate: () => setState(() {})) - : UserDiscoveryDisabledComponent(onUpdate: () => setState(() {})), + body: StreamBuilder( + stream: AppSession.onUserUpdated, + builder: (context, _) { + return AppSession.currentUser.isUserDiscoveryEnabled + ? const UserDiscoveryEnabledComponent() + : const UserDiscoveryDisabledComponent(); + }, + ), ); } } diff --git a/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart b/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart index 36c9ab87..21664ba5 100644 --- a/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart +++ b/lib/src/views/settings/privacy/user_discovery/user_discovery_disabled.component.dart @@ -4,9 +4,7 @@ import 'package:twonly/src/themes/light.dart'; import 'package:twonly/src/utils/misc.dart'; class UserDiscoveryDisabledComponent extends StatefulWidget { - const UserDiscoveryDisabledComponent({required this.onUpdate, super.key}); - - final VoidCallback onUpdate; + const UserDiscoveryDisabledComponent({super.key}); @override State createState() => @@ -20,7 +18,6 @@ class _UserDiscoveryDisabledComponentState threshold: 2, minimumRequiredImagesExchanged: 4, ); - widget.onUpdate(); } @override diff --git a/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart b/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart index 8acc3022..00ad46aa 100644 --- a/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart +++ b/lib/src/views/settings/privacy/user_discovery/user_discovery_enabled.component.dart @@ -15,9 +15,7 @@ import 'package:twonly/src/views/components/user_context_menu.component.dart'; import 'package:twonly/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart'; class UserDiscoveryEnabledComponent extends StatefulWidget { - const UserDiscoveryEnabledComponent({required this.onUpdate, super.key}); - - final VoidCallback onUpdate; + const UserDiscoveryEnabledComponent({super.key}); @override State createState() => @@ -69,9 +67,6 @@ class _UserDiscoveryEnabledComponentState if (ok) { await UserDiscoveryService.disable(); } - - // This will show the DisabledComponent as the gUser has been updated... - widget.onUpdate(); } @override @@ -119,7 +114,7 @@ class _UserDiscoveryEnabledComponentState ), subtitle: (version != null && - (gUser.isDeveloper || !kReleaseMode)) + (AppSession.currentUser.isDeveloper || !kReleaseMode)) ? Text( context.lang.userDiscoveryEnabledVersion( '${version.announcement}.${version.promotion}', @@ -171,7 +166,7 @@ class _UserDiscoveryEnabledComponentState title: Text(context.lang.userDiscoveryActionDisable), onTap: _disableUserDiscovery, ), - if (_version != null && (gUser.isDeveloper || !kReleaseMode)) + if (_version != null && (AppSession.currentUser.isDeveloper || !kReleaseMode)) ListTile( title: Text( context.lang.userDiscoveryEnabledYourVersion( diff --git a/lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart b/lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart index e0cf5c0c..9e306834 100644 --- a/lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart +++ b/lib/src/views/settings/privacy/user_discovery/user_discovery_settings.view.dart @@ -22,26 +22,28 @@ class _UserDiscoverySettingsViewState extends State { @override void initState() { - _minimumRequiredImagesExchanged = gUser.minimumRequiredImagesExchanged; - _userDiscoveryThreshold = gUser.userDiscoveryThreshold; + _minimumRequiredImagesExchanged = + AppSession.currentUser.minimumRequiredImagesExchanged; + _userDiscoveryThreshold = AppSession.currentUser.userDiscoveryThreshold; super.initState(); } Future _saveChanges() async { final requiresNewInitialization = - gUser.userDiscoveryThreshold != _userDiscoveryThreshold; + AppSession.currentUser.userDiscoveryThreshold != + _userDiscoveryThreshold; - await updateUserdata((u) { + await updateUser((u) { u ..minimumRequiredImagesExchanged = _minimumRequiredImagesExchanged ..userDiscoveryThreshold = _userDiscoveryThreshold; - return u; }); if (requiresNewInitialization) { await UserDiscoveryService.initializeOrUpdate( - threshold: gUser.userDiscoveryThreshold, - minimumRequiredImagesExchanged: gUser.minimumRequiredImagesExchanged, + threshold: AppSession.currentUser.userDiscoveryThreshold, + minimumRequiredImagesExchanged: + AppSession.currentUser.minimumRequiredImagesExchanged, ); } if (mounted) Navigator.pop(context); @@ -113,8 +115,9 @@ class _UserDiscoverySettingsViewState extends State { height: 30, ), if (_minimumRequiredImagesExchanged != - gUser.minimumRequiredImagesExchanged || - _userDiscoveryThreshold != gUser.userDiscoveryThreshold) + AppSession.currentUser.minimumRequiredImagesExchanged || + _userDiscoveryThreshold != + AppSession.currentUser.userDiscoveryThreshold) Padding( padding: const EdgeInsets.all(17), child: FilledButton( diff --git a/lib/src/views/settings/profile/modify_avatar.view.dart b/lib/src/views/settings/profile/modify_avatar.view.dart index 4fb0f946..c91ebbfd 100644 --- a/lib/src/views/settings/profile/modify_avatar.view.dart +++ b/lib/src/views/settings/profile/modify_avatar.view.dart @@ -23,13 +23,12 @@ class _ModifyAvatarViewState extends State { } Future updateUserAvatar(String json, String svg) async { - await updateUserdata((user) { - user + await updateUser( + (u) => u ..avatarJson = json ..avatarSvg = svg - ..avatarCounter = user.avatarCounter + 1; - return user; - }); + ..avatarCounter = u.avatarCounter + 1, + ); } AvatarMakerThemeData getAvatarMakerTheme(BuildContext context) { @@ -121,7 +120,8 @@ class _ModifyAvatarViewState extends State { canPop: false, onPopInvokedWithResult: (didPop, result) async { if (didPop) return; - if (_avatarMakerController.getJsonOptionsSync() != gUser.avatarJson) { + if (_avatarMakerController.getJsonOptionsSync() != + AppSession.currentUser.avatarJson) { // there where changes final shouldPop = await _showBackDialog() ?? false; if (context.mounted && shouldPop) { diff --git a/lib/src/views/settings/profile/profile.view.dart b/lib/src/views/settings/profile/profile.view.dart index fa743e29..6b9c05a3 100644 --- a/lib/src/views/settings/profile/profile.view.dart +++ b/lib/src/views/settings/profile/profile.view.dart @@ -47,13 +47,11 @@ class _ProfileViewState extends State { } Future updateUserDisplayName(String displayName) async { - await updateUserdata((user) { - user + await updateUser( + (u) => u ..displayName = displayName - ..avatarCounter = user.avatarCounter + 1; - return user; - }); - if (mounted) setState(() {}); // gUser has updated + ..avatarCounter = u.avatarCounter + 1, + ); } Future _updateUsername(String username) async { @@ -94,13 +92,11 @@ class _ProfileViewState extends State { await removeTwonlySafeFromServer(); unawaited(performTwonlySafeBackup(force: true)); - await updateUserdata((user) { - user + await updateUser( + (u) => u ..username = username - ..avatarCounter = user.avatarCounter + 1; - return user; - }); - setState(() {}); // gUser has updated + ..avatarCounter = u.avatarCounter + 1, + ); } @override @@ -109,99 +105,107 @@ class _ProfileViewState extends State { appBar: AppBar( title: Text(context.lang.settingsProfile), ), - body: ListView( - physics: const BouncingScrollPhysics(), - children: [ - const SizedBox(height: 25), - AvatarMakerAvatar( - backgroundColor: Colors.transparent, - radius: 80, - controller: _avatarMakerController, - ), - const SizedBox(height: 10), - Center( - child: SizedBox( - height: 35, - child: ElevatedButton.icon( - icon: const Icon(Icons.edit), - label: Text(context.lang.settingsProfileCustomizeAvatar), - onPressed: () async { - await context.push(Routes.settingsProfileModifyAvatar); - await _avatarMakerController.performRestore(); - setState(() {}); + body: StreamBuilder( + stream: AppSession.onUserUpdated, + builder: (context, _) { + return ListView( + physics: const BouncingScrollPhysics(), + children: [ + const SizedBox(height: 25), + AvatarMakerAvatar( + backgroundColor: Colors.transparent, + radius: 80, + controller: _avatarMakerController, + ), + const SizedBox(height: 10), + Center( + child: SizedBox( + height: 35, + child: ElevatedButton.icon( + icon: const Icon(Icons.edit), + label: Text(context.lang.settingsProfileCustomizeAvatar), + onPressed: () async { + await context.push(Routes.settingsProfileModifyAvatar); + await _avatarMakerController.performRestore(); + }, + ), + ), + ), + const SizedBox(height: 20), + const Divider(), + BetterListTile( + leading: const Padding( + padding: EdgeInsets.only(right: 5, left: 1), + child: FaIcon( + FontAwesomeIcons.qrcode, + size: 20, + ), + ), + onTap: () => context.push(Routes.settingsPublicProfile), + text: context.lang.profileYourQrCode, + ), + BetterListTile( + leading: const Padding( + padding: EdgeInsets.only(right: 5, left: 1), + child: FaIcon( + FontAwesomeIcons.at, + size: 20, + ), + ), + text: context.lang.registerUsernameDecoration, + subtitle: Text(AppSession.currentUser.username), + onTap: () async { + final username = await showDisplayNameChangeDialog( + context, + AppSession.currentUser.username, + context.lang.registerUsernameDecoration, + context.lang.registerUsernameDecoration, + maxLength: 12, + inputFormatters: [ + LengthLimitingTextInputFormatter(12), + FilteringTextInputFormatter.allow( + RegExp('[a-z0-9A-Z._]'), + ), + ], + ); + if (context.mounted && username != null && username != '') { + await _updateUsername(username); + } }, ), - ), - ), - const SizedBox(height: 20), - const Divider(), - BetterListTile( - leading: const Padding( - padding: EdgeInsets.only(right: 5, left: 1), - child: FaIcon( - FontAwesomeIcons.qrcode, - size: 20, + BetterListTile( + icon: FontAwesomeIcons.userPen, + text: context.lang.settingsProfileEditDisplayName, + subtitle: Text(AppSession.currentUser.displayName), + onTap: () async { + final displayName = await showDisplayNameChangeDialog( + context, + AppSession.currentUser.displayName, + context.lang.settingsProfileEditDisplayName, + context.lang.settingsProfileEditDisplayNameNew, + maxLength: 30, + ); + if (context.mounted && + displayName != null && + displayName != '') { + await updateUserDisplayName(displayName); + } + }, ), - ), - onTap: () => context.push(Routes.settingsPublicProfile), - text: context.lang.profileYourQrCode, - ), - BetterListTile( - leading: const Padding( - padding: EdgeInsets.only(right: 5, left: 1), - child: FaIcon( - FontAwesomeIcons.at, - size: 20, + BetterListTile( + text: context.lang.yourTwonlyScore, + icon: FontAwesomeIcons.trophy, + trailing: Text( + twonlyScore.toString(), + style: TextStyle( + color: context.color.primary, + fontSize: 18, + ), + ), ), - ), - text: context.lang.registerUsernameDecoration, - subtitle: Text(gUser.username), - onTap: () async { - final username = await showDisplayNameChangeDialog( - context, - gUser.username, - context.lang.registerUsernameDecoration, - context.lang.registerUsernameDecoration, - maxLength: 12, - inputFormatters: [ - LengthLimitingTextInputFormatter(12), - FilteringTextInputFormatter.allow(RegExp('[a-z0-9A-Z._]')), - ], - ); - if (context.mounted && username != null && username != '') { - await _updateUsername(username); - } - }, - ), - BetterListTile( - icon: FontAwesomeIcons.userPen, - text: context.lang.settingsProfileEditDisplayName, - subtitle: Text(gUser.displayName), - onTap: () async { - final displayName = await showDisplayNameChangeDialog( - context, - gUser.displayName, - context.lang.settingsProfileEditDisplayName, - context.lang.settingsProfileEditDisplayNameNew, - maxLength: 30, - ); - if (context.mounted && displayName != null && displayName != '') { - await updateUserDisplayName(displayName); - } - }, - ), - BetterListTile( - text: context.lang.yourTwonlyScore, - icon: FontAwesomeIcons.trophy, - trailing: Text( - twonlyScore.toString(), - style: TextStyle( - color: context.color.primary, - fontSize: 18, - ), - ), - ), - ], + ], + ); + }, ), ); } diff --git a/lib/src/views/settings/settings_main.view.dart b/lib/src/views/settings/settings_main.view.dart index 47a11a4f..b16c1e64 100644 --- a/lib/src/views/settings/settings_main.view.dart +++ b/lib/src/views/settings/settings_main.view.dart @@ -47,12 +47,12 @@ class _SettingsMainViewState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - substringBy(gUser.displayName, 27), + substringBy(AppSession.currentUser.displayName, 27), style: const TextStyle(fontSize: 20), textAlign: TextAlign.left, ), Text( - gUser.username, + AppSession.currentUser.username, style: const TextStyle( fontSize: 14, ), @@ -124,11 +124,11 @@ class _SettingsMainViewState extends State { onTap: () async { await context.push(Routes.settingsHelp); setState(() { - // gUser could have been changed + // AppSession.currentUser could have been changed }); }, ), - if (gUser.isDeveloper) + if (AppSession.currentUser.isDeveloper) BetterListTile( icon: FontAwesomeIcons.code, text: 'Developer Settings', diff --git a/lib/src/views/settings/subscription/subscription.view.dart b/lib/src/views/settings/subscription/subscription.view.dart index 12839923..da53fc85 100644 --- a/lib/src/views/settings/subscription/subscription.view.dart +++ b/lib/src/views/settings/subscription/subscription.view.dart @@ -290,7 +290,7 @@ class _PlanCardState extends State { var url = 'https://apps.apple.com/account/subscriptions'; if (Platform.isAndroid) { url = - 'https://play.google.com/store/account/subscriptions?sku=${gUser.subscriptionPlanIdStore}&package=eu.twonly'; + 'https://play.google.com/store/account/subscriptions?sku=${AppSession.currentUser.subscriptionPlanIdStore}&package=eu.twonly'; } await launchUrl( Uri.parse(url), diff --git a/lib/src/views/settings/subscription_custom/subscription.view.dart b/lib/src/views/settings/subscription_custom/subscription.view.dart index 4867d27c..062b22a0 100644 --- a/lib/src/views/settings/subscription_custom/subscription.view.dart +++ b/lib/src/views/settings/subscription_custom/subscription.view.dart @@ -39,10 +39,7 @@ String localePrizing(BuildContext context, int cents) { Future loadPlanBalance({bool useCache = true}) async { final ballance = await apiService.getPlanBallance(); if (ballance != null) { - await updateUserdata((u) { - u.lastPlanBallance = ballance.writeToJson(); - return u; - }); + await updateUser((u) => u.lastPlanBallance = ballance.writeToJson()); return ballance; } final user = await getUser(); diff --git a/lib/src/views/user_study/user_study_data_collection.dart b/lib/src/views/user_study/user_study_data_collection.dart index 1b576ee8..d5020d82 100644 --- a/lib/src/views/user_study/user_study_data_collection.dart +++ b/lib/src/views/user_study/user_study_data_collection.dart @@ -15,7 +15,7 @@ const surveyUrlBase = 'https://survey.twonly.org/upload.php'; Future handleUserStudyUpload() async { try { - final token = gUser.userStudyParticipantsToken; + final token = AppSession.currentUser.userStudyParticipantsToken; if (token == null) return; // in case the survey was taken offline try again @@ -35,8 +35,8 @@ Future handleUserStudyUpload() async { await KeyValueStore.delete(userStudySurveyKey); } - if (gUser.lastUserStudyDataUpload != null && - isToday(gUser.lastUserStudyDataUpload!)) { + if (AppSession.currentUser.lastUserStudyDataUpload != null && + isToday(AppSession.currentUser.lastUserStudyDataUpload!)) { // Only send updates once a day. // This enables to see if improvements to actually work. return; @@ -56,18 +56,16 @@ Future handleUserStudyUpload() async { headers: {'Content-Type': 'application/json'}, ); if (response.statusCode == 200) { - await updateUserdata((u) { + await updateUser((u) { u.lastUserStudyDataUpload = DateTime.now(); - return u; }); } if (response.statusCode == 404) { // Token is unknown to the server... - await updateUserdata((u) { + await updateUser((u) { u ..lastUserStudyDataUpload = null ..userStudyParticipantsToken = null; - return u; }); } } catch (e) { diff --git a/lib/src/views/user_study/user_study_questionnaire.view.dart b/lib/src/views/user_study/user_study_questionnaire.view.dart index 96cbc9dd..493331de 100644 --- a/lib/src/views/user_study/user_study_questionnaire.view.dart +++ b/lib/src/views/user_study/user_study_questionnaire.view.dart @@ -50,12 +50,11 @@ class _UserStudyQuestionnaireViewState Future _submitData() async { await KeyValueStore.put(userStudySurveyKey, _responses); - await updateUserdata((u) { + await updateUser((u) { // generate a random participants id to identify data send later while keeping the user anonym u ..userStudyParticipantsToken = getRandomString(25) ..askedForUserStudyPermission = true; - return u; }); await handleUserStudyUpload(); diff --git a/lib/src/views/user_study/user_study_welcome.view.dart b/lib/src/views/user_study/user_study_welcome.view.dart index 4598d013..9de6d907 100644 --- a/lib/src/views/user_study/user_study_welcome.view.dart +++ b/lib/src/views/user_study/user_study_welcome.view.dart @@ -86,10 +86,9 @@ class _UserStudyWelcomeViewState extends State { Center( child: GestureDetector( onTap: () async { - await updateUserdata((u) { - u.askedForUserStudyPermission = true; - return u; - }); + await updateUser( + (u) => u.askedForUserStudyPermission = true, + ); if (context.mounted) context.pop(); }, child: const Text( From 56aa6e9f7e369ed69a3dfb74f62a197f39e3bf6f Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 21 Apr 2026 03:34:52 +0200 Subject: [PATCH 27/86] rewrite global user variable --- lib/app.dart | 8 +- lib/globals.dart | 13 +- lib/src/providers/settings.provider.dart | 5 +- lib/src/views/public_profile.view.dart | 7 +- .../settings/chat/chat_reactions.view.dart | 123 +++++++++--------- 5 files changed, 71 insertions(+), 85 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index 4e4bb61b..b6f75f9f 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -176,12 +176,12 @@ class _AppMainWidgetState extends State { _isTwonlyLocked = false; }), ); - } else if (AppSession.currentUser.twonlySafeBackup == null && !_skipBackup) { + } else if (AppSession.currentUser.twonlySafeBackup == null && + !_skipBackup) { child = SetupBackupView( - callBack: () { + callBack: () => setState(() { _skipBackup = true; - setState(() {}); - }, + }), ); } else { child = HomeView( diff --git a/lib/globals.dart b/lib/globals.dart index c1a3c02b..e7708ea3 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -27,17 +27,9 @@ class AppState { } class AppGlobalKeys { - static final GlobalKey scaffoldMessengerKey = - GlobalKey(); + static final scaffoldMessengerKey = GlobalKey(); } -late ApiService apiService; - -// uses for background notification -late TwonlyDB twonlyDB; - -// Cached UserData in the memory. Every time the user data is changed the `updateUserdata` function is called, -// which will update this global variable. The variable is set in the main.dart and after the user has registered in the register.view.dart class AppSession { static late UserData currentUser; @@ -48,3 +40,6 @@ class AppSession { _userDataUpdateController.add(null); } } + +late ApiService apiService; +late TwonlyDB twonlyDB; diff --git a/lib/src/providers/settings.provider.dart b/lib/src/providers/settings.provider.dart index 840f2d66..d1b916dd 100644 --- a/lib/src/providers/settings.provider.dart +++ b/lib/src/providers/settings.provider.dart @@ -21,9 +21,6 @@ class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); - await updateUserdata((user) { - user.themeMode = newThemeMode; - return user; - }); + await updateUser((u) => u.themeMode = newThemeMode); } } diff --git a/lib/src/views/public_profile.view.dart b/lib/src/views/public_profile.view.dart index 091b672e..64b18477 100644 --- a/lib/src/views/public_profile.view.dart +++ b/lib/src/views/public_profile.view.dart @@ -34,8 +34,7 @@ class _PublicProfileViewState extends State { _qrCode = await getProfileQrCodeData(); _userAvatar = await getUserAvatar(); _publicKey = await getUserPublicKey(); - - setState(() {}); + if (mounted) setState(() {}); } @override @@ -126,7 +125,9 @@ class _PublicProfileViewState extends State { text: context.lang.shareYourProfile, subtitle: (_publicKey == null) ? null - : Text('https://me.twonly.eu/${AppSession.currentUser.username}'), + : Text( + 'https://me.twonly.eu/${AppSession.currentUser.username}', + ), onTap: () { final params = ShareParams( text: diff --git a/lib/src/views/settings/chat/chat_reactions.view.dart b/lib/src/views/settings/chat/chat_reactions.view.dart index a58778e9..171b7667 100644 --- a/lib/src/views/settings/chat/chat_reactions.view.dart +++ b/lib/src/views/settings/chat/chat_reactions.view.dart @@ -1,6 +1,5 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; +import 'package:twonly/globals.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/views/components/animate_icon.dart'; @@ -14,32 +13,30 @@ class ChatReactionSelectionView extends StatefulWidget { } class _ChatReactionSelectionView extends State { - List selectedEmojis = []; + List _selectedEmojis = []; + + List _emojisFromSession() { + final user = AppSession.currentUser; + if (user.preSelectedEmojies != null) { + return user.preSelectedEmojies!; + } + return EmojiAnimation.animatedIcons.keys.toList().sublist(0, 6); + } @override void initState() { super.initState(); - unawaited(initAsync()); - } - - Future initAsync() async { - final user = await getUser(); - if (user != null && user.preSelectedEmojies != null) { - selectedEmojis = user.preSelectedEmojies!; - } else { - selectedEmojis = EmojiAnimation.animatedIcons.keys.toList().sublist(0, 6); - } - setState(() {}); + _selectedEmojis = _emojisFromSession(); } Future _onEmojiSelected(String emoji) async { - if (selectedEmojis.contains(emoji)) { - selectedEmojis.remove(emoji); + if (_selectedEmojis.contains(emoji)) { + _selectedEmojis.remove(emoji); } else { - if (selectedEmojis.length < 12) { - selectedEmojis.add(emoji); + if (_selectedEmojis.length < 12) { + _selectedEmojis.add(emoji); await updateUser((user) { - user.preSelectedEmojies = selectedEmojis; + user.preSelectedEmojies = _selectedEmojis; }); } else { ScaffoldMessenger.of(context).showSnackBar( @@ -55,56 +52,52 @@ class _ChatReactionSelectionView extends State { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Select Reactions'), - ), - body: GridView.builder( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, // Number of columns - ), - itemCount: EmojiAnimation.animatedIcons.keys.length, - itemBuilder: (context, index) { - final emoji = EmojiAnimation.animatedIcons.keys.elementAt(index); - return GestureDetector( - onTap: () async { - await _onEmojiSelected(emoji); - }, - child: Card( - color: selectedEmojis.contains(emoji) - ? context.color.primary.withAlpha(150) - : context.color.surface, - child: Center( - child: SizedBox( - width: 40, - height: 40, - child: EmojiAnimation( - emoji: emoji, - // repeat: selectedEmojis.contains(emoji), + return StreamBuilder( + stream: AppSession.onUserUpdated, + builder: (context, _) { + _selectedEmojis = _emojisFromSession(); + return Scaffold( + appBar: AppBar( + title: const Text('Select Reactions'), + ), + body: GridView.builder( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + ), + itemCount: EmojiAnimation.animatedIcons.keys.length, + itemBuilder: (context, index) { + final emoji = EmojiAnimation.animatedIcons.keys.elementAt(index); + return GestureDetector( + onTap: () => _onEmojiSelected(emoji), + child: Card( + color: _selectedEmojis.contains(emoji) + ? context.color.primary.withAlpha(150) + : context.color.surface, + child: Center( + child: SizedBox( + width: 40, + height: 40, + child: EmojiAnimation(emoji: emoji), + ), ), ), + ); + }, + ), + floatingActionButton: Padding( + padding: const EdgeInsets.only(bottom: 30), + child: FloatingActionButton( + foregroundColor: Colors.white, + onPressed: () => updateUser( + (u) => u.preSelectedEmojies = EmojiAnimation.animatedIcons.keys + .toList() + .sublist(0, 6), ), + child: const Icon(Icons.settings_backup_restore_rounded), ), - ); - }, - ), - floatingActionButton: Padding( - padding: const EdgeInsets.only(bottom: 30), - child: FloatingActionButton( - foregroundColor: Colors.white, - onPressed: () async { - selectedEmojis = EmojiAnimation.animatedIcons.keys.toList().sublist( - 0, - 6, - ); - setState(() {}); - await updateUser((user) { - user.preSelectedEmojies = selectedEmojis; - }); - }, - child: const Icon(Icons.settings_backup_restore_rounded), - ), - ), + ), + ); + }, ); } } From ba2f9644c029fa3e90f0096f132c2e3f57ad4887 Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 21 Apr 2026 15:45:42 +0200 Subject: [PATCH 28/86] fix splash screen in light mode --- android/app/src/main/res/values/styles.xml | 2 + ios/Runner/Base.lproj/LaunchScreen.storyboard | 2 +- lib/core/bridge.dart | 30 ++-- lib/core/bridge/callbacks.dart | 5 +- lib/core/bridge/wrapper/user_discovery.dart | 5 +- lib/core/frb_generated.dart | 152 +++++++++--------- lib/core/frb_generated.io.dart | 20 ++- lib/core/frb_generated.web.dart | 13 +- lib/main.dart | 4 +- .../callback_dispatcher.background.dart | 7 +- lib/src/utils/log.dart | 36 ++--- rust/src/bridge/callbacks/macros.rs | 2 +- rust/src/frb_generated.rs | 10 +- 13 files changed, 142 insertions(+), 146 deletions(-) diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index cb1ef880..31dc1c5c 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -5,6 +5,8 @@ @drawable/launch_background + + #FF57CC99