diff --git a/CHANGELOG.md b/CHANGELOG.md
index a9d3887..5aae546 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
# Changelog
+## 0.0.89
+
+- Adds link preview to images
+- Adds option to manual focus in the camera
+- Adds support to switch between front and back cameras during video recording
+- Adds basic face filters
+- Improves image editor, like emojis or text under a drawing can be moved
+- Improves speed after taking a picture
+- Fixes issue with emojis disappearing in the image editor
+
## 0.0.86
- Allows to reopen send images (if send without time limit or enabled auth)
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index bc0b3a7..deed6bf 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -33,6 +33,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/filters/beard_upper_lip.webp b/assets/filters/beard_upper_lip.webp
new file mode 100644
index 0000000..058b2ed
Binary files /dev/null and b/assets/filters/beard_upper_lip.webp differ
diff --git a/assets/filters/dog_brown_ear.webp b/assets/filters/dog_brown_ear.webp
new file mode 100644
index 0000000..0dfec38
Binary files /dev/null and b/assets/filters/dog_brown_ear.webp differ
diff --git a/assets/filters/dog_brown_nose.webp b/assets/filters/dog_brown_nose.webp
new file mode 100644
index 0000000..7716995
Binary files /dev/null and b/assets/filters/dog_brown_nose.webp differ
diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift
index ab236bd..5ec1185 100644
--- a/ios/NotificationService/NotificationService.swift
+++ b/ios/NotificationService/NotificationService.swift
@@ -109,10 +109,10 @@ func getPushNotificationData(pushData: String) -> (
} else if pushUser != nil {
return (
pushUser!.displayName,
- getPushNotificationText(pushNotification: pushNotification).0, pushUser!.userID
+ getPushNotificationText(pushNotification: pushNotification, userKnown: true).0, pushUser!.userID
)
} else {
- let content = getPushNotificationText(pushNotification: pushNotification)
+ let content = getPushNotificationText(pushNotification: pushNotification, userKnown: false)
return (
content.1, content.0, 1
)
@@ -205,57 +205,77 @@ func readFromKeychain(key: String) -> String? {
return nil
}
-func getPushNotificationText(pushNotification: PushNotification) -> (String, String) {
+func getPushNotificationText(pushNotification: PushNotification, userKnown: Bool) -> (String, String) {
let systemLanguage = Locale.current.language.languageCode?.identifier ?? "en" // Get the current system language
var pushNotificationText: [PushKind: String] = [:]
- var title = "[Unknown]"
+ var title = "You"
+ var noTranslationFoundTitle = "You have a new message."
+ var noTranslationFoundBody = "Open twonly to learn more."
// Define the messages based on the system language
if systemLanguage.contains("de") { // German
- title = "[Unbekannt]"
- pushNotificationText = [
- .text: "hat eine Nachricht{inGroup} gesendet.",
- .twonly: "hat ein twonly{inGroup} gesendet.",
- .video: "hat ein Video{inGroup} gesendet.",
- .image: "hat ein Bild{inGroup} gesendet.",
- .audio: "hat eine Sprachnachricht{inGroup} gesendet.",
- .contactRequest: "möchte sich mit dir vernetzen.",
- .acceptRequest: "ist jetzt mit dir vernetzt.",
- .storedMediaFile: "hat dein Bild gespeichert.",
- .reaction: "hat auf dein Bild reagiert.",
- .testNotification: "Das ist eine Testbenachrichtigung.",
- .reopenedMedia: "hat dein Bild erneut geöffnet.",
- .reactionToVideo: "hat mit {{content}} auf dein Video reagiert.",
- .reactionToText: "hat mit {{content}} auf deinen Text reagiert.",
- .reactionToImage: "hat mit {{content}} auf dein Bild reagiert.",
- .reactionToAudio: "hat mit {{content}} auf deine Sprachnachricht reagiert.",
- .response: "hat dir{inGroup} geantwortet.",
- .addedToGroup: "hat dich zu \"{{content}}\" hinzugefügt.",
- ]
- } else { // Default to English
- pushNotificationText = [
- .text: "sent a message{inGroup}.",
- .twonly: "sent a twonly{inGroup}.",
- .video: "sent a video{inGroup}.",
- .image: "sent an image{inGroup}.",
- .audio: "sent a voice message{inGroup}.",
- .contactRequest: "wants to connect with you.",
- .acceptRequest: "is now connected with you.",
- .storedMediaFile: "has stored your image.",
- .reaction: "has reacted to your image.",
- .testNotification: "This is a test notification.",
- .reopenedMedia: "has reopened your image.",
- .reactionToVideo: "has reacted with {{content}} to your video.",
- .reactionToText: "has reacted with {{content}} to your text.",
- .reactionToImage: "has reacted with {{content}} to your image.",
- .reactionToAudio: "has reacted with {{content}} to your voice message.",
- .response: "has responded{inGroup}.",
- .addedToGroup: "has added you to \"{{content}}\"",
- ]
+ title = "Du"
+ noTranslationFoundTitle = "Du hast eine neue Nachricht."
+ noTranslationFoundBody = "Öffne twonly um mehr zu erfahren."
+ if (userKnown) {
+ pushNotificationText = [
+ .text: "hat eine Nachricht{inGroup} gesendet.",
+ .twonly: "hat ein twonly{inGroup} gesendet.",
+ .video: "hat ein Video{inGroup} gesendet.",
+ .image: "hat ein Bild{inGroup} gesendet.",
+ .audio: "hat eine Sprachnachricht{inGroup} gesendet.",
+ .contactRequest: "möchte sich mit dir vernetzen.",
+ .acceptRequest: "ist jetzt mit dir vernetzt.",
+ .storedMediaFile: "hat dein Bild gespeichert.",
+ .reaction: "hat auf dein Bild reagiert.",
+ .testNotification: "Das ist eine Testbenachrichtigung.",
+ .reopenedMedia: "hat dein Bild erneut geöffnet.",
+ .reactionToVideo: "hat mit {{content}} auf dein Video reagiert.",
+ .reactionToText: "hat mit {{content}} auf deinen Text reagiert.",
+ .reactionToImage: "hat mit {{content}} auf dein Bild reagiert.",
+ .reactionToAudio: "hat mit {{content}} auf deine Sprachnachricht reagiert.",
+ .response: "hat dir{inGroup} geantwortet.",
+ .addedToGroup: "hat dich zu \"{{content}}\" hinzugefügt.",
+ ]
+ } else {
+ pushNotificationText = [
+ .contactRequest: "hast eine neue Kontaktanfrage erhalten.",
+ ]
+ }
+ } else {
+ if (userKnown) {
+ pushNotificationText = [
+ .text: "sent a message{inGroup}.",
+ .twonly: "sent a twonly{inGroup}.",
+ .video: "sent a video{inGroup}.",
+ .image: "sent an image{inGroup}.",
+ .audio: "sent a voice message{inGroup}.",
+ .contactRequest: "wants to connect with you.",
+ .acceptRequest: "is now connected with you.",
+ .storedMediaFile: "has stored your image.",
+ .reaction: "has reacted to your image.",
+ .testNotification: "This is a test notification.",
+ .reopenedMedia: "has reopened your image.",
+ .reactionToVideo: "has reacted with {{content}} to your video.",
+ .reactionToText: "has reacted with {{content}} to your text.",
+ .reactionToImage: "has reacted with {{content}} to your image.",
+ .reactionToAudio: "has reacted with {{content}} to your voice message.",
+ .response: "has responded{inGroup}.",
+ .addedToGroup: "has added you to \"{{content}}\"",
+ ]
+ } else {
+ pushNotificationText = [
+ .contactRequest: "have received a new contact request.",
+ ]
+ }
}
var content = pushNotificationText[pushNotification.kind] ?? ""
+ if (content == "") {
+ title = noTranslationFoundTitle
+ content = noTranslationFoundBody
+ }
if pushNotification.hasAdditionalContent {
content.replace("{{content}}", with: pushNotification.additionalContent)
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 301b4b9..b0cfa92 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -136,6 +136,10 @@ PODS:
- google_mlkit_commons (0.11.0):
- Flutter
- MLKitVision
+ - google_mlkit_face_detection (0.13.1):
+ - Flutter
+ - google_mlkit_commons
+ - GoogleMLKit/FaceDetection (~> 7.0.0)
- GoogleAdsOnDeviceConversion (3.2.0):
- GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/Logger (~> 8.1)
@@ -169,6 +173,9 @@ PODS:
- GoogleMLKit/BarcodeScanning (7.0.0):
- GoogleMLKit/MLKitCore
- MLKitBarcodeScanning (~> 6.0.0)
+ - GoogleMLKit/FaceDetection (7.0.0):
+ - GoogleMLKit/MLKitCore
+ - MLKitFaceDetection (~> 6.0.0)
- GoogleMLKit/MLKitCore (7.0.0):
- MLKitCommon (~> 12.0.0)
- GoogleToolboxForMac/Defines (4.2.1)
@@ -251,6 +258,9 @@ PODS:
- GoogleUtilities/Logger (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
+ - MLKitFaceDetection (6.0.0):
+ - MLKitCommon (~> 12.0)
+ - MLKitVision (~> 8.0)
- MLKitVision (8.0.0):
- GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
- "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
@@ -357,6 +367,7 @@ DEPENDENCIES:
- gal (from `.symlinks/plugins/gal/darwin`)
- google_mlkit_barcode_scanning (from `.symlinks/plugins/google_mlkit_barcode_scanning/ios`)
- google_mlkit_commons (from `.symlinks/plugins/google_mlkit_commons/ios`)
+ - google_mlkit_face_detection (from `.symlinks/plugins/google_mlkit_face_detection/ios`)
- GoogleUtilities
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`)
@@ -398,6 +409,7 @@ SPEC REPOS:
- MLImage
- MLKitBarcodeScanning
- MLKitCommon
+ - MLKitFaceDetection
- MLKitVision
- nanopb
- PromisesObjC
@@ -454,6 +466,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/google_mlkit_barcode_scanning/ios"
google_mlkit_commons:
:path: ".symlinks/plugins/google_mlkit_commons/ios"
+ google_mlkit_face_detection:
+ :path: ".symlinks/plugins/google_mlkit_face_detection/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
in_app_purchase_storekit:
@@ -518,6 +532,7 @@ SPEC CHECKSUMS:
gal: baecd024ebfd13c441269ca7404792a7152fde89
google_mlkit_barcode_scanning: 8f5987f244a43fe1167689c548342a5174108159
google_mlkit_commons: 2abe6a70e1824e431d16a51085cb475b672c8aab
+ google_mlkit_face_detection: 754da2113a1952f063c7c5dc347ac6ae8934fb77
GoogleAdsOnDeviceConversion: d68c69dd9581a0f5da02617b6f377e5be483970f
GoogleAppMeasurement: 3bf40aff49a601af5da1c3345702fcb4991d35ee
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
@@ -533,6 +548,7 @@ SPEC CHECKSUMS:
MLImage: 0ad1c5f50edd027672d8b26b0fee78a8b4a0fc56
MLKitBarcodeScanning: 0a3064da0a7f49ac24ceb3cb46a5bc67496facd2
MLKitCommon: 07c2c33ae5640e5380beaaa6e4b9c249a205542d
+ MLKitFaceDetection: 2a593db4837db503ad3426b565e7aab045cefea5
MLKitVision: 45e79d68845a2de77e2dd4d7f07947f0ed157b0e
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
no_screenshot: 89e778ede9f1e39cc3fb9404d782a42712f2a0b2
diff --git a/ios/ShareExtension/Info.plist b/ios/ShareExtension/Info.plist
index 3e8521b..5edbc20 100644
--- a/ios/ShareExtension/Info.plist
+++ b/ios/ShareExtension/Info.plist
@@ -22,6 +22,8 @@
NSExtensionActivationRule
+ NSExtensionActivationSupportsWebURLWithMaxCount
+ 1
NSExtensionActivationSupportsWebURLWithMaxCount
1
NSExtensionActivationSupportsImageWithMaxCount
diff --git a/lib/src/database/daos/reactions.dao.dart b/lib/src/database/daos/reactions.dao.dart
index 59ef34a..286fc68 100644
--- a/lib/src/database/daos/reactions.dao.dart
+++ b/lib/src/database/daos/reactions.dao.dart
@@ -22,7 +22,7 @@ class ReactionsDao extends DatabaseAccessor with _$ReactionsDaoMixin {
String emoji,
bool remove,
) async {
- if (!isEmoji(emoji)) {
+ if (!isOneEmoji(emoji)) {
Log.error('Did not update reaction as it is not an emoji!');
return;
}
@@ -59,7 +59,7 @@ class ReactionsDao extends DatabaseAccessor with _$ReactionsDaoMixin {
String emoji,
bool remove,
) async {
- if (!isEmoji(emoji)) {
+ if (!isOneEmoji(emoji)) {
Log.error('Did not update reaction as it is not an emoji!');
return;
}
diff --git a/lib/src/database/schemas/twonly_db/drift_schema_v7.json b/lib/src/database/schemas/twonly_db/drift_schema_v7.json
new file mode 100644
index 0000000..f77953a
--- /dev/null
+++ b/lib/src/database/schemas/twonly_db/drift_schema_v7.json
@@ -0,0 +1 @@
+{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":false},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"contacts","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"username","getter_name":"username","moor_type":"string","nullable":false,"customConstraints":null,"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":[]}],"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":"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":[],"type_converter":{"dart_expr":"const EnumNameConverter(MessageType.values)","dart_type_name":"MessageType"}},{"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],"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,"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":"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":["id"]}},{"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_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":"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":[0],"type":"table","data":{"name":"signal_contact_pre_keys","was_declared_in_moor":false,"columns":[{"name":"contact_id","getter_name":"contactId","moor_type":"int","nullable":false,"customConstraints":null,"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":"pre_key_id","getter_name":"preKeyId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"pre_key","getter_name":"preKey","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[],"explicit_pk":["contact_id","pre_key_id"]}},{"id":14,"references":[0],"type":"table","data":{"name":"signal_contact_signed_pre_keys","was_declared_in_moor":false,"columns":[{"name":"contact_id","getter_name":"contactId","moor_type":"int","nullable":false,"customConstraints":null,"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":"signed_pre_key_id","getter_name":"signedPreKeyId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"signed_pre_key","getter_name":"signedPreKey","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"signed_pre_key_signature","getter_name":"signedPreKeySignature","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[],"explicit_pk":["contact_id"]}},{"id":15,"references":[3],"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,"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(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":16,"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"]}}]}
\ No newline at end of file
diff --git a/lib/src/database/tables/messages.table.dart b/lib/src/database/tables/messages.table.dart
index 6739432..89e2975 100644
--- a/lib/src/database/tables/messages.table.dart
+++ b/lib/src/database/tables/messages.table.dart
@@ -22,6 +22,8 @@ class Messages extends Table {
.nullable()
.references(MediaFiles, #mediaId, onDelete: KeyAction.setNull)();
+ BlobColumn get additionalMessageData => blob().nullable()();
+
BoolColumn get mediaStored => boolean().withDefault(const Constant(false))();
BoolColumn get mediaReopened =>
boolean().withDefault(const Constant(false))();
@@ -56,7 +58,7 @@ class MessageActions extends Table {
text().references(Messages, #messageId, onDelete: KeyAction.cascade)();
IntColumn get contactId =>
- integer().references(Contacts, #contactId, onDelete: KeyAction.cascade)();
+ integer().references(Contacts, #userId, onDelete: KeyAction.cascade)();
TextColumn get type => textEnum()();
@@ -75,7 +77,7 @@ class MessageHistories extends Table {
IntColumn get contactId => integer()
.nullable()
- .references(Contacts, #contactId, onDelete: KeyAction.cascade)();
+ .references(Contacts, #userId, onDelete: KeyAction.cascade)();
TextColumn get content => text().nullable()();
diff --git a/lib/src/database/twonly.db.dart b/lib/src/database/twonly.db.dart
index 3cace23..07ec778 100644
--- a/lib/src/database/twonly.db.dart
+++ b/lib/src/database/twonly.db.dart
@@ -68,7 +68,7 @@ class TwonlyDB extends _$TwonlyDB {
TwonlyDB.forTesting(DatabaseConnection super.connection);
@override
- int get schemaVersion => 6;
+ int get schemaVersion => 7;
static QueryExecutor _openConnection() {
return driftDatabase(
@@ -85,39 +85,49 @@ class TwonlyDB extends _$TwonlyDB {
beforeOpen: (details) async {
await customStatement('PRAGMA foreign_keys = ON');
},
- onUpgrade: stepByStep(
- from1To2: (m, schema) async {
- await m.addColumn(schema.messages, schema.messages.mediaReopened);
- await m.dropColumn(schema.mediaFiles, 'reopen_by_contact');
- },
- from2To3: (m, schema) async {
- await m.addColumn(schema.groups, schema.groups.draftMessage);
- },
- from3To4: (m, schema) async {
- await m.alterTable(
- TableMigration(
- schema.groupHistories,
- columnTransformer: {
- schema.groupHistories.affectedContactId:
- schema.groupHistories.affectedContactId,
- },
- ),
- );
- },
- from4To5: (m, schema) async {
- await m.addColumn(schema.receipts, schema.receipts.markForRetry);
- await m.addColumn(
- schema.mediaFiles,
- schema.mediaFiles.storedFileHash,
- );
- },
- from5To6: (m, schema) async {
- await m.addColumn(
- schema.receipts,
- schema.receipts.markForRetryAfterAccepted,
- );
- },
- ),
+ onUpgrade: (m, from, to) async {
+ // disable foreign_keys before migrations
+ await customStatement('PRAGMA foreign_keys = OFF');
+ return stepByStep(
+ from1To2: (m, schema) async {
+ await m.addColumn(schema.messages, schema.messages.mediaReopened);
+ await m.dropColumn(schema.mediaFiles, 'reopen_by_contact');
+ },
+ from2To3: (m, schema) async {
+ await m.addColumn(schema.groups, schema.groups.draftMessage);
+ },
+ from3To4: (m, schema) async {
+ await m.alterTable(
+ TableMigration(
+ schema.groupHistories,
+ columnTransformer: {
+ schema.groupHistories.affectedContactId:
+ schema.groupHistories.affectedContactId,
+ },
+ ),
+ );
+ },
+ from4To5: (m, schema) async {
+ await m.addColumn(schema.receipts, schema.receipts.markForRetry);
+ await m.addColumn(
+ schema.mediaFiles,
+ schema.mediaFiles.storedFileHash,
+ );
+ },
+ from5To6: (m, schema) async {
+ await m.addColumn(
+ schema.receipts,
+ schema.receipts.markForRetryAfterAccepted,
+ );
+ },
+ from6To7: (m, schema) async {
+ await m.addColumn(
+ schema.messages,
+ schema.messages.additionalMessageData,
+ );
+ },
+ )(m, from, to);
+ },
);
}
diff --git a/lib/src/database/twonly.db.g.dart b/lib/src/database/twonly.db.g.dart
index 0ae2daf..bad66a1 100644
--- a/lib/src/database/twonly.db.g.dart
+++ b/lib/src/database/twonly.db.g.dart
@@ -2796,6 +2796,12 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
requiredDuringInsert: false,
defaultConstraints: GeneratedColumn.constraintIsAlways(
'REFERENCES media_files (media_id) ON DELETE SET NULL'));
+ static const VerificationMeta _additionalMessageDataMeta =
+ const VerificationMeta('additionalMessageData');
+ @override
+ late final GeneratedColumn additionalMessageData =
+ GeneratedColumn('additional_message_data', aliasedName, true,
+ type: DriftSqlType.blob, requiredDuringInsert: false);
static const VerificationMeta _mediaStoredMeta =
const VerificationMeta('mediaStored');
@override
@@ -2884,6 +2890,7 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
type,
content,
mediaId,
+ additionalMessageData,
mediaStored,
mediaReopened,
downloadToken,
@@ -2930,6 +2937,12 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
context.handle(_mediaIdMeta,
mediaId.isAcceptableOrUnknown(data['media_id']!, _mediaIdMeta));
}
+ if (data.containsKey('additional_message_data')) {
+ context.handle(
+ _additionalMessageDataMeta,
+ additionalMessageData.isAcceptableOrUnknown(
+ data['additional_message_data']!, _additionalMessageDataMeta));
+ }
if (data.containsKey('media_stored')) {
context.handle(
_mediaStoredMeta,
@@ -3013,6 +3026,8 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
.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.bool, data['${effectivePrefix}media_stored'])!,
mediaReopened: attachedDatabase.typeMapping
@@ -3054,6 +3069,7 @@ class Message extends DataClass implements Insertable {
final MessageType type;
final String? content;
final String? mediaId;
+ final Uint8List? additionalMessageData;
final bool mediaStored;
final bool mediaReopened;
final Uint8List? downloadToken;
@@ -3072,6 +3088,7 @@ class Message extends DataClass implements Insertable {
required this.type,
this.content,
this.mediaId,
+ this.additionalMessageData,
required this.mediaStored,
required this.mediaReopened,
this.downloadToken,
@@ -3100,6 +3117,10 @@ class Message extends DataClass implements Insertable {
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) {
@@ -3142,6 +3163,9 @@ class Message extends DataClass implements Insertable {
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
@@ -3181,6 +3205,8 @@ class Message extends DataClass implements Insertable {
.fromJson(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']),
@@ -3206,6 +3232,8 @@ class Message extends DataClass implements Insertable {
serializer.toJson($MessagesTable.$convertertype.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),
@@ -3227,6 +3255,7 @@ class Message extends DataClass implements Insertable {
MessageType? type,
Value content = const Value.absent(),
Value mediaId = const Value.absent(),
+ Value additionalMessageData = const Value.absent(),
bool? mediaStored,
bool? mediaReopened,
Value downloadToken = const Value.absent(),
@@ -3245,6 +3274,9 @@ class Message extends DataClass implements Insertable {
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:
@@ -3268,6 +3300,9 @@ class Message extends DataClass implements Insertable {
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
@@ -3303,6 +3338,7 @@ class Message extends DataClass implements Insertable {
..write('type: $type, ')
..write('content: $content, ')
..write('mediaId: $mediaId, ')
+ ..write('additionalMessageData: $additionalMessageData, ')
..write('mediaStored: $mediaStored, ')
..write('mediaReopened: $mediaReopened, ')
..write('downloadToken: $downloadToken, ')
@@ -3326,6 +3362,7 @@ class Message extends DataClass implements Insertable {
type,
content,
mediaId,
+ $driftBlobEquality.hash(additionalMessageData),
mediaStored,
mediaReopened,
$driftBlobEquality.hash(downloadToken),
@@ -3347,6 +3384,8 @@ class Message extends DataClass implements Insertable {
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) &&
@@ -3367,6 +3406,7 @@ class MessagesCompanion extends UpdateCompanion {
final Value type;
final Value content;
final Value mediaId;
+ final Value additionalMessageData;
final Value mediaStored;
final Value mediaReopened;
final Value downloadToken;
@@ -3386,6 +3426,7 @@ class MessagesCompanion extends UpdateCompanion {
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(),
@@ -3406,6 +3447,7 @@ class MessagesCompanion extends UpdateCompanion {
required MessageType 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(),
@@ -3428,6 +3470,7 @@ class MessagesCompanion extends UpdateCompanion {
Expression? type,
Expression? content,
Expression? mediaId,
+ Expression? additionalMessageData,
Expression? mediaStored,
Expression? mediaReopened,
Expression? downloadToken,
@@ -3448,6 +3491,8 @@ class MessagesCompanion extends UpdateCompanion {
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,
@@ -3471,6 +3516,7 @@ class MessagesCompanion extends UpdateCompanion {
Value? type,
Value? content,
Value? mediaId,
+ Value? additionalMessageData,
Value? mediaStored,
Value? mediaReopened,
Value? downloadToken,
@@ -3490,6 +3536,8 @@ class MessagesCompanion extends UpdateCompanion {
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,
@@ -3527,6 +3575,10 @@ class MessagesCompanion extends UpdateCompanion {
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);
}
@@ -3575,6 +3627,7 @@ class MessagesCompanion extends UpdateCompanion {
..write('type: $type, ')
..write('content: $content, ')
..write('mediaId: $mediaId, ')
+ ..write('additionalMessageData: $additionalMessageData, ')
..write('mediaStored: $mediaStored, ')
..write('mediaReopened: $mediaReopened, ')
..write('downloadToken: $downloadToken, ')
@@ -3621,7 +3674,10 @@ class $MessageHistoriesTable extends MessageHistories
@override
late final GeneratedColumn contactId = GeneratedColumn(
'contact_id', aliasedName, true,
- type: DriftSqlType.int, requiredDuringInsert: false);
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ defaultConstraints: GeneratedColumn.constraintIsAlways(
+ 'REFERENCES contacts (user_id) ON DELETE CASCADE'));
static const VerificationMeta _contentMeta =
const VerificationMeta('content');
@override
@@ -6964,7 +7020,10 @@ class $MessageActionsTable extends MessageActions
@override
late final GeneratedColumn contactId = GeneratedColumn(
'contact_id', aliasedName, false,
- type: DriftSqlType.int, requiredDuringInsert: true);
+ type: DriftSqlType.int,
+ requiredDuringInsert: true,
+ defaultConstraints: GeneratedColumn.constraintIsAlways(
+ 'REFERENCES contacts (user_id) ON DELETE CASCADE'));
@override
late final GeneratedColumnWithTypeConverter type =
GeneratedColumn('type', aliasedName, false,
@@ -7837,6 +7896,13 @@ abstract class _$TwonlyDB extends GeneratedDatabase {
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),
@@ -7894,6 +7960,13 @@ abstract class _$TwonlyDB extends GeneratedDatabase {
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),
@@ -7955,6 +8028,23 @@ final class $$ContactsTableReferences
manager.$state.copyWith(prefetchedData: cache));
}
+ static MultiTypedResultKey<$MessageHistoriesTable, List>
+ _messageHistoriesRefsTable(_$TwonlyDB db) =>
+ MultiTypedResultKey.fromTable(db.messageHistories,
+ aliasName: $_aliasNameGenerator(
+ db.contacts.userId, db.messageHistories.contactId));
+
+ $$MessageHistoriesTableProcessedTableManager get messageHistoriesRefs {
+ final manager =
+ $$MessageHistoriesTableTableManager($_db, $_db.messageHistories).filter(
+ (f) => f.contactId.userId.sqlEquals($_itemColumn('user_id')!));
+
+ final cache =
+ $_typedResult.readTableOrNull(_messageHistoriesRefsTable($_db));
+ return ProcessedTableManager(
+ manager.$state.copyWith(prefetchedData: cache));
+ }
+
static MultiTypedResultKey<$ReactionsTable, List>
_reactionsRefsTable(_$TwonlyDB db) => MultiTypedResultKey.fromTable(
db.reactions,
@@ -8041,6 +8131,22 @@ final class $$ContactsTableReferences
manager.$state.copyWith(prefetchedData: cache));
}
+ static MultiTypedResultKey<$MessageActionsTable, List>
+ _messageActionsRefsTable(_$TwonlyDB db) =>
+ MultiTypedResultKey.fromTable(db.messageActions,
+ aliasName: $_aliasNameGenerator(
+ db.contacts.userId, db.messageActions.contactId));
+
+ $$MessageActionsTableProcessedTableManager get messageActionsRefs {
+ final manager = $$MessageActionsTableTableManager($_db, $_db.messageActions)
+ .filter(
+ (f) => f.contactId.userId.sqlEquals($_itemColumn('user_id')!));
+
+ final cache = $_typedResult.readTableOrNull(_messageActionsRefsTable($_db));
+ return ProcessedTableManager(
+ manager.$state.copyWith(prefetchedData: cache));
+ }
+
static MultiTypedResultKey<$GroupHistoriesTable, List>
_groupHistoriesRefsTable(_$TwonlyDB db) =>
MultiTypedResultKey.fromTable(db.groupHistories,
@@ -8130,6 +8236,27 @@ class $$ContactsTableFilterComposer
return f(composer);
}
+ Expression messageHistoriesRefs(
+ Expression Function($$MessageHistoriesTableFilterComposer f) f) {
+ final $$MessageHistoriesTableFilterComposer composer = $composerBuilder(
+ composer: this,
+ getCurrentColumn: (t) => t.userId,
+ referencedTable: $db.messageHistories,
+ getReferencedColumn: (t) => t.contactId,
+ builder: (joinBuilder,
+ {$addJoinBuilderToRootComposer,
+ $removeJoinBuilderFromRootComposer}) =>
+ $$MessageHistoriesTableFilterComposer(
+ $db: $db,
+ $table: $db.messageHistories,
+ $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
+ joinBuilder: joinBuilder,
+ $removeJoinBuilderFromRootComposer:
+ $removeJoinBuilderFromRootComposer,
+ ));
+ return f(composer);
+ }
+
Expression reactionsRefs(
Expression Function($$ReactionsTableFilterComposer f) f) {
final $$ReactionsTableFilterComposer composer = $composerBuilder(
@@ -8239,6 +8366,27 @@ class $$ContactsTableFilterComposer
return f(composer);
}
+ Expression messageActionsRefs(
+ Expression Function($$MessageActionsTableFilterComposer f) f) {
+ final $$MessageActionsTableFilterComposer composer = $composerBuilder(
+ composer: this,
+ getCurrentColumn: (t) => t.userId,
+ referencedTable: $db.messageActions,
+ getReferencedColumn: (t) => t.contactId,
+ builder: (joinBuilder,
+ {$addJoinBuilderToRootComposer,
+ $removeJoinBuilderFromRootComposer}) =>
+ $$MessageActionsTableFilterComposer(
+ $db: $db,
+ $table: $db.messageActions,
+ $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
+ joinBuilder: joinBuilder,
+ $removeJoinBuilderFromRootComposer:
+ $removeJoinBuilderFromRootComposer,
+ ));
+ return f(composer);
+ }
+
Expression groupHistoriesRefs(
Expression Function($$GroupHistoriesTableFilterComposer f) f) {
final $$GroupHistoriesTableFilterComposer composer = $composerBuilder(
@@ -8383,6 +8531,27 @@ class $$ContactsTableAnnotationComposer
return f(composer);
}
+ Expression messageHistoriesRefs(
+ Expression Function($$MessageHistoriesTableAnnotationComposer a) f) {
+ final $$MessageHistoriesTableAnnotationComposer composer = $composerBuilder(
+ composer: this,
+ getCurrentColumn: (t) => t.userId,
+ referencedTable: $db.messageHistories,
+ getReferencedColumn: (t) => t.contactId,
+ builder: (joinBuilder,
+ {$addJoinBuilderToRootComposer,
+ $removeJoinBuilderFromRootComposer}) =>
+ $$MessageHistoriesTableAnnotationComposer(
+ $db: $db,
+ $table: $db.messageHistories,
+ $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
+ joinBuilder: joinBuilder,
+ $removeJoinBuilderFromRootComposer:
+ $removeJoinBuilderFromRootComposer,
+ ));
+ return f(composer);
+ }
+
Expression reactionsRefs(
Expression Function($$ReactionsTableAnnotationComposer a) f) {
final $$ReactionsTableAnnotationComposer composer = $composerBuilder(
@@ -8493,6 +8662,27 @@ class $$ContactsTableAnnotationComposer
return f(composer);
}
+ Expression messageActionsRefs(
+ Expression Function($$MessageActionsTableAnnotationComposer a) f) {
+ final $$MessageActionsTableAnnotationComposer composer = $composerBuilder(
+ composer: this,
+ getCurrentColumn: (t) => t.userId,
+ referencedTable: $db.messageActions,
+ getReferencedColumn: (t) => t.contactId,
+ builder: (joinBuilder,
+ {$addJoinBuilderToRootComposer,
+ $removeJoinBuilderFromRootComposer}) =>
+ $$MessageActionsTableAnnotationComposer(
+ $db: $db,
+ $table: $db.messageActions,
+ $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
+ joinBuilder: joinBuilder,
+ $removeJoinBuilderFromRootComposer:
+ $removeJoinBuilderFromRootComposer,
+ ));
+ return f(composer);
+ }
+
Expression groupHistoriesRefs(
Expression Function($$GroupHistoriesTableAnnotationComposer a) f) {
final $$GroupHistoriesTableAnnotationComposer composer = $composerBuilder(
@@ -8528,11 +8718,13 @@ class $$ContactsTableTableManager extends RootTableManager<
Contact,
PrefetchHooks Function(
{bool messagesRefs,
+ bool messageHistoriesRefs,
bool reactionsRefs,
bool groupMembersRefs,
bool receiptsRefs,
bool signalContactPreKeysRefs,
bool signalContactSignedPreKeysRefs,
+ bool messageActionsRefs,
bool groupHistoriesRefs})> {
$$ContactsTableTableManager(_$TwonlyDB db, $ContactsTable table)
: super(TableManagerState(
@@ -8610,22 +8802,26 @@ class $$ContactsTableTableManager extends RootTableManager<
.toList(),
prefetchHooksCallback: (
{messagesRefs = false,
+ messageHistoriesRefs = false,
reactionsRefs = false,
groupMembersRefs = false,
receiptsRefs = false,
signalContactPreKeysRefs = false,
signalContactSignedPreKeysRefs = false,
+ messageActionsRefs = false,
groupHistoriesRefs = false}) {
return PrefetchHooks(
db: db,
explicitlyWatchedTables: [
if (messagesRefs) db.messages,
+ if (messageHistoriesRefs) db.messageHistories,
if (reactionsRefs) db.reactions,
if (groupMembersRefs) db.groupMembers,
if (receiptsRefs) db.receipts,
if (signalContactPreKeysRefs) db.signalContactPreKeys,
if (signalContactSignedPreKeysRefs)
db.signalContactSignedPreKeys,
+ if (messageActionsRefs) db.messageActions,
if (groupHistoriesRefs) db.groupHistories
],
addJoins: null,
@@ -8643,6 +8839,19 @@ class $$ContactsTableTableManager extends RootTableManager<
(item, referencedItems) => referencedItems
.where((e) => e.senderId == item.userId),
typedResults: items),
+ if (messageHistoriesRefs)
+ await $_getPrefetchedData(
+ currentTable: table,
+ referencedTable: $$ContactsTableReferences
+ ._messageHistoriesRefsTable(db),
+ managerFromTypedResult: (p0) =>
+ $$ContactsTableReferences(db, table, p0)
+ .messageHistoriesRefs,
+ referencedItemsForCurrentItem:
+ (item, referencedItems) => referencedItems
+ .where((e) => e.contactId == item.userId),
+ typedResults: items),
if (reactionsRefs)
await $_getPrefetchedData(
@@ -8707,6 +8916,19 @@ class $$ContactsTableTableManager extends RootTableManager<
(item, referencedItems) => referencedItems
.where((e) => e.contactId == item.userId),
typedResults: items),
+ if (messageActionsRefs)
+ await $_getPrefetchedData(
+ currentTable: table,
+ referencedTable: $$ContactsTableReferences
+ ._messageActionsRefsTable(db),
+ managerFromTypedResult: (p0) =>
+ $$ContactsTableReferences(db, table, p0)
+ .messageActionsRefs,
+ referencedItemsForCurrentItem:
+ (item, referencedItems) => referencedItems
+ .where((e) => e.contactId == item.userId),
+ typedResults: items),
if (groupHistoriesRefs)
await $_getPrefetchedData(
@@ -8740,11 +8962,13 @@ typedef $$ContactsTableProcessedTableManager = ProcessedTableManager<
Contact,
PrefetchHooks Function(
{bool messagesRefs,
+ bool messageHistoriesRefs,
bool reactionsRefs,
bool groupMembersRefs,
bool receiptsRefs,
bool signalContactPreKeysRefs,
bool signalContactSignedPreKeysRefs,
+ bool messageActionsRefs,
bool groupHistoriesRefs})>;
typedef $$GroupsTableCreateCompanionBuilder = GroupsCompanion Function({
required String groupId,
@@ -9927,6 +10151,7 @@ typedef $$MessagesTableCreateCompanionBuilder = MessagesCompanion Function({
required MessageType type,
Value content,
Value mediaId,
+ Value additionalMessageData,
Value mediaStored,
Value mediaReopened,
Value downloadToken,
@@ -9947,6 +10172,7 @@ typedef $$MessagesTableUpdateCompanionBuilder = MessagesCompanion Function({
Value type,
Value content,
Value mediaId,
+ Value additionalMessageData,
Value mediaStored,
Value mediaReopened,
Value downloadToken,
@@ -10096,6 +10322,10 @@ class $$MessagesTableFilterComposer
ColumnFilters get content => $composableBuilder(
column: $table.content, builder: (column) => ColumnFilters(column));
+ ColumnFilters get additionalMessageData => $composableBuilder(
+ column: $table.additionalMessageData,
+ builder: (column) => ColumnFilters(column));
+
ColumnFilters get mediaStored => $composableBuilder(
column: $table.mediaStored, builder: (column) => ColumnFilters(column));
@@ -10294,6 +10524,10 @@ class $$MessagesTableOrderingComposer
ColumnOrderings get content => $composableBuilder(
column: $table.content, builder: (column) => ColumnOrderings(column));
+ ColumnOrderings get additionalMessageData => $composableBuilder(
+ column: $table.additionalMessageData,
+ builder: (column) => ColumnOrderings(column));
+
ColumnOrderings get mediaStored => $composableBuilder(
column: $table.mediaStored, builder: (column) => ColumnOrderings(column));
@@ -10410,6 +10644,9 @@ class $$MessagesTableAnnotationComposer
GeneratedColumn get content =>
$composableBuilder(column: $table.content, builder: (column) => column);
+ GeneratedColumn get additionalMessageData => $composableBuilder(
+ column: $table.additionalMessageData, builder: (column) => column);
+
GeneratedColumn get mediaStored => $composableBuilder(
column: $table.mediaStored, builder: (column) => column);
@@ -10624,6 +10861,7 @@ class $$MessagesTableTableManager extends RootTableManager<
Value type = const Value.absent(),
Value content = const Value.absent(),
Value mediaId = const Value.absent(),
+ Value additionalMessageData = const Value.absent(),
Value mediaStored = const Value.absent(),
Value mediaReopened = const Value.absent(),
Value downloadToken = const Value.absent(),
@@ -10644,6 +10882,7 @@ class $$MessagesTableTableManager extends RootTableManager<
type: type,
content: content,
mediaId: mediaId,
+ additionalMessageData: additionalMessageData,
mediaStored: mediaStored,
mediaReopened: mediaReopened,
downloadToken: downloadToken,
@@ -10664,6 +10903,7 @@ class $$MessagesTableTableManager extends RootTableManager<
required MessageType type,
Value content = const Value.absent(),
Value mediaId = const Value.absent(),
+ Value additionalMessageData = const Value.absent(),
Value mediaStored = const Value.absent(),
Value mediaReopened = const Value.absent(),
Value downloadToken = const Value.absent(),
@@ -10684,6 +10924,7 @@ class $$MessagesTableTableManager extends RootTableManager<
type: type,
content: content,
mediaId: mediaId,
+ additionalMessageData: additionalMessageData,
mediaStored: mediaStored,
mediaReopened: mediaReopened,
downloadToken: downloadToken,
@@ -10878,6 +11119,21 @@ final class $$MessageHistoriesTableReferences
return ProcessedTableManager(
manager.$state.copyWith(prefetchedData: [item]));
}
+
+ static $ContactsTable _contactIdTable(_$TwonlyDB db) =>
+ db.contacts.createAlias($_aliasNameGenerator(
+ db.messageHistories.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 $$MessageHistoriesTableFilterComposer
@@ -10892,9 +11148,6 @@ class $$MessageHistoriesTableFilterComposer
ColumnFilters get id => $composableBuilder(
column: $table.id, builder: (column) => ColumnFilters(column));
- ColumnFilters get contactId => $composableBuilder(
- column: $table.contactId, builder: (column) => ColumnFilters(column));
-
ColumnFilters get content => $composableBuilder(
column: $table.content, builder: (column) => ColumnFilters(column));
@@ -10920,6 +11173,26 @@ class $$MessageHistoriesTableFilterComposer
));
return composer;
}
+
+ $$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 $$MessageHistoriesTableOrderingComposer
@@ -10934,9 +11207,6 @@ class $$MessageHistoriesTableOrderingComposer
ColumnOrderings get id => $composableBuilder(
column: $table.id, builder: (column) => ColumnOrderings(column));
- ColumnOrderings get contactId => $composableBuilder(
- column: $table.contactId, builder: (column) => ColumnOrderings(column));
-
ColumnOrderings get content => $composableBuilder(
column: $table.content, builder: (column) => ColumnOrderings(column));
@@ -10962,6 +11232,26 @@ class $$MessageHistoriesTableOrderingComposer
));
return composer;
}
+
+ $$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 $$MessageHistoriesTableAnnotationComposer
@@ -10976,9 +11266,6 @@ class $$MessageHistoriesTableAnnotationComposer
GeneratedColumn get id =>
$composableBuilder(column: $table.id, builder: (column) => column);
- GeneratedColumn get contactId =>
- $composableBuilder(column: $table.contactId, builder: (column) => column);
-
GeneratedColumn get content =>
$composableBuilder(column: $table.content, builder: (column) => column);
@@ -11004,6 +11291,26 @@ class $$MessageHistoriesTableAnnotationComposer
));
return composer;
}
+
+ $$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 $$MessageHistoriesTableTableManager extends RootTableManager<
@@ -11017,7 +11324,7 @@ class $$MessageHistoriesTableTableManager extends RootTableManager<
$$MessageHistoriesTableUpdateCompanionBuilder,
(MessageHistory, $$MessageHistoriesTableReferences),
MessageHistory,
- PrefetchHooks Function({bool messageId})> {
+ PrefetchHooks Function({bool messageId, bool contactId})> {
$$MessageHistoriesTableTableManager(
_$TwonlyDB db, $MessageHistoriesTable table)
: super(TableManagerState(
@@ -11063,7 +11370,7 @@ class $$MessageHistoriesTableTableManager extends RootTableManager<
$$MessageHistoriesTableReferences(db, table, e)
))
.toList(),
- prefetchHooksCallback: ({messageId = false}) {
+ prefetchHooksCallback: ({messageId = false, contactId = false}) {
return PrefetchHooks(
db: db,
explicitlyWatchedTables: [],
@@ -11091,6 +11398,17 @@ class $$MessageHistoriesTableTableManager extends RootTableManager<
.messageId,
) as T;
}
+ if (contactId) {
+ state = state.withJoin(
+ currentTable: table,
+ currentColumn: table.contactId,
+ referencedTable:
+ $$MessageHistoriesTableReferences._contactIdTable(db),
+ referencedColumn: $$MessageHistoriesTableReferences
+ ._contactIdTable(db)
+ .userId,
+ ) as T;
+ }
return state;
},
@@ -11113,7 +11431,7 @@ typedef $$MessageHistoriesTableProcessedTableManager = ProcessedTableManager<
$$MessageHistoriesTableUpdateCompanionBuilder,
(MessageHistory, $$MessageHistoriesTableReferences),
MessageHistory,
- PrefetchHooks Function({bool messageId})>;
+ PrefetchHooks Function({bool messageId, bool contactId})>;
typedef $$ReactionsTableCreateCompanionBuilder = ReactionsCompanion Function({
required String messageId,
required String emoji,
@@ -13581,6 +13899,21 @@ final class $$MessageActionsTableReferences
return ProcessedTableManager(
manager.$state.copyWith(prefetchedData: [item]));
}
+
+ static $ContactsTable _contactIdTable(_$TwonlyDB db) =>
+ db.contacts.createAlias($_aliasNameGenerator(
+ db.messageActions.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 $$MessageActionsTableFilterComposer
@@ -13592,9 +13925,6 @@ class $$MessageActionsTableFilterComposer
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
- ColumnFilters get contactId => $composableBuilder(
- column: $table.contactId, builder: (column) => ColumnFilters(column));
-
ColumnWithTypeConverterFilters
get type => $composableBuilder(
column: $table.type,
@@ -13622,6 +13952,26 @@ class $$MessageActionsTableFilterComposer
));
return composer;
}
+
+ $$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 $$MessageActionsTableOrderingComposer
@@ -13633,9 +13983,6 @@ class $$MessageActionsTableOrderingComposer
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
- ColumnOrderings get contactId => $composableBuilder(
- column: $table.contactId, builder: (column) => ColumnOrderings(column));
-
ColumnOrderings get type => $composableBuilder(
column: $table.type, builder: (column) => ColumnOrderings(column));
@@ -13661,6 +14008,26 @@ class $$MessageActionsTableOrderingComposer
));
return composer;
}
+
+ $$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 $$MessageActionsTableAnnotationComposer
@@ -13672,9 +14039,6 @@ class $$MessageActionsTableAnnotationComposer
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
- GeneratedColumn get contactId =>
- $composableBuilder(column: $table.contactId, builder: (column) => column);
-
GeneratedColumnWithTypeConverter get type =>
$composableBuilder(column: $table.type, builder: (column) => column);
@@ -13700,6 +14064,26 @@ class $$MessageActionsTableAnnotationComposer
));
return composer;
}
+
+ $$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 $$MessageActionsTableTableManager extends RootTableManager<
@@ -13713,7 +14097,7 @@ class $$MessageActionsTableTableManager extends RootTableManager<
$$MessageActionsTableUpdateCompanionBuilder,
(MessageAction, $$MessageActionsTableReferences),
MessageAction,
- PrefetchHooks Function({bool messageId})> {
+ PrefetchHooks Function({bool messageId, bool contactId})> {
$$MessageActionsTableTableManager(_$TwonlyDB db, $MessageActionsTable table)
: super(TableManagerState(
db: db,
@@ -13758,7 +14142,7 @@ class $$MessageActionsTableTableManager extends RootTableManager<
$$MessageActionsTableReferences(db, table, e)
))
.toList(),
- prefetchHooksCallback: ({messageId = false}) {
+ prefetchHooksCallback: ({messageId = false, contactId = false}) {
return PrefetchHooks(
db: db,
explicitlyWatchedTables: [],
@@ -13786,6 +14170,17 @@ class $$MessageActionsTableTableManager extends RootTableManager<
.messageId,
) as T;
}
+ if (contactId) {
+ state = state.withJoin(
+ currentTable: table,
+ currentColumn: table.contactId,
+ referencedTable:
+ $$MessageActionsTableReferences._contactIdTable(db),
+ referencedColumn: $$MessageActionsTableReferences
+ ._contactIdTable(db)
+ .userId,
+ ) as T;
+ }
return state;
},
@@ -13808,7 +14203,7 @@ typedef $$MessageActionsTableProcessedTableManager = ProcessedTableManager<
$$MessageActionsTableUpdateCompanionBuilder,
(MessageAction, $$MessageActionsTableReferences),
MessageAction,
- PrefetchHooks Function({bool messageId})>;
+ PrefetchHooks Function({bool messageId, bool contactId})>;
typedef $$GroupHistoriesTableCreateCompanionBuilder = GroupHistoriesCompanion
Function({
required String groupHistoryId,
diff --git a/lib/src/database/twonly.db.steps.dart b/lib/src/database/twonly.db.steps.dart
index 24ecbc9..fc68ba1 100644
--- a/lib/src/database/twonly.db.steps.dart
+++ b/lib/src/database/twonly.db.steps.dart
@@ -2804,12 +2804,439 @@ i1.GeneratedColumn _column_104(String aliasedName) =>
i1.GeneratedColumn(
'mark_for_retry_after_accepted', aliasedName, true,
type: i1.DriftSqlType.dateTime);
+
+final class Schema7 extends i0.VersionedSchema {
+ Schema7({required super.database}) : super(version: 7);
+ @override
+ late final List entities = [
+ contacts,
+ groups,
+ mediaFiles,
+ messages,
+ messageHistories,
+ reactions,
+ groupMembers,
+ receipts,
+ receivedReceipts,
+ signalIdentityKeyStores,
+ signalPreKeyStores,
+ signalSenderKeyStores,
+ signalSessionStores,
+ signalContactPreKeys,
+ signalContactSignedPreKeys,
+ messageActions,
+ groupHistories,
+ ];
+ late final Shape0 contacts = Shape0(
+ source: i0.VersionedTable(
+ entityName: 'contacts',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(user_id)',
+ ],
+ columns: [
+ _column_0,
+ _column_1,
+ _column_2,
+ _column_3,
+ _column_4,
+ _column_5,
+ _column_6,
+ _column_7,
+ _column_8,
+ _column_9,
+ _column_10,
+ _column_11,
+ _column_12,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape17 groups = Shape17(
+ source: i0.VersionedTable(
+ entityName: 'groups',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(group_id)',
+ ],
+ columns: [
+ _column_13,
+ _column_14,
+ _column_15,
+ _column_16,
+ _column_17,
+ _column_18,
+ _column_19,
+ _column_20,
+ _column_21,
+ _column_22,
+ _column_23,
+ _column_24,
+ _column_100,
+ _column_25,
+ _column_26,
+ _column_27,
+ _column_12,
+ _column_28,
+ _column_29,
+ _column_30,
+ _column_31,
+ _column_32,
+ _column_33,
+ _column_34,
+ _column_35,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape18 mediaFiles = Shape18(
+ source: i0.VersionedTable(
+ entityName: 'media_files',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(media_id)',
+ ],
+ columns: [
+ _column_36,
+ _column_37,
+ _column_38,
+ _column_39,
+ _column_40,
+ _column_41,
+ _column_42,
+ _column_43,
+ _column_44,
+ _column_45,
+ _column_46,
+ _column_47,
+ _column_48,
+ _column_49,
+ _column_102,
+ _column_12,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape21 messages = Shape21(
+ source: i0.VersionedTable(
+ entityName: 'messages',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(message_id)',
+ ],
+ columns: [
+ _column_50,
+ _column_51,
+ _column_52,
+ _column_37,
+ _column_53,
+ _column_54,
+ _column_105,
+ _column_55,
+ _column_56,
+ _column_46,
+ _column_57,
+ _column_58,
+ _column_59,
+ _column_60,
+ _column_12,
+ _column_61,
+ _column_62,
+ _column_63,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape4 messageHistories = Shape4(
+ source: i0.VersionedTable(
+ entityName: 'message_histories',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(id)',
+ ],
+ columns: [
+ _column_64,
+ _column_65,
+ _column_66,
+ _column_53,
+ _column_12,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape5 reactions = Shape5(
+ source: i0.VersionedTable(
+ entityName: 'reactions',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(message_id, sender_id, emoji)',
+ ],
+ columns: [
+ _column_65,
+ _column_67,
+ _column_68,
+ _column_12,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape6 groupMembers = Shape6(
+ source: i0.VersionedTable(
+ entityName: 'group_members',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(group_id, contact_id)',
+ ],
+ columns: [
+ _column_50,
+ _column_69,
+ _column_70,
+ _column_71,
+ _column_72,
+ _column_12,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape20 receipts = Shape20(
+ source: i0.VersionedTable(
+ entityName: 'receipts',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(receipt_id)',
+ ],
+ columns: [
+ _column_73,
+ _column_74,
+ _column_75,
+ _column_76,
+ _column_77,
+ _column_103,
+ _column_104,
+ _column_78,
+ _column_79,
+ _column_80,
+ _column_12,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape8 receivedReceipts = Shape8(
+ source: i0.VersionedTable(
+ entityName: 'received_receipts',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(receipt_id)',
+ ],
+ columns: [
+ _column_73,
+ _column_12,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape9 signalIdentityKeyStores = Shape9(
+ source: i0.VersionedTable(
+ entityName: 'signal_identity_key_stores',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(device_id, name)',
+ ],
+ columns: [
+ _column_81,
+ _column_82,
+ _column_83,
+ _column_12,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape10 signalPreKeyStores = Shape10(
+ source: i0.VersionedTable(
+ entityName: 'signal_pre_key_stores',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(pre_key_id)',
+ ],
+ columns: [
+ _column_84,
+ _column_85,
+ _column_12,
+ ],
+ 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_86,
+ _column_87,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape12 signalSessionStores = Shape12(
+ source: i0.VersionedTable(
+ entityName: 'signal_session_stores',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(device_id, name)',
+ ],
+ columns: [
+ _column_81,
+ _column_82,
+ _column_88,
+ _column_12,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape13 signalContactPreKeys = Shape13(
+ source: i0.VersionedTable(
+ entityName: 'signal_contact_pre_keys',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(contact_id, pre_key_id)',
+ ],
+ columns: [
+ _column_74,
+ _column_84,
+ _column_85,
+ _column_12,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape14 signalContactSignedPreKeys = Shape14(
+ source: i0.VersionedTable(
+ entityName: 'signal_contact_signed_pre_keys',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(contact_id)',
+ ],
+ columns: [
+ _column_74,
+ _column_89,
+ _column_90,
+ _column_91,
+ _column_12,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape15 messageActions = Shape15(
+ source: i0.VersionedTable(
+ entityName: 'message_actions',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(message_id, contact_id, type)',
+ ],
+ columns: [
+ _column_65,
+ _column_92,
+ _column_37,
+ _column_93,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape16 groupHistories = Shape16(
+ source: i0.VersionedTable(
+ entityName: 'group_histories',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [
+ 'PRIMARY KEY(group_history_id)',
+ ],
+ columns: [
+ _column_94,
+ _column_50,
+ _column_95,
+ _column_101,
+ _column_97,
+ _column_98,
+ _column_99,
+ _column_37,
+ _column_93,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+}
+
+class Shape21 extends i0.VersionedTable {
+ Shape21({required super.source, required super.alias}) : super.aliased();
+ i1.GeneratedColumn get groupId =>
+ columnsByName['group_id']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get messageId =>
+ columnsByName['message_id']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get senderId =>
+ columnsByName['sender_id']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get type =>
+ columnsByName['type']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get content =>
+ columnsByName['content']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get mediaId =>
+ columnsByName['media_id']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get additionalMessageData =>
+ columnsByName['additional_message_data']!
+ as i1.GeneratedColumn;
+ i1.GeneratedColumn get mediaStored =>
+ columnsByName['media_stored']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get mediaReopened =>
+ columnsByName['media_reopened']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get downloadToken =>
+ columnsByName['download_token']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get quotesMessageId =>
+ columnsByName['quotes_message_id']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get isDeletedFromSender =>
+ columnsByName['is_deleted_from_sender']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get openedAt =>
+ columnsByName['opened_at']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get openedByAll =>
+ columnsByName['opened_by_all']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get createdAt =>
+ columnsByName['created_at']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get modifiedAt =>
+ columnsByName['modified_at']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get ackByUser =>
+ columnsByName['ack_by_user']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get ackByServer =>
+ columnsByName['ack_by_server']! as i1.GeneratedColumn;
+}
+
+i1.GeneratedColumn _column_105(String aliasedName) =>
+ i1.GeneratedColumn(
+ 'additional_message_data', aliasedName, true,
+ type: i1.DriftSqlType.blob);
i0.MigrationStepWithVersion migrationSteps({
required Future Function(i1.Migrator m, Schema2 schema) from1To2,
required Future Function(i1.Migrator m, Schema3 schema) from2To3,
required Future Function(i1.Migrator m, Schema4 schema) from3To4,
required Future Function(i1.Migrator m, Schema5 schema) from4To5,
required Future Function(i1.Migrator m, Schema6 schema) from5To6,
+ required Future Function(i1.Migrator m, Schema7 schema) from6To7,
}) {
return (currentVersion, database) async {
switch (currentVersion) {
@@ -2838,6 +3265,11 @@ i0.MigrationStepWithVersion migrationSteps({
final migrator = i1.Migrator(database, schema);
await from5To6(migrator, schema);
return 6;
+ case 6:
+ final schema = Schema7(database: database);
+ final migrator = i1.Migrator(database, schema);
+ await from6To7(migrator, schema);
+ return 7;
default:
throw ArgumentError.value('Unknown migration from $currentVersion');
}
@@ -2850,6 +3282,7 @@ i1.OnUpgrade stepByStep({
required Future Function(i1.Migrator m, Schema4 schema) from3To4,
required Future Function(i1.Migrator m, Schema5 schema) from4To5,
required Future Function(i1.Migrator m, Schema6 schema) from5To6,
+ required Future Function(i1.Migrator m, Schema7 schema) from6To7,
}) =>
i0.VersionedSchema.stepByStepHelper(
step: migrationSteps(
@@ -2858,4 +3291,5 @@ i1.OnUpgrade stepByStep({
from3To4: from3To4,
from4To5: from4To5,
from5To6: from5To6,
+ from6To7: from6To7,
));
diff --git a/lib/src/localization/generated/app_localizations.dart b/lib/src/localization/generated/app_localizations.dart
index 2a6f815..fb8ea1b 100644
--- a/lib/src/localization/generated/app_localizations.dart
+++ b/lib/src/localization/generated/app_localizations.dart
@@ -2518,6 +2518,12 @@ abstract class AppLocalizations {
/// **'wants to connect with you.'**
String get notificationContactRequest;
+ /// No description provided for @notificationContactRequestUnknownUser.
+ ///
+ /// In en, this message translates to:
+ /// **'have received a new contact request.'**
+ String get notificationContactRequestUnknownUser;
+
/// No description provided for @notificationAcceptRequest.
///
/// In en, this message translates to:
@@ -2572,11 +2578,17 @@ abstract class AppLocalizations {
/// **'has responded{inGroup}.'**
String notificationResponse(Object inGroup);
- /// No description provided for @notificationTitleUnknownUser.
+ /// No description provided for @notificationTitleUnknown.
///
/// In en, this message translates to:
- /// **'[Unknown]'**
- String get notificationTitleUnknownUser;
+ /// **'You have a new message.'**
+ String get notificationTitleUnknown;
+
+ /// No description provided for @notificationBodyUnknown.
+ ///
+ /// In en, this message translates to:
+ /// **'Open twonly to learn more.'**
+ String get notificationBodyUnknown;
/// No description provided for @notificationCategoryMessageTitle.
///
diff --git a/lib/src/localization/generated/app_localizations_de.dart b/lib/src/localization/generated/app_localizations_de.dart
index c328e26..3a3c99a 100644
--- a/lib/src/localization/generated/app_localizations_de.dart
+++ b/lib/src/localization/generated/app_localizations_de.dart
@@ -1380,6 +1380,10 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get notificationContactRequest => 'möchte sich mit dir vernetzen.';
+ @override
+ String get notificationContactRequestUnknownUser =>
+ 'hast eine neue Kontaktanfrage erhalten.';
+
@override
String get notificationAcceptRequest => 'ist jetzt mit dir vernetzt.';
@@ -1418,7 +1422,10 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
- String get notificationTitleUnknownUser => '[Unbekannt]';
+ String get notificationTitleUnknown => 'Du hast eine neue Nachricht.';
+
+ @override
+ String get notificationBodyUnknown => 'Öffne twonly um mehr zu erfahren.';
@override
String get notificationCategoryMessageTitle => 'Nachrichten';
diff --git a/lib/src/localization/generated/app_localizations_en.dart b/lib/src/localization/generated/app_localizations_en.dart
index 13f17c7..fecc2ac 100644
--- a/lib/src/localization/generated/app_localizations_en.dart
+++ b/lib/src/localization/generated/app_localizations_en.dart
@@ -1372,6 +1372,10 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get notificationContactRequest => 'wants to connect with you.';
+ @override
+ String get notificationContactRequestUnknownUser =>
+ 'have received a new contact request.';
+
@override
String get notificationAcceptRequest => 'is now connected with you.';
@@ -1410,7 +1414,10 @@ class AppLocalizationsEn extends AppLocalizations {
}
@override
- String get notificationTitleUnknownUser => '[Unknown]';
+ String get notificationTitleUnknown => 'You have a new message.';
+
+ @override
+ String get notificationBodyUnknown => 'Open twonly to learn more.';
@override
String get notificationCategoryMessageTitle => 'Messages';
diff --git a/lib/src/localization/generated/app_localizations_sv.dart b/lib/src/localization/generated/app_localizations_sv.dart
index 7b15afc..bcd7c52 100644
--- a/lib/src/localization/generated/app_localizations_sv.dart
+++ b/lib/src/localization/generated/app_localizations_sv.dart
@@ -1372,6 +1372,10 @@ class AppLocalizationsSv extends AppLocalizations {
@override
String get notificationContactRequest => 'wants to connect with you.';
+ @override
+ String get notificationContactRequestUnknownUser =>
+ 'have received a new contact request.';
+
@override
String get notificationAcceptRequest => 'is now connected with you.';
@@ -1410,7 +1414,10 @@ class AppLocalizationsSv extends AppLocalizations {
}
@override
- String get notificationTitleUnknownUser => '[Unknown]';
+ String get notificationTitleUnknown => 'You have a new message.';
+
+ @override
+ String get notificationBodyUnknown => 'Open twonly to learn more.';
@override
String get notificationCategoryMessageTitle => 'Messages';
diff --git a/lib/src/localization/translations b/lib/src/localization/translations
index 20f3c2f..9d04e9e 160000
--- a/lib/src/localization/translations
+++ b/lib/src/localization/translations
@@ -1 +1 @@
-Subproject commit 20f3c2f0a49e4c9be452ecbc84d98054c92974e1
+Subproject commit 9d04e9e1d0cdba8f1be4b0cbba341706c3cffac9
diff --git a/lib/src/model/json/userdata.dart b/lib/src/model/json/userdata.dart
index eb26ef3..9945264 100644
--- a/lib/src/model/json/userdata.dart
+++ b/lib/src/model/json/userdata.dart
@@ -108,6 +108,19 @@ class UserData {
DateTime? nextTimeToShowBackupNotice;
BackupServer? backupServer;
TwonlySafeBackup? twonlySafeBackup;
+
+ // For my master thesis I want to create a anonymous user study:
+ // - users in the "Tester" Plan can, if they want, take part of the user study
+
+ @JsonKey(defaultValue: false)
+ bool askedForUserStudyPermission = false;
+
+ // So update data can be assigned. If set the user choose to participate.
+ String? userStudyParticipantsToken;
+
+ // Once a day the anonymous data is collected and send to the server
+ DateTime? lastUserStudyDataUpload;
+
Map toJson() => _$UserDataToJson(this);
}
diff --git a/lib/src/model/json/userdata.g.dart b/lib/src/model/json/userdata.g.dart
index a478117..3dc2fbb 100644
--- a/lib/src/model/json/userdata.g.dart
+++ b/lib/src/model/json/userdata.g.dart
@@ -77,7 +77,14 @@ UserData _$UserDataFromJson(Map json) => UserData(
..twonlySafeBackup = json['twonlySafeBackup'] == null
? null
: TwonlySafeBackup.fromJson(
- json['twonlySafeBackup'] as Map);
+ json['twonlySafeBackup'] as Map)
+ ..askedForUserStudyPermission =
+ json['askedForUserStudyPermission'] as bool? ?? false
+ ..userStudyParticipantsToken =
+ json['userStudyParticipantsToken'] as String?
+ ..lastUserStudyDataUpload = json['lastUserStudyDataUpload'] == null
+ ? null
+ : DateTime.parse(json['lastUserStudyDataUpload'] as String);
Map _$UserDataToJson(UserData instance) => {
'userId': instance.userId,
@@ -122,6 +129,10 @@ Map _$UserDataToJson(UserData instance) => {
instance.nextTimeToShowBackupNotice?.toIso8601String(),
'backupServer': instance.backupServer,
'twonlySafeBackup': instance.twonlySafeBackup,
+ 'askedForUserStudyPermission': instance.askedForUserStudyPermission,
+ 'userStudyParticipantsToken': instance.userStudyParticipantsToken,
+ 'lastUserStudyDataUpload':
+ instance.lastUserStudyDataUpload?.toIso8601String(),
};
const _$ThemeModeEnumMap = {
diff --git a/lib/src/model/protobuf/client/data.proto b/lib/src/model/protobuf/client/data.proto
new file mode 100644
index 0000000..20a3b48
--- /dev/null
+++ b/lib/src/model/protobuf/client/data.proto
@@ -0,0 +1,11 @@
+syntax = "proto3";
+
+
+message AdditionalMessageData {
+ enum Type {
+ LINK = 0;
+ }
+ Type type = 1;
+
+ optional string link = 2;
+}
\ No newline at end of file
diff --git a/lib/src/model/protobuf/client/generated/data.pb.dart b/lib/src/model/protobuf/client/generated/data.pb.dart
new file mode 100644
index 0000000..9b547b3
--- /dev/null
+++ b/lib/src/model/protobuf/client/generated/data.pb.dart
@@ -0,0 +1,99 @@
+// This is a generated file - do not edit.
+//
+// Generated from data.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:protobuf/protobuf.dart' as $pb;
+
+import 'data.pbenum.dart';
+
+export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions;
+
+export 'data.pbenum.dart';
+
+class AdditionalMessageData extends $pb.GeneratedMessage {
+ factory AdditionalMessageData({
+ AdditionalMessageData_Type? type,
+ $core.String? link,
+ }) {
+ final result = create();
+ if (type != null) result.type = type;
+ if (link != null) result.link = link;
+ return result;
+ }
+
+ AdditionalMessageData._();
+
+ factory AdditionalMessageData.fromBuffer($core.List<$core.int> data,
+ [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
+ create()..mergeFromBuffer(data, registry);
+ factory AdditionalMessageData.fromJson($core.String json,
+ [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
+ create()..mergeFromJson(json, registry);
+
+ static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+ _omitMessageNames ? '' : 'AdditionalMessageData',
+ createEmptyInstance: create)
+ ..e(
+ 1, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE,
+ defaultOrMaker: AdditionalMessageData_Type.LINK,
+ valueOf: AdditionalMessageData_Type.valueOf,
+ enumValues: AdditionalMessageData_Type.values)
+ ..aOS(2, _omitFieldNames ? '' : 'link')
+ ..hasRequiredFields = false;
+
+ @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+ AdditionalMessageData clone() =>
+ AdditionalMessageData()..mergeFromMessage(this);
+ @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+ AdditionalMessageData copyWith(
+ void Function(AdditionalMessageData) updates) =>
+ super.copyWith((message) => updates(message as AdditionalMessageData))
+ as AdditionalMessageData;
+
+ @$core.override
+ $pb.BuilderInfo get info_ => _i;
+
+ @$core.pragma('dart2js:noInline')
+ static AdditionalMessageData create() => AdditionalMessageData._();
+ @$core.override
+ AdditionalMessageData createEmptyInstance() => create();
+ static $pb.PbList createRepeated() =>
+ $pb.PbList();
+ @$core.pragma('dart2js:noInline')
+ static AdditionalMessageData getDefault() => _defaultInstance ??=
+ $pb.GeneratedMessage.$_defaultFor(create);
+ static AdditionalMessageData? _defaultInstance;
+
+ @$pb.TagNumber(1)
+ AdditionalMessageData_Type get type => $_getN(0);
+ @$pb.TagNumber(1)
+ set type(AdditionalMessageData_Type value) => $_setField(1, value);
+ @$pb.TagNumber(1)
+ $core.bool hasType() => $_has(0);
+ @$pb.TagNumber(1)
+ void clearType() => $_clearField(1);
+
+ @$pb.TagNumber(2)
+ $core.String get link => $_getSZ(1);
+ @$pb.TagNumber(2)
+ set link($core.String value) => $_setString(1, value);
+ @$pb.TagNumber(2)
+ $core.bool hasLink() => $_has(1);
+ @$pb.TagNumber(2)
+ void clearLink() => $_clearField(2);
+}
+
+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/data.pbenum.dart b/lib/src/model/protobuf/client/generated/data.pbenum.dart
new file mode 100644
index 0000000..4f40622
--- /dev/null
+++ b/lib/src/model/protobuf/client/generated/data.pbenum.dart
@@ -0,0 +1,35 @@
+// This is a generated file - do not edit.
+//
+// Generated from data.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:protobuf/protobuf.dart' as $pb;
+
+class AdditionalMessageData_Type extends $pb.ProtobufEnum {
+ static const AdditionalMessageData_Type LINK =
+ AdditionalMessageData_Type._(0, _omitEnumNames ? '' : 'LINK');
+
+ static const $core.List values =
+ [
+ LINK,
+ ];
+
+ static final $core.List _byValue =
+ $pb.ProtobufEnum.$_initByValueList(values, 0);
+ static AdditionalMessageData_Type? valueOf($core.int value) =>
+ value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+ const AdditionalMessageData_Type._(super.value, super.name);
+}
+
+const $core.bool _omitEnumNames =
+ $core.bool.fromEnvironment('protobuf.omit_enum_names');
diff --git a/lib/src/model/protobuf/client/generated/data.pbjson.dart b/lib/src/model/protobuf/client/generated/data.pbjson.dart
new file mode 100644
index 0000000..fb0a248
--- /dev/null
+++ b/lib/src/model/protobuf/client/generated/data.pbjson.dart
@@ -0,0 +1,49 @@
+// This is a generated file - do not edit.
+//
+// Generated from data.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 additionalMessageDataDescriptor instead')
+const AdditionalMessageData$json = {
+ '1': 'AdditionalMessageData',
+ '2': [
+ {
+ '1': 'type',
+ '3': 1,
+ '4': 1,
+ '5': 14,
+ '6': '.AdditionalMessageData.Type',
+ '10': 'type'
+ },
+ {'1': 'link', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'link', '17': true},
+ ],
+ '4': [AdditionalMessageData_Type$json],
+ '8': [
+ {'1': '_link'},
+ ],
+};
+
+@$core.Deprecated('Use additionalMessageDataDescriptor instead')
+const AdditionalMessageData_Type$json = {
+ '1': 'Type',
+ '2': [
+ {'1': 'LINK', '2': 0},
+ ],
+};
+
+/// Descriptor for `AdditionalMessageData`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List additionalMessageDataDescriptor = $convert.base64Decode(
+ 'ChVBZGRpdGlvbmFsTWVzc2FnZURhdGESLwoEdHlwZRgBIAEoDjIbLkFkZGl0aW9uYWxNZXNzYW'
+ 'dlRGF0YS5UeXBlUgR0eXBlEhcKBGxpbmsYAiABKAlIAFIEbGlua4gBASIQCgRUeXBlEggKBExJ'
+ 'TksQAEIHCgVfbGluaw==');
diff --git a/lib/src/model/protobuf/client/generated/messages.pb.dart b/lib/src/model/protobuf/client/generated/messages.pb.dart
index a02260f..b137dde 100644
--- a/lib/src/model/protobuf/client/generated/messages.pb.dart
+++ b/lib/src/model/protobuf/client/generated/messages.pb.dart
@@ -969,6 +969,7 @@ class EncryptedContent_Media extends $pb.GeneratedMessage {
$core.List<$core.int>? encryptionKey,
$core.List<$core.int>? encryptionMac,
$core.List<$core.int>? encryptionNonce,
+ $core.List<$core.int>? additionalMessageData,
}) {
final result = create();
if (senderMessageId != null) result.senderMessageId = senderMessageId;
@@ -983,6 +984,8 @@ class EncryptedContent_Media extends $pb.GeneratedMessage {
if (encryptionKey != null) result.encryptionKey = encryptionKey;
if (encryptionMac != null) result.encryptionMac = encryptionMac;
if (encryptionNonce != null) result.encryptionNonce = encryptionNonce;
+ if (additionalMessageData != null)
+ result.additionalMessageData = additionalMessageData;
return result;
}
@@ -1024,6 +1027,8 @@ class EncryptedContent_Media extends $pb.GeneratedMessage {
..a<$core.List<$core.int>>(
10, _omitFieldNames ? '' : 'encryptionNonce', $pb.PbFieldType.OY,
protoName: 'encryptionNonce')
+ ..a<$core.List<$core.int>>(
+ 11, _omitFieldNames ? '' : 'additionalMessageData', $pb.PbFieldType.OY)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@@ -1138,6 +1143,16 @@ class EncryptedContent_Media extends $pb.GeneratedMessage {
$core.bool hasEncryptionNonce() => $_has(9);
@$pb.TagNumber(10)
void clearEncryptionNonce() => $_clearField(10);
+
+ @$pb.TagNumber(11)
+ $core.List<$core.int> get additionalMessageData => $_getN(10);
+ @$pb.TagNumber(11)
+ set additionalMessageData($core.List<$core.int> value) =>
+ $_setBytes(10, value);
+ @$pb.TagNumber(11)
+ $core.bool hasAdditionalMessageData() => $_has(10);
+ @$pb.TagNumber(11)
+ void clearAdditionalMessageData() => $_clearField(11);
}
class EncryptedContent_MediaUpdate extends $pb.GeneratedMessage {
diff --git a/lib/src/model/protobuf/client/generated/messages.pbjson.dart b/lib/src/model/protobuf/client/generated/messages.pbjson.dart
index 0331672..fd49512 100644
--- a/lib/src/model/protobuf/client/generated/messages.pbjson.dart
+++ b/lib/src/model/protobuf/client/generated/messages.pbjson.dart
@@ -603,6 +603,15 @@ const EncryptedContent_Media$json = {
'10': 'encryptionNonce',
'17': true
},
+ {
+ '1': 'additional_message_data',
+ '3': 11,
+ '4': 1,
+ '5': 12,
+ '9': 6,
+ '10': 'additionalMessageData',
+ '17': true
+ },
],
'4': [EncryptedContent_Media_Type$json],
'8': [
@@ -612,6 +621,7 @@ const EncryptedContent_Media$json = {
{'1': '_encryptionKey'},
{'1': '_encryptionMac'},
{'1': '_encryptionNonce'},
+ {'1': '_additional_message_data'},
],
};
@@ -840,7 +850,7 @@ final $typed_data.Uint8List encryptedContentDescriptor = $convert.base64Decode(
'EjoKGG11bHRpcGxlVGFyZ2V0TWVzc2FnZUlkcxgDIAMoCVIYbXVsdGlwbGVUYXJnZXRNZXNzYW'
'dlSWRzEhcKBHRleHQYBCABKAlIAVIEdGV4dIgBARIcCgl0aW1lc3RhbXAYBSABKANSCXRpbWVz'
'dGFtcCItCgRUeXBlEgoKBkRFTEVURRAAEg0KCUVESVRfVEVYVBABEgoKBk9QRU5FRBACQhIKEF'
- '9zZW5kZXJNZXNzYWdlSWRCBwoFX3RleHQalwUKBU1lZGlhEigKD3NlbmRlck1lc3NhZ2VJZBgB'
+ '9zZW5kZXJNZXNzYWdlSWRCBwoFX3RleHQa8AUKBU1lZGlhEigKD3NlbmRlck1lc3NhZ2VJZBgB'
'IAEoCVIPc2VuZGVyTWVzc2FnZUlkEjAKBHR5cGUYAiABKA4yHC5FbmNyeXB0ZWRDb250ZW50Lk'
'1lZGlhLlR5cGVSBHR5cGUSQwoaZGlzcGxheUxpbWl0SW5NaWxsaXNlY29uZHMYAyABKANIAFIa'
'ZGlzcGxheUxpbWl0SW5NaWxsaXNlY29uZHOIAQESNgoWcmVxdWlyZXNBdXRoZW50aWNhdGlvbh'
@@ -849,29 +859,31 @@ final $typed_data.Uint8List encryptedContentDescriptor = $convert.base64Decode(
'dubG9hZFRva2VuGAcgASgMSAJSDWRvd25sb2FkVG9rZW6IAQESKQoNZW5jcnlwdGlvbktleRgI'
'IAEoDEgDUg1lbmNyeXB0aW9uS2V5iAEBEikKDWVuY3J5cHRpb25NYWMYCSABKAxIBFINZW5jcn'
'lwdGlvbk1hY4gBARItCg9lbmNyeXB0aW9uTm9uY2UYCiABKAxIBVIPZW5jcnlwdGlvbk5vbmNl'
- 'iAEBIj4KBFR5cGUSDAoIUkVVUExPQUQQABIJCgVJTUFHRRABEgkKBVZJREVPEAISBwoDR0lGEA'
- 'MSCQoFQVVESU8QBEIdChtfZGlzcGxheUxpbWl0SW5NaWxsaXNlY29uZHNCEQoPX3F1b3RlTWVz'
- 'c2FnZUlkQhAKDl9kb3dubG9hZFRva2VuQhAKDl9lbmNyeXB0aW9uS2V5QhAKDl9lbmNyeXB0aW'
- '9uTWFjQhIKEF9lbmNyeXB0aW9uTm9uY2UapwEKC01lZGlhVXBkYXRlEjYKBHR5cGUYASABKA4y'
- 'Ii5FbmNyeXB0ZWRDb250ZW50Lk1lZGlhVXBkYXRlLlR5cGVSBHR5cGUSKAoPdGFyZ2V0TWVzc2'
- 'FnZUlkGAIgASgJUg90YXJnZXRNZXNzYWdlSWQiNgoEVHlwZRIMCghSRU9QRU5FRBAAEgoKBlNU'
- 'T1JFRBABEhQKEERFQ1JZUFRJT05fRVJST1IQAhp4Cg5Db250YWN0UmVxdWVzdBI5CgR0eXBlGA'
- 'EgASgOMiUuRW5jcnlwdGVkQ29udGVudC5Db250YWN0UmVxdWVzdC5UeXBlUgR0eXBlIisKBFR5'
- 'cGUSCwoHUkVRVUVTVBAAEgoKBlJFSkVDVBABEgoKBkFDQ0VQVBACGp4CCg1Db250YWN0VXBkYX'
- 'RlEjgKBHR5cGUYASABKA4yJC5FbmNyeXB0ZWRDb250ZW50LkNvbnRhY3RVcGRhdGUuVHlwZVIE'
- 'dHlwZRI1ChNhdmF0YXJTdmdDb21wcmVzc2VkGAIgASgMSABSE2F2YXRhclN2Z0NvbXByZXNzZW'
- 'SIAQESHwoIdXNlcm5hbWUYAyABKAlIAVIIdXNlcm5hbWWIAQESJQoLZGlzcGxheU5hbWUYBCAB'
- 'KAlIAlILZGlzcGxheU5hbWWIAQEiHwoEVHlwZRILCgdSRVFVRVNUEAASCgoGVVBEQVRFEAFCFg'
- 'oUX2F2YXRhclN2Z0NvbXByZXNzZWRCCwoJX3VzZXJuYW1lQg4KDF9kaXNwbGF5TmFtZRrVAQoI'
- 'UHVzaEtleXMSMwoEdHlwZRgBIAEoDjIfLkVuY3J5cHRlZENvbnRlbnQuUHVzaEtleXMuVHlwZV'
- 'IEdHlwZRIZCgVrZXlJZBgCIAEoA0gAUgVrZXlJZIgBARIVCgNrZXkYAyABKAxIAVIDa2V5iAEB'
- 'EiEKCWNyZWF0ZWRBdBgEIAEoA0gCUgljcmVhdGVkQXSIAQEiHwoEVHlwZRILCgdSRVFVRVNUEA'
- 'ASCgoGVVBEQVRFEAFCCAoGX2tleUlkQgYKBF9rZXlCDAoKX2NyZWF0ZWRBdBqpAQoJRmxhbWVT'
- 'eW5jEiIKDGZsYW1lQ291bnRlchgBIAEoA1IMZmxhbWVDb3VudGVyEjYKFmxhc3RGbGFtZUNvdW'
- '50ZXJDaGFuZ2UYAiABKANSFmxhc3RGbGFtZUNvdW50ZXJDaGFuZ2USHgoKYmVzdEZyaWVuZBgD'
- 'IAEoCFIKYmVzdEZyaWVuZBIgCgtmb3JjZVVwZGF0ZRgEIAEoCFILZm9yY2VVcGRhdGVCCgoIX2'
- 'dyb3VwSWRCDwoNX2lzRGlyZWN0Q2hhdEIXChVfc2VuZGVyUHJvZmlsZUNvdW50ZXJCEAoOX21l'
- 'c3NhZ2VVcGRhdGVCCAoGX21lZGlhQg4KDF9tZWRpYVVwZGF0ZUIQCg5fY29udGFjdFVwZGF0ZU'
- 'IRCg9fY29udGFjdFJlcXVlc3RCDAoKX2ZsYW1lU3luY0ILCglfcHVzaEtleXNCCwoJX3JlYWN0'
- 'aW9uQg4KDF90ZXh0TWVzc2FnZUIOCgxfZ3JvdXBDcmVhdGVCDAoKX2dyb3VwSm9pbkIOCgxfZ3'
- 'JvdXBVcGRhdGVCFwoVX3Jlc2VuZEdyb3VwUHVibGljS2V5QhEKD19lcnJvcl9tZXNzYWdlcw==');
+ 'iAEBEjsKF2FkZGl0aW9uYWxfbWVzc2FnZV9kYXRhGAsgASgMSAZSFWFkZGl0aW9uYWxNZXNzYW'
+ 'dlRGF0YYgBASI+CgRUeXBlEgwKCFJFVVBMT0FEEAASCQoFSU1BR0UQARIJCgVWSURFTxACEgcK'
+ 'A0dJRhADEgkKBUFVRElPEARCHQobX2Rpc3BsYXlMaW1pdEluTWlsbGlzZWNvbmRzQhEKD19xdW'
+ '90ZU1lc3NhZ2VJZEIQCg5fZG93bmxvYWRUb2tlbkIQCg5fZW5jcnlwdGlvbktleUIQCg5fZW5j'
+ 'cnlwdGlvbk1hY0ISChBfZW5jcnlwdGlvbk5vbmNlQhoKGF9hZGRpdGlvbmFsX21lc3NhZ2VfZG'
+ 'F0YRqnAQoLTWVkaWFVcGRhdGUSNgoEdHlwZRgBIAEoDjIiLkVuY3J5cHRlZENvbnRlbnQuTWVk'
+ 'aWFVcGRhdGUuVHlwZVIEdHlwZRIoCg90YXJnZXRNZXNzYWdlSWQYAiABKAlSD3RhcmdldE1lc3'
+ 'NhZ2VJZCI2CgRUeXBlEgwKCFJFT1BFTkVEEAASCgoGU1RPUkVEEAESFAoQREVDUllQVElPTl9F'
+ 'UlJPUhACGngKDkNvbnRhY3RSZXF1ZXN0EjkKBHR5cGUYASABKA4yJS5FbmNyeXB0ZWRDb250ZW'
+ '50LkNvbnRhY3RSZXF1ZXN0LlR5cGVSBHR5cGUiKwoEVHlwZRILCgdSRVFVRVNUEAASCgoGUkVK'
+ 'RUNUEAESCgoGQUNDRVBUEAIangIKDUNvbnRhY3RVcGRhdGUSOAoEdHlwZRgBIAEoDjIkLkVuY3'
+ 'J5cHRlZENvbnRlbnQuQ29udGFjdFVwZGF0ZS5UeXBlUgR0eXBlEjUKE2F2YXRhclN2Z0NvbXBy'
+ 'ZXNzZWQYAiABKAxIAFITYXZhdGFyU3ZnQ29tcHJlc3NlZIgBARIfCgh1c2VybmFtZRgDIAEoCU'
+ 'gBUgh1c2VybmFtZYgBARIlCgtkaXNwbGF5TmFtZRgEIAEoCUgCUgtkaXNwbGF5TmFtZYgBASIf'
+ 'CgRUeXBlEgsKB1JFUVVFU1QQABIKCgZVUERBVEUQAUIWChRfYXZhdGFyU3ZnQ29tcHJlc3NlZE'
+ 'ILCglfdXNlcm5hbWVCDgoMX2Rpc3BsYXlOYW1lGtUBCghQdXNoS2V5cxIzCgR0eXBlGAEgASgO'
+ 'Mh8uRW5jcnlwdGVkQ29udGVudC5QdXNoS2V5cy5UeXBlUgR0eXBlEhkKBWtleUlkGAIgASgDSA'
+ 'BSBWtleUlkiAEBEhUKA2tleRgDIAEoDEgBUgNrZXmIAQESIQoJY3JlYXRlZEF0GAQgASgDSAJS'
+ 'CWNyZWF0ZWRBdIgBASIfCgRUeXBlEgsKB1JFUVVFU1QQABIKCgZVUERBVEUQAUIICgZfa2V5SW'
+ 'RCBgoEX2tleUIMCgpfY3JlYXRlZEF0GqkBCglGbGFtZVN5bmMSIgoMZmxhbWVDb3VudGVyGAEg'
+ 'ASgDUgxmbGFtZUNvdW50ZXISNgoWbGFzdEZsYW1lQ291bnRlckNoYW5nZRgCIAEoA1IWbGFzdE'
+ 'ZsYW1lQ291bnRlckNoYW5nZRIeCgpiZXN0RnJpZW5kGAMgASgIUgpiZXN0RnJpZW5kEiAKC2Zv'
+ 'cmNlVXBkYXRlGAQgASgIUgtmb3JjZVVwZGF0ZUIKCghfZ3JvdXBJZEIPCg1faXNEaXJlY3RDaG'
+ 'F0QhcKFV9zZW5kZXJQcm9maWxlQ291bnRlckIQCg5fbWVzc2FnZVVwZGF0ZUIICgZfbWVkaWFC'
+ 'DgoMX21lZGlhVXBkYXRlQhAKDl9jb250YWN0VXBkYXRlQhEKD19jb250YWN0UmVxdWVzdEIMCg'
+ 'pfZmxhbWVTeW5jQgsKCV9wdXNoS2V5c0ILCglfcmVhY3Rpb25CDgoMX3RleHRNZXNzYWdlQg4K'
+ 'DF9ncm91cENyZWF0ZUIMCgpfZ3JvdXBKb2luQg4KDF9ncm91cFVwZGF0ZUIXChVfcmVzZW5kR3'
+ 'JvdXBQdWJsaWNLZXlCEQoPX2Vycm9yX21lc3NhZ2Vz');
diff --git a/lib/src/model/protobuf/client/messages.proto b/lib/src/model/protobuf/client/messages.proto
index 1e71cbc..38e24ad 100644
--- a/lib/src/model/protobuf/client/messages.proto
+++ b/lib/src/model/protobuf/client/messages.proto
@@ -132,6 +132,8 @@ message EncryptedContent {
optional bytes encryptionKey = 8;
optional bytes encryptionMac = 9;
optional bytes encryptionNonce = 10;
+
+ optional bytes additional_message_data = 11;
}
message MediaUpdate {
diff --git a/lib/src/services/api.service.dart b/lib/src/services/api.service.dart
index 68e7489..7c3c395 100644
--- a/lib/src/services/api.service.dart
+++ b/lib/src/services/api.service.dart
@@ -26,6 +26,7 @@ import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart
as server;
import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pbserver.dart';
import 'package:twonly/src/services/api/mediafiles/download.service.dart';
+import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
import 'package:twonly/src/services/api/messages.dart';
import 'package:twonly/src/services/api/server_messages.dart';
import 'package:twonly/src/services/api/utils.dart';
@@ -41,6 +42,7 @@ import 'package:twonly/src/utils/keyvalue.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/user_study/user_study_data_collection.dart';
import 'package:web_socket_channel/io.dart';
final lockConnecting = Mutex();
@@ -100,6 +102,11 @@ class ApiService {
unawaited(fetchGroupStatesForUnjoinedGroups());
unawaited(fetchMissingGroupPublicKey());
unawaited(checkForDeletedUsernames());
+
+ 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());
+ }
}
}
@@ -313,6 +320,12 @@ class ApiService {
return user;
});
globalCallbackUpdatePlan(planFromString(authenticated.plan));
+
+ // this was triggered by apiService.ipaPurchase, so call the onAuthenticated again
+ if (isAuthenticated) {
+ // Trigger the re-upload from images, after Plan change, in case the limit was reached before...
+ unawaited(finishStartedPreprocessing());
+ }
}
}
if (res.isError) {
diff --git a/lib/src/services/api/client2client/media.c2c.dart b/lib/src/services/api/client2client/media.c2c.dart
index 807706a..d0c8e3a 100644
--- a/lib/src/services/api/client2client/media.c2c.dart
+++ b/lib/src/services/api/client2client/media.c2c.dart
@@ -105,6 +105,11 @@ Future handleMedia(
groupId: Value(groupId),
mediaId: Value(mediaFile.mediaId),
type: const Value(MessageType.media),
+ additionalMessageData: Value.absentIfNull(
+ media.hasAdditionalMessageData()
+ ? Uint8List.fromList(media.additionalMessageData)
+ : null,
+ ),
quotesMessageId: Value(
media.hasQuoteMessageId() ? media.quoteMessageId : null,
),
diff --git a/lib/src/services/api/mediafiles/upload.service.dart b/lib/src/services/api/mediafiles/upload.service.dart
index 26f3d7e..6826f20 100644
--- a/lib/src/services/api/mediafiles/upload.service.dart
+++ b/lib/src/services/api/mediafiles/upload.service.dart
@@ -16,6 +16,7 @@ import 'package:twonly/src/database/tables/mediafiles.table.dart';
import 'package:twonly/src/database/tables/messages.table.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/model/protobuf/api/http/http_requests.pb.dart';
+import 'package:twonly/src/model/protobuf/client/generated/data.pb.dart';
import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart';
import 'package:twonly/src/services/api/mediafiles/media_background.service.dart';
import 'package:twonly/src/services/api/messages.dart';
@@ -88,8 +89,9 @@ Future initializeMediaUpload(
Future insertMediaFileInMessagesTable(
MediaFileService mediaService,
- List groupIds,
-) async {
+ List groupIds, {
+ AdditionalMessageData? additionalData,
+}) async {
await twonlyDB.mediaFilesDao.updateAllMediaFiles(
const MediaFilesCompanion(
isDraftMedia: Value(false),
@@ -101,6 +103,8 @@ Future insertMediaFileInMessagesTable(
groupId: Value(groupId),
mediaId: Value(mediaService.mediaFile.mediaId),
type: const Value(MessageType.media),
+ additionalMessageData:
+ Value.absentIfNull(additionalData?.writeToBuffer()),
),
);
await twonlyDB.groupsDao.increaseLastMessageExchange(groupId, clock.now());
@@ -245,6 +249,7 @@ Future _createUploadRequest(MediaFileService media) async {
encryptionKey: media.mediaFile.encryptionKey,
encryptionNonce: media.mediaFile.encryptionNonce,
encryptionMac: media.mediaFile.encryptionMac,
+ additionalMessageData: message.additionalMessageData,
),
);
diff --git a/lib/src/services/api/messages.dart b/lib/src/services/api/messages.dart
index 49ee512..6db4af4 100644
--- a/lib/src/services/api/messages.dart
+++ b/lib/src/services/api/messages.dart
@@ -61,6 +61,7 @@ Future<(Uint8List, Uint8List?)?> tryToSendCompleteMessage({
String? receiptId,
Receipt? receipt,
bool onlyReturnEncryptedData = false,
+ bool blocking = true,
}) async {
try {
if (receiptId == null && receipt == null) return null;
@@ -238,12 +239,11 @@ Future sendCipherTextToGroup(
encryptedContent.groupId = groupId;
for (final groupMember in groupMembers) {
- unawaited(
- sendCipherText(
- groupMember.contactId,
- encryptedContent,
- messageId: messageId,
- ),
+ await sendCipherText(
+ groupMember.contactId,
+ encryptedContent,
+ messageId: messageId,
+ blocking: false,
);
}
}
@@ -252,6 +252,7 @@ Future<(Uint8List, Uint8List?)?> sendCipherText(
int contactId,
pb.EncryptedContent encryptedContent, {
bool onlyReturnEncryptedData = false,
+ bool blocking = true,
String? messageId,
}) async {
encryptedContent.senderProfileCounter = Int64(gUser.avatarCounter);
@@ -270,10 +271,15 @@ Future<(Uint8List, Uint8List?)?> sendCipherText(
);
if (receipt != null) {
- return tryToSendCompleteMessage(
+ final tmp = tryToSendCompleteMessage(
receipt: receipt,
onlyReturnEncryptedData: onlyReturnEncryptedData,
+ blocking: blocking,
);
+ if (!blocking) {
+ return null;
+ }
+ return tmp;
}
return null;
}
@@ -302,6 +308,7 @@ Future notifyContactAboutOpeningMessage(
timestamp: Int64(actionAt.millisecondsSinceEpoch),
),
),
+ blocking: false,
);
for (final messageId in messageOtherIds) {
await twonlyDB.messagesDao.updateMessageId(
diff --git a/lib/src/services/intent/links.intent.dart b/lib/src/services/intent/links.intent.dart
index c4a1066..cf4e7fa 100644
--- a/lib/src/services/intent/links.intent.dart
+++ b/lib/src/services/intent/links.intent.dart
@@ -13,7 +13,7 @@ import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
import 'package:twonly/src/services/signal/session.signal.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart';
-import 'package:twonly/src/views/camera/share_image_editor_view.dart';
+import 'package:twonly/src/views/camera/share_image_editor.view.dart';
import 'package:twonly/src/views/chats/add_new_user.view.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/views/contact/contact.view.dart';
@@ -151,6 +151,7 @@ Future handleIntentMediaFile(
Future handleIntentSharedFile(
BuildContext context,
List files,
+ void Function(Uri) onUrlCallBack,
) async {
for (final file in files) {
if (file.value == null) {
@@ -163,7 +164,9 @@ Future handleIntentSharedFile(
switch (file.type) {
case SharedMediaType.URL:
- // await handleIntentUrl(context, Uri.parse(file.value!));
+ if (file.value?.startsWith('http') ?? false) {
+ onUrlCallBack(Uri.parse(file.value!));
+ }
case SharedMediaType.IMAGE:
var type = MediaType.image;
if (file.value!.endsWith('.gif')) {
diff --git a/lib/src/services/mediafiles/mediafile.service.dart b/lib/src/services/mediafiles/mediafile.service.dart
index 2901006..2528ea0 100644
--- a/lib/src/services/mediafiles/mediafile.service.dart
+++ b/lib/src/services/mediafiles/mediafile.service.dart
@@ -24,66 +24,71 @@ class MediaFileService {
}
static Future purgeTempFolder() async {
- final tempDirectory = MediaFileService.buildDirectoryPath(
- 'tmp',
- globalApplicationSupportDirectory,
- );
+ try {
+ final tempDirectory = MediaFileService.buildDirectoryPath(
+ 'tmp',
+ globalApplicationSupportDirectory,
+ );
- final files = tempDirectory.listSync();
- for (final file in files) {
- final mediaId = basename(file.path).split('.').first;
+ final files = tempDirectory.listSync();
+ for (final file in files) {
+ final mediaId = basename(file.path).split('.').first;
- // in case the mediaID is unknown the file will be deleted
- var delete = true;
+ // in case the mediaID is unknown the file will be deleted
+ var delete = true;
- final service = await MediaFileService.fromMediaId(mediaId);
+ final service = await MediaFileService.fromMediaId(mediaId);
- if (service != null) {
- if (service.mediaFile.isDraftMedia) {
- delete = false;
- }
-
- final messages =
- await twonlyDB.messagesDao.getMessagesByMediaId(mediaId);
-
- // in case messages in empty the file will be deleted, as delete is true by default
-
- for (final message in messages) {
- if (service.mediaFile.type == MediaType.audio) {
- delete = false; // do not delete voice messages
- }
-
- if (message.openedAt == null) {
- // Message was not yet opened from all persons, so wait...
+ if (service != null) {
+ if (service.mediaFile.isDraftMedia) {
delete = false;
- } else if (service.mediaFile.requiresAuthentication ||
- service.mediaFile.displayLimitInMilliseconds != null) {
- // Message was opened by all persons, and they can not reopen the image.
- // This branch will prevent to reach the next if condition, with would otherwise store the image for two days
- // delete = true; // do not overwrite a previous delete = false
- // this is just to make it easier to understand :)
- } else if (message.openedAt!
- .isAfter(clock.now().subtract(const Duration(days: 2)))) {
- // In case the image was opened, but send with unlimited time or no authentication.
- if (message.senderId == null) {
- delete = false;
- } else {
- // Check weather the image was send in a group. Then the images is preserved for two days in case another person stores the image.
- // This also allows to reopen this image for two days.
- final group = await twonlyDB.groupsDao.getGroup(message.groupId);
- if (group != null && !group.isDirectChat) {
- delete = false;
- }
+ }
+
+ final messages =
+ await twonlyDB.messagesDao.getMessagesByMediaId(mediaId);
+
+ // in case messages in empty the file will be deleted, as delete is true by default
+
+ for (final message in messages) {
+ if (service.mediaFile.type == MediaType.audio) {
+ delete = false; // do not delete voice messages
+ }
+
+ if (message.openedAt == null) {
+ // Message was not yet opened from all persons, so wait...
+ delete = false;
+ } else if (service.mediaFile.requiresAuthentication ||
+ service.mediaFile.displayLimitInMilliseconds != null) {
+ // Message was opened by all persons, and they can not reopen the image.
+ // This branch will prevent to reach the next if condition, with would otherwise store the image for two days
+ // delete = true; // do not overwrite a previous delete = false
+ // this is just to make it easier to understand :)
+ } else if (message.openedAt!
+ .isAfter(clock.now().subtract(const Duration(days: 2)))) {
+ // In case the image was opened, but send with unlimited time or no authentication.
+ if (message.senderId == null) {
+ delete = false;
+ } else {
+ // Check weather the image was send in a group. Then the images is preserved for two days in case another person stores the image.
+ // This also allows to reopen this image for two days.
+ final group =
+ await twonlyDB.groupsDao.getGroup(message.groupId);
+ if (group != null && !group.isDirectChat) {
+ delete = false;
+ }
+ }
+ // In case the app was send in a direct chat, then it can be deleted.
}
- // In case the app was send in a direct chat, then it can be deleted.
}
}
- }
- if (delete) {
- Log.info('Purging media file $mediaId');
- file.deleteSync();
+ if (delete) {
+ Log.info('Purging media file $mediaId');
+ file.deleteSync();
+ }
}
+ } catch (e) {
+ Log.error(e);
}
}
diff --git a/lib/src/services/notifications/background.notifications.dart b/lib/src/services/notifications/background.notifications.dart
index 4c652d2..f7eaacc 100644
--- a/lib/src/services/notifications/background.notifications.dart
+++ b/lib/src/services/notifications/background.notifications.dart
@@ -99,9 +99,10 @@ Future handlePushData(String pushDataB64) async {
}
} catch (e) {
Log.error(e);
+ final lang = getLocalizations();
await customLocalPushNotification(
- 'Du hast eine neue Nachricht.',
- 'Öffne twonly um mehr zu erfahren.',
+ lang.notificationTitleUnknown,
+ lang.notificationBodyUnknown,
);
}
}
@@ -186,16 +187,14 @@ Future showLocalPushNotification(
Future showLocalPushNotificationWithoutUserId(
PushNotification pushNotification,
) async {
- String? body;
-
- body = getPushNotificationText(pushNotification);
-
final lang = getLocalizations();
- final title = lang.notificationTitleUnknownUser;
+ var title = lang.notificationTitleUnknown;
+ var body = lang.notificationBodyUnknown;
- if (body == '') {
- Log.error('No push notification type defined!');
+ if (pushNotification.kind == PushKind.contactRequest) {
+ title = lang.you;
+ body = lang.notificationContactRequestUnknownUser;
}
final androidNotificationDetails = AndroidNotificationDetails(
diff --git a/lib/src/utils/keyvalue.dart b/lib/src/utils/keyvalue.dart
index 05e5639..e52274d 100644
--- a/lib/src/utils/keyvalue.dart
+++ b/lib/src/utils/keyvalue.dart
@@ -4,38 +4,41 @@ import 'package:path_provider/path_provider.dart';
import 'package:twonly/src/utils/log.dart';
class KeyValueStore {
- static Future _getFilePath(String key) async {
+ static Future