From 2f3f927914c4eeee7e88d4da78534f446db7d185 Mon Sep 17 00:00:00 2001 From: otsmr Date: Sun, 19 Oct 2025 14:44:49 +0200 Subject: [PATCH] handle text and media server messages, update pushkeys --- .../push_notification.pb.swift | 20 +- lib/src/constants/secure_storage_keys.dart | 4 +- lib/src/database/daos/contacts.dao.dart | 5 +- lib/src/database/daos/groups.dao.dart | 14 +- lib/src/database/daos/mediafiles.dao.dart | 54 ++ lib/src/database/daos/mediafiles.dao.g.dart | 8 + lib/src/database/daos/messages.dao.dart | 74 +-- lib/src/database/daos/messages.dao.g.dart | 1 + lib/src/database/daos/reactions.dao.dart | 12 +- lib/src/database/daos/receipts.dao.dart | 45 +- lib/src/database/tables/contacts.table.dart | 1 - lib/src/database/tables/groups.table.dart | 1 + lib/src/database/tables/mediafiles.table.dart | 23 +- lib/src/database/tables/messages.table.dart | 9 +- lib/src/database/tables/receipts.table.dart | 3 + lib/src/database/twonly.db.dart | 4 +- lib/src/database/twonly.db.g.dart | 460 +++++++++++------- .../client/generated/messages.pb.dart | 142 ++++-- .../client/generated/messages.pbenum.dart | 10 +- .../client/generated/messages.pbjson.dart | 117 +++-- .../generated/push_notification.pb.dart | 16 +- .../generated/push_notification.pbjson.dart | 8 +- lib/src/model/protobuf/client/messages.proto | 29 +- .../protobuf/client/push_notification.proto | 4 +- lib/src/services/api.service.dart | 2 +- lib/src/services/api/media_download.dart | 2 +- lib/src/services/api/messages.dart | 287 +++++------ lib/src/services/api/server_messages.dart | 6 +- .../contact.server_messages.dart | 14 +- .../media.server_messages.dart | 230 +++++---- .../messages.server_messages.dart | 15 +- .../pushkeys.server_messages.dart | 3 + .../reaction.server_message.dart | 2 + .../text_message.server_messages.dart | 141 +----- .../background.notifications.dart | 2 +- .../notifications/pushkeys.notifications.dart | 143 ++++-- .../services/signal/encryption.signal.dart | 14 +- lib/src/services/thumbnail.service.dart | 14 + lib/src/utils/misc.dart | 6 + lib/src/views/settings/notification.view.dart | 9 +- test/unit_test.dart | 8 + 41 files changed, 1172 insertions(+), 790 deletions(-) create mode 100644 lib/src/database/daos/mediafiles.dao.dart create mode 100644 lib/src/database/daos/mediafiles.dao.g.dart diff --git a/ios/NotificationService/push_notification.pb.swift b/ios/NotificationService/push_notification.pb.swift index 8bdc778..3bddafc 100644 --- a/ios/NotificationService/push_notification.pb.swift +++ b/ios/NotificationService/push_notification.pb.swift @@ -128,8 +128,8 @@ struct PushNotification: Sendable { var kind: PushKind = .reaction - var messageID: Int64 { - get {return _messageID ?? 0} + var messageID: String { + get {return _messageID ?? String()} set {_messageID = newValue} } /// Returns true if `messageID` has been explicitly set. @@ -150,7 +150,7 @@ struct PushNotification: Sendable { init() {} - fileprivate var _messageID: Int64? = nil + fileprivate var _messageID: String? = nil fileprivate var _reactionContent: String? = nil } @@ -177,8 +177,8 @@ struct PushUser: Sendable { var blocked: Bool = false - var lastMessageID: Int64 { - get {return _lastMessageID ?? 0} + var lastMessageID: String { + get {return _lastMessageID ?? String()} set {_lastMessageID = newValue} } /// Returns true if `lastMessageID` has been explicitly set. @@ -192,7 +192,7 @@ struct PushUser: Sendable { init() {} - fileprivate var _lastMessageID: Int64? = nil + fileprivate var _lastMessageID: String? = nil } struct PushKey: Sendable { @@ -273,7 +273,7 @@ extension PushNotification: SwiftProtobuf.Message, SwiftProtobuf._MessageImpleme // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularEnumField(value: &self.kind) }() - case 2: try { try decoder.decodeSingularInt64Field(value: &self._messageID) }() + case 2: try { try decoder.decodeSingularStringField(value: &self._messageID) }() case 3: try { try decoder.decodeSingularStringField(value: &self._reactionContent) }() default: break } @@ -289,7 +289,7 @@ extension PushNotification: SwiftProtobuf.Message, SwiftProtobuf._MessageImpleme try visitor.visitSingularEnumField(value: self.kind, fieldNumber: 1) } try { if let v = self._messageID { - try visitor.visitSingularInt64Field(value: v, fieldNumber: 2) + try visitor.visitSingularStringField(value: v, fieldNumber: 2) } }() try { if let v = self._reactionContent { try visitor.visitSingularStringField(value: v, fieldNumber: 3) @@ -349,7 +349,7 @@ extension PushUser: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB case 1: try { try decoder.decodeSingularInt64Field(value: &self.userID) }() case 2: try { try decoder.decodeSingularStringField(value: &self.displayName) }() case 3: try { try decoder.decodeSingularBoolField(value: &self.blocked) }() - case 4: try { try decoder.decodeSingularInt64Field(value: &self._lastMessageID) }() + case 4: try { try decoder.decodeSingularStringField(value: &self._lastMessageID) }() case 5: try { try decoder.decodeRepeatedMessageField(value: &self.pushKeys) }() default: break } @@ -371,7 +371,7 @@ extension PushUser: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB try visitor.visitSingularBoolField(value: self.blocked, fieldNumber: 3) } try { if let v = self._lastMessageID { - try visitor.visitSingularInt64Field(value: v, fieldNumber: 4) + try visitor.visitSingularStringField(value: v, fieldNumber: 4) } }() if !self.pushKeys.isEmpty { try visitor.visitRepeatedMessageField(value: self.pushKeys, fieldNumber: 5) diff --git a/lib/src/constants/secure_storage_keys.dart b/lib/src/constants/secure_storage_keys.dart index 8e2eac5..43da069 100644 --- a/lib/src/constants/secure_storage_keys.dart +++ b/lib/src/constants/secure_storage_keys.dart @@ -6,6 +6,6 @@ class SecureStorageKeys { static const String userData = 'userData'; static const String twonlySafeLastBackupHash = 'twonly_safe_last_backup_hash'; - static const String receivingPushKeys = 'receiving_push_keys'; - static const String sendingPushKeys = 'sending_push_keys'; + static const String receivingPushKeys = 'push_keys_receiving'; + static const String sendingPushKeys = 'push_keys_sending'; } diff --git a/lib/src/database/daos/contacts.dao.dart b/lib/src/database/daos/contacts.dao.dart index 9050ee0..54e70ab 100644 --- a/lib/src/database/daos/contacts.dao.dart +++ b/lib/src/database/daos/contacts.dao.dart @@ -120,10 +120,7 @@ class ContactsDao extends DatabaseAccessor with _$ContactsDaoMixin { Stream> watchNotAcceptedContacts() { return (select(contacts) ..where( - (t) => - t.accepted.equals(false) & - t.archived.equals(false) & - t.blocked.equals(false), + (t) => t.accepted.equals(false) & t.blocked.equals(false), )) .watch(); // return (select(contacts)).watch(); diff --git a/lib/src/database/daos/groups.dao.dart b/lib/src/database/daos/groups.dao.dart index 6c9536a..b004215 100644 --- a/lib/src/database/daos/groups.dao.dart +++ b/lib/src/database/daos/groups.dao.dart @@ -12,10 +12,18 @@ class GroupsDao extends DatabaseAccessor with _$GroupsDaoMixin { GroupsDao(super.db); Future isContactInGroup(int contactId, String groupId) async { - final entry = await (select(groupMembers) - ..where( - (t) => t.contactId.equals(contactId) & t.groupId.equals(groupId))) + final entry = await (select(groupMembers)..where( + // ignore: require_trailing_commas + (t) => t.contactId.equals(contactId) & t.groupId.equals(groupId))) .getSingleOrNull(); return entry != null; } + + Future updateGroup( + String groupId, + GroupsCompanion updates, + ) async { + await (update(groups)..where((c) => c.groupId.equals(groupId))) + .write(updates); + } } diff --git a/lib/src/database/daos/mediafiles.dao.dart b/lib/src/database/daos/mediafiles.dao.dart new file mode 100644 index 0000000..057f59e --- /dev/null +++ b/lib/src/database/daos/mediafiles.dao.dart @@ -0,0 +1,54 @@ +import 'package:drift/drift.dart'; +import 'package:twonly/src/database/tables/mediafiles.table.dart'; +import 'package:twonly/src/database/twonly.db.dart'; +import 'package:twonly/src/utils/log.dart'; + +part 'mediafiles.dao.g.dart'; + +@DriftAccessor(tables: [MediaFiles]) +class MediaFilesDao extends DatabaseAccessor + with _$MediaFilesDaoMixin { + // this constructor is required so that the main database can create an instance + // of this object. + // ignore: matching_super_parameters + MediaFilesDao(super.db); + + Future insertMedia(MediaFilesCompanion mediaFile) async { + try { + final rowId = await into(mediaFiles).insert(mediaFile); + + return await (select(mediaFiles)..where((t) => t.rowId.equals(rowId))) + .getSingle(); + } catch (e) { + Log.error('Could not insert media file: $e'); + return null; + } + } + + Future updateMedia( + String mediaId, + MediaFilesCompanion updates, + ) async { + await (update(mediaFiles)..where((c) => c.mediaId.equals(mediaId))) + .write(updates); + } + + Future getMediaFileById(String mediaId) async { + return (select(mediaFiles)..where((t) => t.mediaId.equals(mediaId))) + .getSingleOrNull(); + } + + Future resetPendingDownloadState() async { + await (update(mediaFiles) + ..where( + (c) => c.downloadState.equals( + DownloadState.downloading.name, + ), + )) + .write( + const MediaFilesCompanion( + downloadState: Value(DownloadState.pending), + ), + ); + } +} diff --git a/lib/src/database/daos/mediafiles.dao.g.dart b/lib/src/database/daos/mediafiles.dao.g.dart new file mode 100644 index 0000000..0157e2d --- /dev/null +++ b/lib/src/database/daos/mediafiles.dao.g.dart @@ -0,0 +1,8 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'mediafiles.dao.dart'; + +// ignore_for_file: type=lint +mixin _$MediaFilesDaoMixin on DatabaseAccessor { + $MediaFilesTable get mediaFiles => attachedDatabase.mediaFiles; +} diff --git a/lib/src/database/daos/messages.dao.dart b/lib/src/database/daos/messages.dao.dart index 1244086..b96904e 100644 --- a/lib/src/database/daos/messages.dao.dart +++ b/lib/src/database/daos/messages.dao.dart @@ -1,13 +1,24 @@ import 'package:drift/drift.dart'; +import 'package:twonly/globals.dart'; import 'package:twonly/src/database/tables/contacts.table.dart'; +import 'package:twonly/src/database/tables/groups.table.dart'; import 'package:twonly/src/database/tables/mediafiles.table.dart'; import 'package:twonly/src/database/tables/messages.table.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/services/mediafile.service.dart'; +import 'package:twonly/src/utils/log.dart'; part 'messages.dao.g.dart'; -@DriftAccessor(tables: [Messages, Contacts, MediaFiles, MessageHistories]) +@DriftAccessor( + tables: [ + Messages, + Contacts, + MediaFiles, + MessageHistories, + Groups, + ], +) class MessagesDao extends DatabaseAccessor with _$MessagesDaoMixin { // this constructor is required so that the main database can create an instance // of this object. @@ -156,22 +167,6 @@ class MessagesDao extends DatabaseAccessor with _$MessagesDaoMixin { // .write(updates); // } - // Future resetPendingDownloadState() { - // // All media files in the downloading state are reset to the pending state - // // When the app is used in mobile network, they will not be downloaded at the start - // // if they are not yet downloaded... - // const updates = - // MessagesCompanion(downloadState: Value(DownloadState.pending)); - // return (update(messages) - // ..where( - // (t) => - // t.messageOtherId.isNotNull() & - // t.downloadState.equals(DownloadState.downloading.index) & - // t.kind.equals(MessageKind.media.name), - // )) - // .write(updates); - // } - Future handleMessageDeletion( int contactId, String messageId, @@ -278,28 +273,33 @@ class MessagesDao extends DatabaseAccessor with _$MessagesDaoMixin { // .write(updatedValues); // } - // Future updateMessageByMessageId( - // int messageId, - // MessagesCompanion updatedValues, - // ) { - // return (update(messages)..where((c) => c.messageId.equals(messageId))) - // .write(updatedValues); - // } + Future updateMessageId( + String messageId, + MessagesCompanion updatedValues, + ) { + return (update(messages)..where((c) => c.messageId.equals(messageId))) + .write(updatedValues); + } - // Future insertMessage(MessagesCompanion message) async { - // try { - // await (update(contacts) - // ..where( - // (c) => c.userId.equals(message.contactId.value), - // )) - // .write(ContactsCompanion(lastMessageExchange: Value(DateTime.now()))); + Future insertMessage(MessagesCompanion message) async { + try { + final rowId = await into(messages).insert(message); - // return await into(messages).insert(message); - // } catch (e) { - // Log.error('Error while inserting message: $e'); - // return null; - // } - // } + await twonlyDB.groupsDao.updateGroup( + message.groupId.value, + GroupsCompanion( + lastMessageExchange: Value(DateTime.now()), + archived: const Value(false), + ), + ); + + return await (select(messages)..where((t) => t.rowId.equals(rowId))) + .getSingle(); + } catch (e) { + Log.error('Could not insert message: $e'); + return null; + } + } // Future deleteMessagesByContactId(int contactId) { // return (delete(messages) diff --git a/lib/src/database/daos/messages.dao.g.dart b/lib/src/database/daos/messages.dao.g.dart index bad5c9e..5f11d3a 100644 --- a/lib/src/database/daos/messages.dao.g.dart +++ b/lib/src/database/daos/messages.dao.g.dart @@ -9,4 +9,5 @@ mixin _$MessagesDaoMixin on DatabaseAccessor { $MessagesTable get messages => attachedDatabase.messages; $MessageHistoriesTable get messageHistories => attachedDatabase.messageHistories; + $GroupsTable get groups => attachedDatabase.groups; } diff --git a/lib/src/database/daos/reactions.dao.dart b/lib/src/database/daos/reactions.dao.dart index 65eb24f..1325d30 100644 --- a/lib/src/database/daos/reactions.dao.dart +++ b/lib/src/database/daos/reactions.dao.dart @@ -31,11 +31,13 @@ class ReactionsDao extends DatabaseAccessor with _$ReactionsDaoMixin { )) .go(); if (emoji != null) { - await into(reactions).insert(ReactionsCompanion( - messageId: Value(messageId), - emoji: Value(emoji), - senderId: Value(contactId), - )); + await into(reactions).insert( + ReactionsCompanion( + messageId: Value(messageId), + emoji: Value(emoji), + senderId: Value(contactId), + ), + ); } } catch (e) { Log.error(e); diff --git a/lib/src/database/daos/receipts.dao.dart b/lib/src/database/daos/receipts.dao.dart index cf2193e..df65eb5 100644 --- a/lib/src/database/daos/receipts.dao.dart +++ b/lib/src/database/daos/receipts.dao.dart @@ -15,8 +15,10 @@ class ReceiptsDao extends DatabaseAccessor with _$ReceiptsDaoMixin { Future confirmReceipt(String receiptId, int fromUserId) async { final receipt = await (select(receipts) - ..where((t) => - t.receiptId.equals(receiptId) & t.contactId.equals(fromUserId))) + ..where( + (t) => + t.receiptId.equals(receiptId) & t.contactId.equals(fromUserId), + )) .getSingleOrNull(); if (receipt == null) return; @@ -26,7 +28,7 @@ class ReceiptsDao extends DatabaseAccessor with _$ReceiptsDaoMixin { ..where((t) => t.messageId.equals(receipt.messageId!))) .write( const MessagesCompanion( - acknowledgeByUser: Value(true), + ackByUser: Value(true), ), ); } @@ -39,6 +41,14 @@ class ReceiptsDao extends DatabaseAccessor with _$ReceiptsDaoMixin { .go(); } + Future deleteReceipt(String receiptId) async { + await (delete(receipts) + ..where( + (t) => t.receiptId.equals(receiptId), + )) + .go(); + } + Future insertReceipt(ReceiptsCompanion entry) async { try { final id = await into(receipts).insert(entry); @@ -49,4 +59,33 @@ class ReceiptsDao extends DatabaseAccessor with _$ReceiptsDaoMixin { return null; } } + + Future getReceiptById(String receiptId) async { + try { + return await (select(receipts) + ..where( + (t) => t.receiptId.equals(receiptId), + )) + .getSingleOrNull(); + } catch (e) { + Log.error(e); + return null; + } + } + + Future> getReceiptsNotAckByServer() async { + return (select(receipts) + ..where( + (t) => t.ackByServerAt.isNull(), + )) + .get(); + } + + Future updateReceipt( + String receiptId, + ReceiptsCompanion updates, + ) async { + await (update(receipts)..where((c) => c.receiptId.equals(receiptId))) + .write(updates); + } } diff --git a/lib/src/database/tables/contacts.table.dart b/lib/src/database/tables/contacts.table.dart index 0f9e2b0..0aa40c0 100644 --- a/lib/src/database/tables/contacts.table.dart +++ b/lib/src/database/tables/contacts.table.dart @@ -16,7 +16,6 @@ class Contacts extends Table { BoolColumn get hidden => boolean().withDefault(const Constant(false))(); BoolColumn get blocked => boolean().withDefault(const Constant(false))(); BoolColumn get verified => boolean().withDefault(const Constant(false))(); - BoolColumn get archived => boolean().withDefault(const Constant(false))(); BoolColumn get deleted => boolean().withDefault(const Constant(false))(); BoolColumn get alsoBestFriend => diff --git a/lib/src/database/tables/groups.table.dart b/lib/src/database/tables/groups.table.dart index 08148ae..e6548e4 100644 --- a/lib/src/database/tables/groups.table.dart +++ b/lib/src/database/tables/groups.table.dart @@ -9,6 +9,7 @@ class Groups extends Table { BoolColumn get isGroupAdmin => boolean()(); BoolColumn get isGroupOfTwo => boolean()(); BoolColumn get pinned => boolean().withDefault(const Constant(false))(); + BoolColumn get archived => boolean().withDefault(const Constant(false))(); DateTimeColumn get lastMessageExchange => dateTime().withDefault(currentDateAndTime)(); diff --git a/lib/src/database/tables/mediafiles.table.dart b/lib/src/database/tables/mediafiles.table.dart index 24edcd4..db4a812 100644 --- a/lib/src/database/tables/mediafiles.table.dart +++ b/lib/src/database/tables/mediafiles.table.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:drift/drift.dart'; import 'package:hashlib/random.dart'; @@ -14,13 +16,11 @@ enum UploadState { receiverNotified, } -enum DownloadState { - pending, -} +enum DownloadState { pending, downloading } @DataClassName('MediaFile') class MediaFiles extends Table { - TextColumn get mediaId => text().clientDefault(() => uuid.v4())(); + TextColumn get mediaId => text().clientDefault(() => uuid.v7())(); TextColumn get type => textEnum()(); @@ -34,6 +34,9 @@ class MediaFiles extends Table { BoolColumn get storedByContact => boolean().withDefault(const Constant(false))(); + TextColumn get reuploadRequestedBy => + text().map(IntListTypeConverter()).nullable()(); + IntColumn get displayLimitInMilliseconds => integer().nullable()(); BlobColumn get downloadToken => blob().nullable()(); @@ -46,3 +49,15 @@ class MediaFiles extends Table { @override Set get primaryKey => {mediaId}; } + +class IntListTypeConverter extends TypeConverter, String> { + @override + List fromSql(String fromDb) { + return List.from(jsonDecode(fromDb) as Iterable); + } + + @override + String toSql(List value) { + return json.encode(value); + } +} diff --git a/lib/src/database/tables/messages.table.dart b/lib/src/database/tables/messages.table.dart index 2e33471..3537c63 100644 --- a/lib/src/database/tables/messages.table.dart +++ b/lib/src/database/tables/messages.table.dart @@ -1,11 +1,12 @@ import 'package:drift/drift.dart'; +import 'package:hashlib/random.dart'; import 'package:twonly/src/database/tables/contacts.table.dart'; import 'package:twonly/src/database/tables/mediafiles.table.dart'; @DataClassName('Message') class Messages extends Table { TextColumn get groupId => text()(); - TextColumn get messageId => text()(); + TextColumn get messageId => text().clientDefault(() => uuid.v7())(); // in case senderId is null, it was send by user itself IntColumn get senderId => @@ -23,10 +24,8 @@ class Messages extends Table { BoolColumn get isEdited => boolean().withDefault(const Constant(false))(); - BoolColumn get acknowledgeByUser => - boolean().withDefault(const Constant(false))(); - BoolColumn get acknowledgeByServer => - boolean().withDefault(const Constant(false))(); + BoolColumn get ackByUser => boolean().withDefault(const Constant(false))(); + BoolColumn get ackByServer => boolean().withDefault(const Constant(false))(); IntColumn get openedByCounter => integer().withDefault(const Constant(0))(); DateTimeColumn get openedAt => dateTime().nullable()(); diff --git a/lib/src/database/tables/receipts.table.dart b/lib/src/database/tables/receipts.table.dart index 3ccf85e..c0fa4e6 100644 --- a/lib/src/database/tables/receipts.table.dart +++ b/lib/src/database/tables/receipts.table.dart @@ -15,11 +15,14 @@ class Receipts extends Table { .nullable() .references(Messages, #messageId, onDelete: KeyAction.cascade)(); + /// This is the protobuf 'Message' BlobColumn get message => blob()(); BoolColumn get contactWillSendsReceipt => boolean().withDefault(const Constant(true))(); + DateTimeColumn get ackByServerAt => dateTime().nullable()(); + IntColumn get retryCount => integer().withDefault(const Constant(0))(); DateTimeColumn get lastRetry => dateTime().nullable()(); diff --git a/lib/src/database/twonly.db.dart b/lib/src/database/twonly.db.dart index d4f21f0..1594ce8 100644 --- a/lib/src/database/twonly.db.dart +++ b/lib/src/database/twonly.db.dart @@ -4,6 +4,7 @@ import 'package:drift_flutter/drift_flutter.dart' import 'package:path_provider/path_provider.dart'; import 'package:twonly/src/database/daos/contacts.dao.dart'; import 'package:twonly/src/database/daos/groups.dao.dart'; +import 'package:twonly/src/database/daos/mediafiles.dao.dart'; import 'package:twonly/src/database/daos/messages.dao.dart'; import 'package:twonly/src/database/daos/reactions.dao.dart'; import 'package:twonly/src/database/daos/receipts.dao.dart'; @@ -48,7 +49,8 @@ part 'twonly.db.g.dart'; SignalDao, ReceiptsDao, GroupsDao, - ReactionsDao + ReactionsDao, + MediaFilesDao, ], ) class TwonlyDB extends _$TwonlyDB { diff --git a/lib/src/database/twonly.db.g.dart b/lib/src/database/twonly.db.g.dart index 8238265..472e56a 100644 --- a/lib/src/database/twonly.db.g.dart +++ b/lib/src/database/twonly.db.g.dart @@ -94,16 +94,6 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { defaultConstraints: GeneratedColumn.constraintIsAlways('CHECK ("verified" IN (0, 1))'), defaultValue: const Constant(false)); - static const VerificationMeta _archivedMeta = - const VerificationMeta('archived'); - @override - late final GeneratedColumn archived = GeneratedColumn( - 'archived', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("archived" IN (0, 1))'), - defaultValue: const Constant(false)); static const VerificationMeta _deletedMeta = const VerificationMeta('deleted'); @override @@ -194,7 +184,6 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { hidden, blocked, verified, - archived, deleted, alsoBestFriend, deleteMessagesAfterXMinutes, @@ -266,10 +255,6 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { context.handle(_verifiedMeta, verified.isAcceptableOrUnknown(data['verified']!, _verifiedMeta)); } - if (data.containsKey('archived')) { - context.handle(_archivedMeta, - archived.isAcceptableOrUnknown(data['archived']!, _archivedMeta)); - } if (data.containsKey('deleted')) { context.handle(_deletedMeta, deleted.isAcceptableOrUnknown(data['deleted']!, _deletedMeta)); @@ -358,8 +343,6 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> { .read(DriftSqlType.bool, data['${effectivePrefix}blocked'])!, verified: attachedDatabase.typeMapping .read(DriftSqlType.bool, data['${effectivePrefix}verified'])!, - archived: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}archived'])!, deleted: attachedDatabase.typeMapping .read(DriftSqlType.bool, data['${effectivePrefix}deleted'])!, alsoBestFriend: attachedDatabase.typeMapping @@ -404,7 +387,6 @@ class Contact extends DataClass implements Insertable { final bool hidden; final bool blocked; final bool verified; - final bool archived; final bool deleted; final bool alsoBestFriend; final int deleteMessagesAfterXMinutes; @@ -427,7 +409,6 @@ class Contact extends DataClass implements Insertable { required this.hidden, required this.blocked, required this.verified, - required this.archived, required this.deleted, required this.alsoBestFriend, required this.deleteMessagesAfterXMinutes, @@ -458,7 +439,6 @@ class Contact extends DataClass implements Insertable { map['hidden'] = Variable(hidden); map['blocked'] = Variable(blocked); map['verified'] = Variable(verified); - map['archived'] = Variable(archived); map['deleted'] = Variable(deleted); map['also_best_friend'] = Variable(alsoBestFriend); map['delete_messages_after_x_minutes'] = @@ -501,7 +481,6 @@ class Contact extends DataClass implements Insertable { hidden: Value(hidden), blocked: Value(blocked), verified: Value(verified), - archived: Value(archived), deleted: Value(deleted), alsoBestFriend: Value(alsoBestFriend), deleteMessagesAfterXMinutes: Value(deleteMessagesAfterXMinutes), @@ -539,7 +518,6 @@ class Contact extends DataClass implements Insertable { hidden: serializer.fromJson(json['hidden']), blocked: serializer.fromJson(json['blocked']), verified: serializer.fromJson(json['verified']), - archived: serializer.fromJson(json['archived']), deleted: serializer.fromJson(json['deleted']), alsoBestFriend: serializer.fromJson(json['alsoBestFriend']), deleteMessagesAfterXMinutes: @@ -570,7 +548,6 @@ class Contact extends DataClass implements Insertable { 'hidden': serializer.toJson(hidden), 'blocked': serializer.toJson(blocked), 'verified': serializer.toJson(verified), - 'archived': serializer.toJson(archived), 'deleted': serializer.toJson(deleted), 'alsoBestFriend': serializer.toJson(alsoBestFriend), 'deleteMessagesAfterXMinutes': @@ -598,7 +575,6 @@ class Contact extends DataClass implements Insertable { bool? hidden, bool? blocked, bool? verified, - bool? archived, bool? deleted, bool? alsoBestFriend, int? deleteMessagesAfterXMinutes, @@ -621,7 +597,6 @@ class Contact extends DataClass implements Insertable { hidden: hidden ?? this.hidden, blocked: blocked ?? this.blocked, verified: verified ?? this.verified, - archived: archived ?? this.archived, deleted: deleted ?? this.deleted, alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, deleteMessagesAfterXMinutes: @@ -657,7 +632,6 @@ class Contact extends DataClass implements Insertable { hidden: data.hidden.present ? data.hidden.value : this.hidden, blocked: data.blocked.present ? data.blocked.value : this.blocked, verified: data.verified.present ? data.verified.value : this.verified, - archived: data.archived.present ? data.archived.value : this.archived, deleted: data.deleted.present ? data.deleted.value : this.deleted, alsoBestFriend: data.alsoBestFriend.present ? data.alsoBestFriend.value @@ -701,7 +675,6 @@ class Contact extends DataClass implements Insertable { ..write('hidden: $hidden, ') ..write('blocked: $blocked, ') ..write('verified: $verified, ') - ..write('archived: $archived, ') ..write('deleted: $deleted, ') ..write('alsoBestFriend: $alsoBestFriend, ') ..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ') @@ -729,7 +702,6 @@ class Contact extends DataClass implements Insertable { hidden, blocked, verified, - archived, deleted, alsoBestFriend, deleteMessagesAfterXMinutes, @@ -756,7 +728,6 @@ class Contact extends DataClass implements Insertable { other.hidden == this.hidden && other.blocked == this.blocked && other.verified == this.verified && - other.archived == this.archived && other.deleted == this.deleted && other.alsoBestFriend == this.alsoBestFriend && other.deleteMessagesAfterXMinutes == @@ -782,7 +753,6 @@ class ContactsCompanion extends UpdateCompanion { final Value hidden; final Value blocked; final Value verified; - final Value archived; final Value deleted; final Value alsoBestFriend; final Value deleteMessagesAfterXMinutes; @@ -805,7 +775,6 @@ class ContactsCompanion extends UpdateCompanion { this.hidden = const Value.absent(), this.blocked = const Value.absent(), this.verified = const Value.absent(), - this.archived = const Value.absent(), this.deleted = const Value.absent(), this.alsoBestFriend = const Value.absent(), this.deleteMessagesAfterXMinutes = const Value.absent(), @@ -829,7 +798,6 @@ class ContactsCompanion extends UpdateCompanion { this.hidden = const Value.absent(), this.blocked = const Value.absent(), this.verified = const Value.absent(), - this.archived = const Value.absent(), this.deleted = const Value.absent(), this.alsoBestFriend = const Value.absent(), this.deleteMessagesAfterXMinutes = const Value.absent(), @@ -853,7 +821,6 @@ class ContactsCompanion extends UpdateCompanion { Expression? hidden, Expression? blocked, Expression? verified, - Expression? archived, Expression? deleted, Expression? alsoBestFriend, Expression? deleteMessagesAfterXMinutes, @@ -878,7 +845,6 @@ class ContactsCompanion extends UpdateCompanion { if (hidden != null) 'hidden': hidden, if (blocked != null) 'blocked': blocked, if (verified != null) 'verified': verified, - if (archived != null) 'archived': archived, if (deleted != null) 'deleted': deleted, if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend, if (deleteMessagesAfterXMinutes != null) @@ -907,7 +873,6 @@ class ContactsCompanion extends UpdateCompanion { Value? hidden, Value? blocked, Value? verified, - Value? archived, Value? deleted, Value? alsoBestFriend, Value? deleteMessagesAfterXMinutes, @@ -930,7 +895,6 @@ class ContactsCompanion extends UpdateCompanion { hidden: hidden ?? this.hidden, blocked: blocked ?? this.blocked, verified: verified ?? this.verified, - archived: archived ?? this.archived, deleted: deleted ?? this.deleted, alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, deleteMessagesAfterXMinutes: @@ -982,9 +946,6 @@ class ContactsCompanion extends UpdateCompanion { if (verified.present) { map['verified'] = Variable(verified.value); } - if (archived.present) { - map['archived'] = Variable(archived.value); - } if (deleted.present) { map['deleted'] = Variable(deleted.value); } @@ -1035,7 +996,6 @@ class ContactsCompanion extends UpdateCompanion { ..write('hidden: $hidden, ') ..write('blocked: $blocked, ') ..write('verified: $verified, ') - ..write('archived: $archived, ') ..write('deleted: $deleted, ') ..write('alsoBestFriend: $alsoBestFriend, ') ..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ') @@ -1064,7 +1024,7 @@ class $MediaFilesTable extends MediaFiles 'media_id', aliasedName, false, type: DriftSqlType.string, requiredDuringInsert: false, - clientDefault: () => uuid.v4()); + clientDefault: () => uuid.v7()); @override late final GeneratedColumnWithTypeConverter type = GeneratedColumn('type', aliasedName, false, @@ -1111,6 +1071,13 @@ class $MediaFilesTable extends MediaFiles defaultConstraints: GeneratedColumn.constraintIsAlways( 'CHECK ("stored_by_contact" IN (0, 1))'), defaultValue: const Constant(false)); + @override + late final GeneratedColumnWithTypeConverter?, String> + reuploadRequestedBy = GeneratedColumn( + 'reupload_requested_by', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false) + .withConverter?>( + $MediaFilesTable.$converterreuploadRequestedByn); static const VerificationMeta _displayLimitInMillisecondsMeta = const VerificationMeta('displayLimitInMilliseconds'); @override @@ -1158,6 +1125,7 @@ class $MediaFilesTable extends MediaFiles requiresAuthentication, reopenByContact, storedByContact, + reuploadRequestedBy, displayLimitInMilliseconds, downloadToken, encryptionKey, @@ -1260,6 +1228,9 @@ class $MediaFilesTable extends MediaFiles DriftSqlType.bool, data['${effectivePrefix}reopen_by_contact'])!, storedByContact: attachedDatabase.typeMapping.read( DriftSqlType.bool, data['${effectivePrefix}stored_by_contact'])!, + reuploadRequestedBy: $MediaFilesTable.$converterreuploadRequestedByn + .fromSql(attachedDatabase.typeMapping.read(DriftSqlType.string, + data['${effectivePrefix}reupload_requested_by'])), displayLimitInMilliseconds: attachedDatabase.typeMapping.read( DriftSqlType.int, data['${effectivePrefix}display_limit_in_milliseconds']), @@ -1294,6 +1265,10 @@ class $MediaFilesTable extends MediaFiles static JsonTypeConverter2 $converterdownloadStaten = JsonTypeConverter2.asNullable($converterdownloadState); + static TypeConverter, String> $converterreuploadRequestedBy = + IntListTypeConverter(); + static TypeConverter?, String?> $converterreuploadRequestedByn = + NullAwareTypeConverter.wrap($converterreuploadRequestedBy); } class MediaFile extends DataClass implements Insertable { @@ -1304,6 +1279,7 @@ class MediaFile extends DataClass implements Insertable { final bool requiresAuthentication; final bool reopenByContact; final bool storedByContact; + final List? reuploadRequestedBy; final int? displayLimitInMilliseconds; final Uint8List? downloadToken; final Uint8List? encryptionKey; @@ -1318,6 +1294,7 @@ class MediaFile extends DataClass implements Insertable { required this.requiresAuthentication, required this.reopenByContact, required this.storedByContact, + this.reuploadRequestedBy, this.displayLimitInMilliseconds, this.downloadToken, this.encryptionKey, @@ -1343,6 +1320,11 @@ class MediaFile extends DataClass implements Insertable { map['requires_authentication'] = Variable(requiresAuthentication); map['reopen_by_contact'] = Variable(reopenByContact); map['stored_by_contact'] = Variable(storedByContact); + if (!nullToAbsent || reuploadRequestedBy != null) { + map['reupload_requested_by'] = Variable($MediaFilesTable + .$converterreuploadRequestedByn + .toSql(reuploadRequestedBy)); + } if (!nullToAbsent || displayLimitInMilliseconds != null) { map['display_limit_in_milliseconds'] = Variable(displayLimitInMilliseconds); @@ -1376,6 +1358,9 @@ class MediaFile extends DataClass implements Insertable { requiresAuthentication: Value(requiresAuthentication), reopenByContact: Value(reopenByContact), storedByContact: Value(storedByContact), + reuploadRequestedBy: reuploadRequestedBy == null && nullToAbsent + ? const Value.absent() + : Value(reuploadRequestedBy), displayLimitInMilliseconds: displayLimitInMilliseconds == null && nullToAbsent ? const Value.absent() @@ -1411,6 +1396,8 @@ class MediaFile extends DataClass implements Insertable { serializer.fromJson(json['requiresAuthentication']), reopenByContact: serializer.fromJson(json['reopenByContact']), storedByContact: serializer.fromJson(json['storedByContact']), + reuploadRequestedBy: + serializer.fromJson?>(json['reuploadRequestedBy']), displayLimitInMilliseconds: serializer.fromJson(json['displayLimitInMilliseconds']), downloadToken: serializer.fromJson(json['downloadToken']), @@ -1434,6 +1421,7 @@ class MediaFile extends DataClass implements Insertable { 'requiresAuthentication': serializer.toJson(requiresAuthentication), 'reopenByContact': serializer.toJson(reopenByContact), 'storedByContact': serializer.toJson(storedByContact), + 'reuploadRequestedBy': serializer.toJson?>(reuploadRequestedBy), 'displayLimitInMilliseconds': serializer.toJson(displayLimitInMilliseconds), 'downloadToken': serializer.toJson(downloadToken), @@ -1452,6 +1440,7 @@ class MediaFile extends DataClass implements Insertable { bool? requiresAuthentication, bool? reopenByContact, bool? storedByContact, + Value?> reuploadRequestedBy = const Value.absent(), Value displayLimitInMilliseconds = const Value.absent(), Value downloadToken = const Value.absent(), Value encryptionKey = const Value.absent(), @@ -1468,6 +1457,9 @@ class MediaFile extends DataClass implements Insertable { requiresAuthentication ?? this.requiresAuthentication, reopenByContact: reopenByContact ?? this.reopenByContact, storedByContact: storedByContact ?? this.storedByContact, + reuploadRequestedBy: reuploadRequestedBy.present + ? reuploadRequestedBy.value + : this.reuploadRequestedBy, displayLimitInMilliseconds: displayLimitInMilliseconds.present ? displayLimitInMilliseconds.value : this.displayLimitInMilliseconds, @@ -1500,6 +1492,9 @@ class MediaFile extends DataClass implements Insertable { storedByContact: data.storedByContact.present ? data.storedByContact.value : this.storedByContact, + reuploadRequestedBy: data.reuploadRequestedBy.present + ? data.reuploadRequestedBy.value + : this.reuploadRequestedBy, displayLimitInMilliseconds: data.displayLimitInMilliseconds.present ? data.displayLimitInMilliseconds.value : this.displayLimitInMilliseconds, @@ -1529,6 +1524,7 @@ class MediaFile extends DataClass implements Insertable { ..write('requiresAuthentication: $requiresAuthentication, ') ..write('reopenByContact: $reopenByContact, ') ..write('storedByContact: $storedByContact, ') + ..write('reuploadRequestedBy: $reuploadRequestedBy, ') ..write('displayLimitInMilliseconds: $displayLimitInMilliseconds, ') ..write('downloadToken: $downloadToken, ') ..write('encryptionKey: $encryptionKey, ') @@ -1548,6 +1544,7 @@ class MediaFile extends DataClass implements Insertable { requiresAuthentication, reopenByContact, storedByContact, + reuploadRequestedBy, displayLimitInMilliseconds, $driftBlobEquality.hash(downloadToken), $driftBlobEquality.hash(encryptionKey), @@ -1565,6 +1562,7 @@ class MediaFile extends DataClass implements Insertable { other.requiresAuthentication == this.requiresAuthentication && other.reopenByContact == this.reopenByContact && other.storedByContact == this.storedByContact && + other.reuploadRequestedBy == this.reuploadRequestedBy && other.displayLimitInMilliseconds == this.displayLimitInMilliseconds && $driftBlobEquality.equals(other.downloadToken, this.downloadToken) && $driftBlobEquality.equals(other.encryptionKey, this.encryptionKey) && @@ -1582,6 +1580,7 @@ class MediaFilesCompanion extends UpdateCompanion { final Value requiresAuthentication; final Value reopenByContact; final Value storedByContact; + final Value?> reuploadRequestedBy; final Value displayLimitInMilliseconds; final Value downloadToken; final Value encryptionKey; @@ -1597,6 +1596,7 @@ class MediaFilesCompanion extends UpdateCompanion { this.requiresAuthentication = const Value.absent(), this.reopenByContact = const Value.absent(), this.storedByContact = const Value.absent(), + this.reuploadRequestedBy = const Value.absent(), this.displayLimitInMilliseconds = const Value.absent(), this.downloadToken = const Value.absent(), this.encryptionKey = const Value.absent(), @@ -1613,6 +1613,7 @@ class MediaFilesCompanion extends UpdateCompanion { required bool requiresAuthentication, this.reopenByContact = const Value.absent(), this.storedByContact = const Value.absent(), + this.reuploadRequestedBy = const Value.absent(), this.displayLimitInMilliseconds = const Value.absent(), this.downloadToken = const Value.absent(), this.encryptionKey = const Value.absent(), @@ -1630,6 +1631,7 @@ class MediaFilesCompanion extends UpdateCompanion { Expression? requiresAuthentication, Expression? reopenByContact, Expression? storedByContact, + Expression? reuploadRequestedBy, Expression? displayLimitInMilliseconds, Expression? downloadToken, Expression? encryptionKey, @@ -1647,6 +1649,8 @@ class MediaFilesCompanion extends UpdateCompanion { 'requires_authentication': requiresAuthentication, if (reopenByContact != null) 'reopen_by_contact': reopenByContact, if (storedByContact != null) 'stored_by_contact': storedByContact, + if (reuploadRequestedBy != null) + 'reupload_requested_by': reuploadRequestedBy, if (displayLimitInMilliseconds != null) 'display_limit_in_milliseconds': displayLimitInMilliseconds, if (downloadToken != null) 'download_token': downloadToken, @@ -1666,6 +1670,7 @@ class MediaFilesCompanion extends UpdateCompanion { Value? requiresAuthentication, Value? reopenByContact, Value? storedByContact, + Value?>? reuploadRequestedBy, Value? displayLimitInMilliseconds, Value? downloadToken, Value? encryptionKey, @@ -1682,6 +1687,7 @@ class MediaFilesCompanion extends UpdateCompanion { requiresAuthentication ?? this.requiresAuthentication, reopenByContact: reopenByContact ?? this.reopenByContact, storedByContact: storedByContact ?? this.storedByContact, + reuploadRequestedBy: reuploadRequestedBy ?? this.reuploadRequestedBy, displayLimitInMilliseconds: displayLimitInMilliseconds ?? this.displayLimitInMilliseconds, downloadToken: downloadToken ?? this.downloadToken, @@ -1721,6 +1727,11 @@ class MediaFilesCompanion extends UpdateCompanion { if (storedByContact.present) { map['stored_by_contact'] = Variable(storedByContact.value); } + if (reuploadRequestedBy.present) { + map['reupload_requested_by'] = Variable($MediaFilesTable + .$converterreuploadRequestedByn + .toSql(reuploadRequestedBy.value)); + } if (displayLimitInMilliseconds.present) { map['display_limit_in_milliseconds'] = Variable(displayLimitInMilliseconds.value); @@ -1756,6 +1767,7 @@ class MediaFilesCompanion extends UpdateCompanion { ..write('requiresAuthentication: $requiresAuthentication, ') ..write('reopenByContact: $reopenByContact, ') ..write('storedByContact: $storedByContact, ') + ..write('reuploadRequestedBy: $reuploadRequestedBy, ') ..write('displayLimitInMilliseconds: $displayLimitInMilliseconds, ') ..write('downloadToken: $downloadToken, ') ..write('encryptionKey: $encryptionKey, ') @@ -1784,7 +1796,9 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> { @override late final GeneratedColumn messageId = GeneratedColumn( 'message_id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + type: DriftSqlType.string, + requiredDuringInsert: false, + clientDefault: () => uuid.v7()); static const VerificationMeta _senderIdMeta = const VerificationMeta('senderId'); @override @@ -1838,25 +1852,25 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> { defaultConstraints: GeneratedColumn.constraintIsAlways('CHECK ("is_edited" IN (0, 1))'), defaultValue: const Constant(false)); - static const VerificationMeta _acknowledgeByUserMeta = - const VerificationMeta('acknowledgeByUser'); + static const VerificationMeta _ackByUserMeta = + const VerificationMeta('ackByUser'); @override - late final GeneratedColumn acknowledgeByUser = GeneratedColumn( - 'acknowledge_by_user', aliasedName, false, + late final GeneratedColumn ackByUser = GeneratedColumn( + 'ack_by_user', aliasedName, false, type: DriftSqlType.bool, requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("acknowledge_by_user" IN (0, 1))'), + defaultConstraints: + GeneratedColumn.constraintIsAlways('CHECK ("ack_by_user" IN (0, 1))'), defaultValue: const Constant(false)); - static const VerificationMeta _acknowledgeByServerMeta = - const VerificationMeta('acknowledgeByServer'); + static const VerificationMeta _ackByServerMeta = + const VerificationMeta('ackByServer'); @override - late final GeneratedColumn acknowledgeByServer = GeneratedColumn( - 'acknowledge_by_server', aliasedName, false, + late final GeneratedColumn ackByServer = GeneratedColumn( + 'ack_by_server', aliasedName, false, type: DriftSqlType.bool, requiredDuringInsert: false, defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("acknowledge_by_server" IN (0, 1))'), + 'CHECK ("ack_by_server" IN (0, 1))'), defaultValue: const Constant(false)); static const VerificationMeta _openedByCounterMeta = const VerificationMeta('openedByCounter'); @@ -1898,8 +1912,8 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> { quotesMessageId, isDeletedFromSender, isEdited, - acknowledgeByUser, - acknowledgeByServer, + ackByUser, + ackByServer, openedByCounter, openedAt, createdAt, @@ -1924,8 +1938,6 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> { if (data.containsKey('message_id')) { context.handle(_messageIdMeta, messageId.isAcceptableOrUnknown(data['message_id']!, _messageIdMeta)); - } else if (isInserting) { - context.missing(_messageIdMeta); } if (data.containsKey('sender_id')) { context.handle(_senderIdMeta, @@ -1955,17 +1967,17 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> { context.handle(_isEditedMeta, isEdited.isAcceptableOrUnknown(data['is_edited']!, _isEditedMeta)); } - if (data.containsKey('acknowledge_by_user')) { + if (data.containsKey('ack_by_user')) { context.handle( - _acknowledgeByUserMeta, - acknowledgeByUser.isAcceptableOrUnknown( - data['acknowledge_by_user']!, _acknowledgeByUserMeta)); + _ackByUserMeta, + ackByUser.isAcceptableOrUnknown( + data['ack_by_user']!, _ackByUserMeta)); } - if (data.containsKey('acknowledge_by_server')) { + if (data.containsKey('ack_by_server')) { context.handle( - _acknowledgeByServerMeta, - acknowledgeByServer.isAcceptableOrUnknown( - data['acknowledge_by_server']!, _acknowledgeByServerMeta)); + _ackByServerMeta, + ackByServer.isAcceptableOrUnknown( + data['ack_by_server']!, _ackByServerMeta)); } if (data.containsKey('opened_by_counter')) { context.handle( @@ -2012,10 +2024,10 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> { DriftSqlType.bool, data['${effectivePrefix}is_deleted_from_sender'])!, isEdited: attachedDatabase.typeMapping .read(DriftSqlType.bool, data['${effectivePrefix}is_edited'])!, - acknowledgeByUser: attachedDatabase.typeMapping.read( - DriftSqlType.bool, data['${effectivePrefix}acknowledge_by_user'])!, - acknowledgeByServer: attachedDatabase.typeMapping.read( - DriftSqlType.bool, data['${effectivePrefix}acknowledge_by_server'])!, + ackByUser: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}ack_by_user'])!, + ackByServer: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}ack_by_server'])!, openedByCounter: attachedDatabase.typeMapping .read(DriftSqlType.int, data['${effectivePrefix}opened_by_counter'])!, openedAt: attachedDatabase.typeMapping @@ -2042,8 +2054,8 @@ class Message extends DataClass implements Insertable { final String? quotesMessageId; final bool isDeletedFromSender; final bool isEdited; - final bool acknowledgeByUser; - final bool acknowledgeByServer; + final bool ackByUser; + final bool ackByServer; final int openedByCounter; final DateTime? openedAt; final DateTime createdAt; @@ -2057,8 +2069,8 @@ class Message extends DataClass implements Insertable { this.quotesMessageId, required this.isDeletedFromSender, required this.isEdited, - required this.acknowledgeByUser, - required this.acknowledgeByServer, + required this.ackByUser, + required this.ackByServer, required this.openedByCounter, this.openedAt, required this.createdAt, @@ -2082,8 +2094,8 @@ class Message extends DataClass implements Insertable { } map['is_deleted_from_sender'] = Variable(isDeletedFromSender); map['is_edited'] = Variable(isEdited); - map['acknowledge_by_user'] = Variable(acknowledgeByUser); - map['acknowledge_by_server'] = Variable(acknowledgeByServer); + map['ack_by_user'] = Variable(ackByUser); + map['ack_by_server'] = Variable(ackByServer); map['opened_by_counter'] = Variable(openedByCounter); if (!nullToAbsent || openedAt != null) { map['opened_at'] = Variable(openedAt); @@ -2113,8 +2125,8 @@ class Message extends DataClass implements Insertable { : Value(quotesMessageId), isDeletedFromSender: Value(isDeletedFromSender), isEdited: Value(isEdited), - acknowledgeByUser: Value(acknowledgeByUser), - acknowledgeByServer: Value(acknowledgeByServer), + ackByUser: Value(ackByUser), + ackByServer: Value(ackByServer), openedByCounter: Value(openedByCounter), openedAt: openedAt == null && nullToAbsent ? const Value.absent() @@ -2139,9 +2151,8 @@ class Message extends DataClass implements Insertable { isDeletedFromSender: serializer.fromJson(json['isDeletedFromSender']), isEdited: serializer.fromJson(json['isEdited']), - acknowledgeByUser: serializer.fromJson(json['acknowledgeByUser']), - acknowledgeByServer: - serializer.fromJson(json['acknowledgeByServer']), + ackByUser: serializer.fromJson(json['ackByUser']), + ackByServer: serializer.fromJson(json['ackByServer']), openedByCounter: serializer.fromJson(json['openedByCounter']), openedAt: serializer.fromJson(json['openedAt']), createdAt: serializer.fromJson(json['createdAt']), @@ -2160,8 +2171,8 @@ class Message extends DataClass implements Insertable { 'quotesMessageId': serializer.toJson(quotesMessageId), 'isDeletedFromSender': serializer.toJson(isDeletedFromSender), 'isEdited': serializer.toJson(isEdited), - 'acknowledgeByUser': serializer.toJson(acknowledgeByUser), - 'acknowledgeByServer': serializer.toJson(acknowledgeByServer), + 'ackByUser': serializer.toJson(ackByUser), + 'ackByServer': serializer.toJson(ackByServer), 'openedByCounter': serializer.toJson(openedByCounter), 'openedAt': serializer.toJson(openedAt), 'createdAt': serializer.toJson(createdAt), @@ -2178,8 +2189,8 @@ class Message extends DataClass implements Insertable { Value quotesMessageId = const Value.absent(), bool? isDeletedFromSender, bool? isEdited, - bool? acknowledgeByUser, - bool? acknowledgeByServer, + bool? ackByUser, + bool? ackByServer, int? openedByCounter, Value openedAt = const Value.absent(), DateTime? createdAt, @@ -2195,8 +2206,8 @@ class Message extends DataClass implements Insertable { : this.quotesMessageId, isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, isEdited: isEdited ?? this.isEdited, - acknowledgeByUser: acknowledgeByUser ?? this.acknowledgeByUser, - acknowledgeByServer: acknowledgeByServer ?? this.acknowledgeByServer, + ackByUser: ackByUser ?? this.ackByUser, + ackByServer: ackByServer ?? this.ackByServer, openedByCounter: openedByCounter ?? this.openedByCounter, openedAt: openedAt.present ? openedAt.value : this.openedAt, createdAt: createdAt ?? this.createdAt, @@ -2216,12 +2227,9 @@ class Message extends DataClass implements Insertable { ? data.isDeletedFromSender.value : this.isDeletedFromSender, isEdited: data.isEdited.present ? data.isEdited.value : this.isEdited, - acknowledgeByUser: data.acknowledgeByUser.present - ? data.acknowledgeByUser.value - : this.acknowledgeByUser, - acknowledgeByServer: data.acknowledgeByServer.present - ? data.acknowledgeByServer.value - : this.acknowledgeByServer, + ackByUser: data.ackByUser.present ? data.ackByUser.value : this.ackByUser, + ackByServer: + data.ackByServer.present ? data.ackByServer.value : this.ackByServer, openedByCounter: data.openedByCounter.present ? data.openedByCounter.value : this.openedByCounter, @@ -2243,8 +2251,8 @@ class Message extends DataClass implements Insertable { ..write('quotesMessageId: $quotesMessageId, ') ..write('isDeletedFromSender: $isDeletedFromSender, ') ..write('isEdited: $isEdited, ') - ..write('acknowledgeByUser: $acknowledgeByUser, ') - ..write('acknowledgeByServer: $acknowledgeByServer, ') + ..write('ackByUser: $ackByUser, ') + ..write('ackByServer: $ackByServer, ') ..write('openedByCounter: $openedByCounter, ') ..write('openedAt: $openedAt, ') ..write('createdAt: $createdAt, ') @@ -2263,8 +2271,8 @@ class Message extends DataClass implements Insertable { quotesMessageId, isDeletedFromSender, isEdited, - acknowledgeByUser, - acknowledgeByServer, + ackByUser, + ackByServer, openedByCounter, openedAt, createdAt, @@ -2281,8 +2289,8 @@ class Message extends DataClass implements Insertable { other.quotesMessageId == this.quotesMessageId && other.isDeletedFromSender == this.isDeletedFromSender && other.isEdited == this.isEdited && - other.acknowledgeByUser == this.acknowledgeByUser && - other.acknowledgeByServer == this.acknowledgeByServer && + other.ackByUser == this.ackByUser && + other.ackByServer == this.ackByServer && other.openedByCounter == this.openedByCounter && other.openedAt == this.openedAt && other.createdAt == this.createdAt && @@ -2298,8 +2306,8 @@ class MessagesCompanion extends UpdateCompanion { final Value quotesMessageId; final Value isDeletedFromSender; final Value isEdited; - final Value acknowledgeByUser; - final Value acknowledgeByServer; + final Value ackByUser; + final Value ackByServer; final Value openedByCounter; final Value openedAt; final Value createdAt; @@ -2314,8 +2322,8 @@ class MessagesCompanion extends UpdateCompanion { this.quotesMessageId = const Value.absent(), this.isDeletedFromSender = const Value.absent(), this.isEdited = const Value.absent(), - this.acknowledgeByUser = const Value.absent(), - this.acknowledgeByServer = const Value.absent(), + this.ackByUser = const Value.absent(), + this.ackByServer = const Value.absent(), this.openedByCounter = const Value.absent(), this.openedAt = const Value.absent(), this.createdAt = const Value.absent(), @@ -2324,22 +2332,21 @@ class MessagesCompanion extends UpdateCompanion { }); MessagesCompanion.insert({ required String groupId, - required String messageId, + this.messageId = const Value.absent(), this.senderId = const Value.absent(), this.content = const Value.absent(), this.mediaId = const Value.absent(), this.quotesMessageId = const Value.absent(), this.isDeletedFromSender = const Value.absent(), this.isEdited = const Value.absent(), - this.acknowledgeByUser = const Value.absent(), - this.acknowledgeByServer = const Value.absent(), + this.ackByUser = const Value.absent(), + this.ackByServer = const Value.absent(), this.openedByCounter = const Value.absent(), this.openedAt = const Value.absent(), this.createdAt = const Value.absent(), this.modifiedAt = const Value.absent(), this.rowid = const Value.absent(), - }) : groupId = Value(groupId), - messageId = Value(messageId); + }) : groupId = Value(groupId); static Insertable custom({ Expression? groupId, Expression? messageId, @@ -2349,8 +2356,8 @@ class MessagesCompanion extends UpdateCompanion { Expression? quotesMessageId, Expression? isDeletedFromSender, Expression? isEdited, - Expression? acknowledgeByUser, - Expression? acknowledgeByServer, + Expression? ackByUser, + Expression? ackByServer, Expression? openedByCounter, Expression? openedAt, Expression? createdAt, @@ -2367,9 +2374,8 @@ class MessagesCompanion extends UpdateCompanion { if (isDeletedFromSender != null) 'is_deleted_from_sender': isDeletedFromSender, if (isEdited != null) 'is_edited': isEdited, - if (acknowledgeByUser != null) 'acknowledge_by_user': acknowledgeByUser, - if (acknowledgeByServer != null) - 'acknowledge_by_server': acknowledgeByServer, + if (ackByUser != null) 'ack_by_user': ackByUser, + if (ackByServer != null) 'ack_by_server': ackByServer, if (openedByCounter != null) 'opened_by_counter': openedByCounter, if (openedAt != null) 'opened_at': openedAt, if (createdAt != null) 'created_at': createdAt, @@ -2387,8 +2393,8 @@ class MessagesCompanion extends UpdateCompanion { Value? quotesMessageId, Value? isDeletedFromSender, Value? isEdited, - Value? acknowledgeByUser, - Value? acknowledgeByServer, + Value? ackByUser, + Value? ackByServer, Value? openedByCounter, Value? openedAt, Value? createdAt, @@ -2403,8 +2409,8 @@ class MessagesCompanion extends UpdateCompanion { quotesMessageId: quotesMessageId ?? this.quotesMessageId, isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, isEdited: isEdited ?? this.isEdited, - acknowledgeByUser: acknowledgeByUser ?? this.acknowledgeByUser, - acknowledgeByServer: acknowledgeByServer ?? this.acknowledgeByServer, + ackByUser: ackByUser ?? this.ackByUser, + ackByServer: ackByServer ?? this.ackByServer, openedByCounter: openedByCounter ?? this.openedByCounter, openedAt: openedAt ?? this.openedAt, createdAt: createdAt ?? this.createdAt, @@ -2440,11 +2446,11 @@ class MessagesCompanion extends UpdateCompanion { if (isEdited.present) { map['is_edited'] = Variable(isEdited.value); } - if (acknowledgeByUser.present) { - map['acknowledge_by_user'] = Variable(acknowledgeByUser.value); + if (ackByUser.present) { + map['ack_by_user'] = Variable(ackByUser.value); } - if (acknowledgeByServer.present) { - map['acknowledge_by_server'] = Variable(acknowledgeByServer.value); + if (ackByServer.present) { + map['ack_by_server'] = Variable(ackByServer.value); } if (openedByCounter.present) { map['opened_by_counter'] = Variable(openedByCounter.value); @@ -2475,8 +2481,8 @@ class MessagesCompanion extends UpdateCompanion { ..write('quotesMessageId: $quotesMessageId, ') ..write('isDeletedFromSender: $isDeletedFromSender, ') ..write('isEdited: $isEdited, ') - ..write('acknowledgeByUser: $acknowledgeByUser, ') - ..write('acknowledgeByServer: $acknowledgeByServer, ') + ..write('ackByUser: $ackByUser, ') + ..write('ackByServer: $ackByServer, ') ..write('openedByCounter: $openedByCounter, ') ..write('openedAt: $openedAt, ') ..write('createdAt: $createdAt, ') @@ -3042,6 +3048,16 @@ class $GroupsTable extends Groups with TableInfo<$GroupsTable, Group> { defaultConstraints: GeneratedColumn.constraintIsAlways('CHECK ("pinned" IN (0, 1))'), defaultValue: const Constant(false)); + static const VerificationMeta _archivedMeta = + const VerificationMeta('archived'); + @override + late final GeneratedColumn archived = GeneratedColumn( + 'archived', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('CHECK ("archived" IN (0, 1))'), + defaultValue: const Constant(false)); static const VerificationMeta _lastMessageExchangeMeta = const VerificationMeta('lastMessageExchange'); @override @@ -3064,6 +3080,7 @@ class $GroupsTable extends Groups with TableInfo<$GroupsTable, Group> { isGroupAdmin, isGroupOfTwo, pinned, + archived, lastMessageExchange, createdAt ]; @@ -3101,6 +3118,10 @@ class $GroupsTable extends Groups with TableInfo<$GroupsTable, Group> { context.handle(_pinnedMeta, pinned.isAcceptableOrUnknown(data['pinned']!, _pinnedMeta)); } + if (data.containsKey('archived')) { + context.handle(_archivedMeta, + archived.isAcceptableOrUnknown(data['archived']!, _archivedMeta)); + } if (data.containsKey('last_message_exchange')) { context.handle( _lastMessageExchangeMeta, @@ -3128,6 +3149,8 @@ class $GroupsTable extends Groups with TableInfo<$GroupsTable, Group> { .read(DriftSqlType.bool, data['${effectivePrefix}is_group_of_two'])!, pinned: attachedDatabase.typeMapping .read(DriftSqlType.bool, data['${effectivePrefix}pinned'])!, + archived: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}archived'])!, lastMessageExchange: attachedDatabase.typeMapping.read( DriftSqlType.dateTime, data['${effectivePrefix}last_message_exchange'])!, @@ -3147,6 +3170,7 @@ class Group extends DataClass implements Insertable { final bool isGroupAdmin; final bool isGroupOfTwo; final bool pinned; + final bool archived; final DateTime lastMessageExchange; final DateTime createdAt; const Group( @@ -3154,6 +3178,7 @@ class Group extends DataClass implements Insertable { required this.isGroupAdmin, required this.isGroupOfTwo, required this.pinned, + required this.archived, required this.lastMessageExchange, required this.createdAt}); @override @@ -3163,6 +3188,7 @@ class Group extends DataClass implements Insertable { map['is_group_admin'] = Variable(isGroupAdmin); map['is_group_of_two'] = Variable(isGroupOfTwo); map['pinned'] = Variable(pinned); + map['archived'] = Variable(archived); map['last_message_exchange'] = Variable(lastMessageExchange); map['created_at'] = Variable(createdAt); return map; @@ -3174,6 +3200,7 @@ class Group extends DataClass implements Insertable { isGroupAdmin: Value(isGroupAdmin), isGroupOfTwo: Value(isGroupOfTwo), pinned: Value(pinned), + archived: Value(archived), lastMessageExchange: Value(lastMessageExchange), createdAt: Value(createdAt), ); @@ -3187,6 +3214,7 @@ class Group extends DataClass implements Insertable { isGroupAdmin: serializer.fromJson(json['isGroupAdmin']), isGroupOfTwo: serializer.fromJson(json['isGroupOfTwo']), pinned: serializer.fromJson(json['pinned']), + archived: serializer.fromJson(json['archived']), lastMessageExchange: serializer.fromJson(json['lastMessageExchange']), createdAt: serializer.fromJson(json['createdAt']), @@ -3200,6 +3228,7 @@ class Group extends DataClass implements Insertable { 'isGroupAdmin': serializer.toJson(isGroupAdmin), 'isGroupOfTwo': serializer.toJson(isGroupOfTwo), 'pinned': serializer.toJson(pinned), + 'archived': serializer.toJson(archived), 'lastMessageExchange': serializer.toJson(lastMessageExchange), 'createdAt': serializer.toJson(createdAt), }; @@ -3210,6 +3239,7 @@ class Group extends DataClass implements Insertable { bool? isGroupAdmin, bool? isGroupOfTwo, bool? pinned, + bool? archived, DateTime? lastMessageExchange, DateTime? createdAt}) => Group( @@ -3217,6 +3247,7 @@ class Group extends DataClass implements Insertable { isGroupAdmin: isGroupAdmin ?? this.isGroupAdmin, isGroupOfTwo: isGroupOfTwo ?? this.isGroupOfTwo, pinned: pinned ?? this.pinned, + archived: archived ?? this.archived, lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, createdAt: createdAt ?? this.createdAt, ); @@ -3230,6 +3261,7 @@ class Group extends DataClass implements Insertable { ? data.isGroupOfTwo.value : this.isGroupOfTwo, pinned: data.pinned.present ? data.pinned.value : this.pinned, + archived: data.archived.present ? data.archived.value : this.archived, lastMessageExchange: data.lastMessageExchange.present ? data.lastMessageExchange.value : this.lastMessageExchange, @@ -3244,6 +3276,7 @@ class Group extends DataClass implements Insertable { ..write('isGroupAdmin: $isGroupAdmin, ') ..write('isGroupOfTwo: $isGroupOfTwo, ') ..write('pinned: $pinned, ') + ..write('archived: $archived, ') ..write('lastMessageExchange: $lastMessageExchange, ') ..write('createdAt: $createdAt') ..write(')')) @@ -3252,7 +3285,7 @@ class Group extends DataClass implements Insertable { @override int get hashCode => Object.hash(groupId, isGroupAdmin, isGroupOfTwo, pinned, - lastMessageExchange, createdAt); + archived, lastMessageExchange, createdAt); @override bool operator ==(Object other) => identical(this, other) || @@ -3261,6 +3294,7 @@ class Group extends DataClass implements Insertable { other.isGroupAdmin == this.isGroupAdmin && other.isGroupOfTwo == this.isGroupOfTwo && other.pinned == this.pinned && + other.archived == this.archived && other.lastMessageExchange == this.lastMessageExchange && other.createdAt == this.createdAt); } @@ -3270,6 +3304,7 @@ class GroupsCompanion extends UpdateCompanion { final Value isGroupAdmin; final Value isGroupOfTwo; final Value pinned; + final Value archived; final Value lastMessageExchange; final Value createdAt; final Value rowid; @@ -3278,6 +3313,7 @@ class GroupsCompanion extends UpdateCompanion { this.isGroupAdmin = const Value.absent(), this.isGroupOfTwo = const Value.absent(), this.pinned = const Value.absent(), + this.archived = const Value.absent(), this.lastMessageExchange = const Value.absent(), this.createdAt = const Value.absent(), this.rowid = const Value.absent(), @@ -3287,6 +3323,7 @@ class GroupsCompanion extends UpdateCompanion { required bool isGroupAdmin, required bool isGroupOfTwo, this.pinned = const Value.absent(), + this.archived = const Value.absent(), this.lastMessageExchange = const Value.absent(), this.createdAt = const Value.absent(), this.rowid = const Value.absent(), @@ -3297,6 +3334,7 @@ class GroupsCompanion extends UpdateCompanion { Expression? isGroupAdmin, Expression? isGroupOfTwo, Expression? pinned, + Expression? archived, Expression? lastMessageExchange, Expression? createdAt, Expression? rowid, @@ -3306,6 +3344,7 @@ class GroupsCompanion extends UpdateCompanion { if (isGroupAdmin != null) 'is_group_admin': isGroupAdmin, if (isGroupOfTwo != null) 'is_group_of_two': isGroupOfTwo, if (pinned != null) 'pinned': pinned, + if (archived != null) 'archived': archived, if (lastMessageExchange != null) 'last_message_exchange': lastMessageExchange, if (createdAt != null) 'created_at': createdAt, @@ -3318,6 +3357,7 @@ class GroupsCompanion extends UpdateCompanion { Value? isGroupAdmin, Value? isGroupOfTwo, Value? pinned, + Value? archived, Value? lastMessageExchange, Value? createdAt, Value? rowid}) { @@ -3326,6 +3366,7 @@ class GroupsCompanion extends UpdateCompanion { isGroupAdmin: isGroupAdmin ?? this.isGroupAdmin, isGroupOfTwo: isGroupOfTwo ?? this.isGroupOfTwo, pinned: pinned ?? this.pinned, + archived: archived ?? this.archived, lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, createdAt: createdAt ?? this.createdAt, rowid: rowid ?? this.rowid, @@ -3347,6 +3388,9 @@ class GroupsCompanion extends UpdateCompanion { if (pinned.present) { map['pinned'] = Variable(pinned.value); } + if (archived.present) { + map['archived'] = Variable(archived.value); + } if (lastMessageExchange.present) { map['last_message_exchange'] = Variable(lastMessageExchange.value); @@ -3367,6 +3411,7 @@ class GroupsCompanion extends UpdateCompanion { ..write('isGroupAdmin: $isGroupAdmin, ') ..write('isGroupOfTwo: $isGroupOfTwo, ') ..write('pinned: $pinned, ') + ..write('archived: $archived, ') ..write('lastMessageExchange: $lastMessageExchange, ') ..write('createdAt: $createdAt, ') ..write('rowid: $rowid') @@ -3707,6 +3752,12 @@ class $ReceiptsTable extends Receipts with TableInfo<$ReceiptsTable, Receipt> { defaultConstraints: GeneratedColumn.constraintIsAlways( 'CHECK ("contact_will_sends_receipt" IN (0, 1))'), defaultValue: const Constant(true)); + static const VerificationMeta _ackByServerAtMeta = + const VerificationMeta('ackByServerAt'); + @override + late final GeneratedColumn ackByServerAt = + GeneratedColumn('ack_by_server_at', aliasedName, true, + type: DriftSqlType.dateTime, requiredDuringInsert: false); static const VerificationMeta _retryCountMeta = const VerificationMeta('retryCount'); @override @@ -3736,6 +3787,7 @@ class $ReceiptsTable extends Receipts with TableInfo<$ReceiptsTable, Receipt> { messageId, message, contactWillSendsReceipt, + ackByServerAt, retryCount, lastRetry, createdAt @@ -3777,6 +3829,12 @@ class $ReceiptsTable extends Receipts with TableInfo<$ReceiptsTable, Receipt> { data['contact_will_sends_receipt']!, _contactWillSendsReceiptMeta)); } + if (data.containsKey('ack_by_server_at')) { + context.handle( + _ackByServerAtMeta, + ackByServerAt.isAcceptableOrUnknown( + data['ack_by_server_at']!, _ackByServerAtMeta)); + } if (data.containsKey('retry_count')) { context.handle( _retryCountMeta, @@ -3811,6 +3869,8 @@ class $ReceiptsTable extends Receipts with TableInfo<$ReceiptsTable, Receipt> { contactWillSendsReceipt: attachedDatabase.typeMapping.read( DriftSqlType.bool, data['${effectivePrefix}contact_will_sends_receipt'])!, + ackByServerAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, data['${effectivePrefix}ack_by_server_at']), retryCount: attachedDatabase.typeMapping .read(DriftSqlType.int, data['${effectivePrefix}retry_count'])!, lastRetry: attachedDatabase.typeMapping @@ -3830,8 +3890,11 @@ class Receipt extends DataClass implements Insertable { final String receiptId; final int contactId; final String? messageId; + + /// This is the protobuf 'Message' final Uint8List message; final bool contactWillSendsReceipt; + final DateTime? ackByServerAt; final int retryCount; final DateTime? lastRetry; final DateTime createdAt; @@ -3841,6 +3904,7 @@ class Receipt extends DataClass implements Insertable { this.messageId, required this.message, required this.contactWillSendsReceipt, + this.ackByServerAt, required this.retryCount, this.lastRetry, required this.createdAt}); @@ -3854,6 +3918,9 @@ class Receipt extends DataClass implements Insertable { } map['message'] = Variable(message); map['contact_will_sends_receipt'] = Variable(contactWillSendsReceipt); + if (!nullToAbsent || ackByServerAt != null) { + map['ack_by_server_at'] = Variable(ackByServerAt); + } map['retry_count'] = Variable(retryCount); if (!nullToAbsent || lastRetry != null) { map['last_retry'] = Variable(lastRetry); @@ -3871,6 +3938,9 @@ class Receipt extends DataClass implements Insertable { : Value(messageId), message: Value(message), contactWillSendsReceipt: Value(contactWillSendsReceipt), + ackByServerAt: ackByServerAt == null && nullToAbsent + ? const Value.absent() + : Value(ackByServerAt), retryCount: Value(retryCount), lastRetry: lastRetry == null && nullToAbsent ? const Value.absent() @@ -3889,6 +3959,7 @@ class Receipt extends DataClass implements Insertable { message: serializer.fromJson(json['message']), contactWillSendsReceipt: serializer.fromJson(json['contactWillSendsReceipt']), + ackByServerAt: serializer.fromJson(json['ackByServerAt']), retryCount: serializer.fromJson(json['retryCount']), lastRetry: serializer.fromJson(json['lastRetry']), createdAt: serializer.fromJson(json['createdAt']), @@ -3904,6 +3975,7 @@ class Receipt extends DataClass implements Insertable { 'message': serializer.toJson(message), 'contactWillSendsReceipt': serializer.toJson(contactWillSendsReceipt), + 'ackByServerAt': serializer.toJson(ackByServerAt), 'retryCount': serializer.toJson(retryCount), 'lastRetry': serializer.toJson(lastRetry), 'createdAt': serializer.toJson(createdAt), @@ -3916,6 +3988,7 @@ class Receipt extends DataClass implements Insertable { Value messageId = const Value.absent(), Uint8List? message, bool? contactWillSendsReceipt, + Value ackByServerAt = const Value.absent(), int? retryCount, Value lastRetry = const Value.absent(), DateTime? createdAt}) => @@ -3926,6 +3999,8 @@ class Receipt extends DataClass implements Insertable { message: message ?? this.message, contactWillSendsReceipt: contactWillSendsReceipt ?? this.contactWillSendsReceipt, + ackByServerAt: + ackByServerAt.present ? ackByServerAt.value : this.ackByServerAt, retryCount: retryCount ?? this.retryCount, lastRetry: lastRetry.present ? lastRetry.value : this.lastRetry, createdAt: createdAt ?? this.createdAt, @@ -3939,6 +4014,9 @@ class Receipt extends DataClass implements Insertable { contactWillSendsReceipt: data.contactWillSendsReceipt.present ? data.contactWillSendsReceipt.value : this.contactWillSendsReceipt, + ackByServerAt: data.ackByServerAt.present + ? data.ackByServerAt.value + : this.ackByServerAt, retryCount: data.retryCount.present ? data.retryCount.value : this.retryCount, lastRetry: data.lastRetry.present ? data.lastRetry.value : this.lastRetry, @@ -3954,6 +4032,7 @@ class Receipt extends DataClass implements Insertable { ..write('messageId: $messageId, ') ..write('message: $message, ') ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') + ..write('ackByServerAt: $ackByServerAt, ') ..write('retryCount: $retryCount, ') ..write('lastRetry: $lastRetry, ') ..write('createdAt: $createdAt') @@ -3968,6 +4047,7 @@ class Receipt extends DataClass implements Insertable { messageId, $driftBlobEquality.hash(message), contactWillSendsReceipt, + ackByServerAt, retryCount, lastRetry, createdAt); @@ -3980,6 +4060,7 @@ class Receipt extends DataClass implements Insertable { other.messageId == this.messageId && $driftBlobEquality.equals(other.message, this.message) && other.contactWillSendsReceipt == this.contactWillSendsReceipt && + other.ackByServerAt == this.ackByServerAt && other.retryCount == this.retryCount && other.lastRetry == this.lastRetry && other.createdAt == this.createdAt); @@ -3991,6 +4072,7 @@ class ReceiptsCompanion extends UpdateCompanion { final Value messageId; final Value message; final Value contactWillSendsReceipt; + final Value ackByServerAt; final Value retryCount; final Value lastRetry; final Value createdAt; @@ -4001,6 +4083,7 @@ class ReceiptsCompanion extends UpdateCompanion { this.messageId = const Value.absent(), this.message = const Value.absent(), this.contactWillSendsReceipt = const Value.absent(), + this.ackByServerAt = const Value.absent(), this.retryCount = const Value.absent(), this.lastRetry = const Value.absent(), this.createdAt = const Value.absent(), @@ -4012,6 +4095,7 @@ class ReceiptsCompanion extends UpdateCompanion { this.messageId = const Value.absent(), required Uint8List message, this.contactWillSendsReceipt = const Value.absent(), + this.ackByServerAt = const Value.absent(), this.retryCount = const Value.absent(), this.lastRetry = const Value.absent(), this.createdAt = const Value.absent(), @@ -4024,6 +4108,7 @@ class ReceiptsCompanion extends UpdateCompanion { Expression? messageId, Expression? message, Expression? contactWillSendsReceipt, + Expression? ackByServerAt, Expression? retryCount, Expression? lastRetry, Expression? createdAt, @@ -4036,6 +4121,7 @@ class ReceiptsCompanion extends UpdateCompanion { if (message != null) 'message': message, if (contactWillSendsReceipt != null) 'contact_will_sends_receipt': contactWillSendsReceipt, + if (ackByServerAt != null) 'ack_by_server_at': ackByServerAt, if (retryCount != null) 'retry_count': retryCount, if (lastRetry != null) 'last_retry': lastRetry, if (createdAt != null) 'created_at': createdAt, @@ -4049,6 +4135,7 @@ class ReceiptsCompanion extends UpdateCompanion { Value? messageId, Value? message, Value? contactWillSendsReceipt, + Value? ackByServerAt, Value? retryCount, Value? lastRetry, Value? createdAt, @@ -4060,6 +4147,7 @@ class ReceiptsCompanion extends UpdateCompanion { message: message ?? this.message, contactWillSendsReceipt: contactWillSendsReceipt ?? this.contactWillSendsReceipt, + ackByServerAt: ackByServerAt ?? this.ackByServerAt, retryCount: retryCount ?? this.retryCount, lastRetry: lastRetry ?? this.lastRetry, createdAt: createdAt ?? this.createdAt, @@ -4086,6 +4174,9 @@ class ReceiptsCompanion extends UpdateCompanion { map['contact_will_sends_receipt'] = Variable(contactWillSendsReceipt.value); } + if (ackByServerAt.present) { + map['ack_by_server_at'] = Variable(ackByServerAt.value); + } if (retryCount.present) { map['retry_count'] = Variable(retryCount.value); } @@ -4109,6 +4200,7 @@ class ReceiptsCompanion extends UpdateCompanion { ..write('messageId: $messageId, ') ..write('message: $message, ') ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') + ..write('ackByServerAt: $ackByServerAt, ') ..write('retryCount: $retryCount, ') ..write('lastRetry: $lastRetry, ') ..write('createdAt: $createdAt, ') @@ -5744,6 +5836,7 @@ abstract class _$TwonlyDB extends GeneratedDatabase { late final ReceiptsDao receiptsDao = ReceiptsDao(this as TwonlyDB); late final GroupsDao groupsDao = GroupsDao(this as TwonlyDB); late final ReactionsDao reactionsDao = ReactionsDao(this as TwonlyDB); + late final MediaFilesDao mediaFilesDao = MediaFilesDao(this as TwonlyDB); @override Iterable> get allTables => allSchemaEntities.whereType>(); @@ -5833,7 +5926,6 @@ typedef $$ContactsTableCreateCompanionBuilder = ContactsCompanion Function({ Value hidden, Value blocked, Value verified, - Value archived, Value deleted, Value alsoBestFriend, Value deleteMessagesAfterXMinutes, @@ -5857,7 +5949,6 @@ typedef $$ContactsTableUpdateCompanionBuilder = ContactsCompanion Function({ Value hidden, Value blocked, Value verified, - Value archived, Value deleted, Value alsoBestFriend, Value deleteMessagesAfterXMinutes, @@ -6019,9 +6110,6 @@ class $$ContactsTableFilterComposer ColumnFilters get verified => $composableBuilder( column: $table.verified, builder: (column) => ColumnFilters(column)); - ColumnFilters get archived => $composableBuilder( - column: $table.archived, builder: (column) => ColumnFilters(column)); - ColumnFilters get deleted => $composableBuilder( column: $table.deleted, builder: (column) => ColumnFilters(column)); @@ -6232,9 +6320,6 @@ class $$ContactsTableOrderingComposer ColumnOrderings get verified => $composableBuilder( column: $table.verified, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get archived => $composableBuilder( - column: $table.archived, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get deleted => $composableBuilder( column: $table.deleted, builder: (column) => ColumnOrderings(column)); @@ -6316,9 +6401,6 @@ class $$ContactsTableAnnotationComposer GeneratedColumn get verified => $composableBuilder(column: $table.verified, builder: (column) => column); - GeneratedColumn get archived => - $composableBuilder(column: $table.archived, builder: (column) => column); - GeneratedColumn get deleted => $composableBuilder(column: $table.deleted, builder: (column) => column); @@ -6521,7 +6603,6 @@ class $$ContactsTableTableManager extends RootTableManager< Value hidden = const Value.absent(), Value blocked = const Value.absent(), Value verified = const Value.absent(), - Value archived = const Value.absent(), Value deleted = const Value.absent(), Value alsoBestFriend = const Value.absent(), Value deleteMessagesAfterXMinutes = const Value.absent(), @@ -6545,7 +6626,6 @@ class $$ContactsTableTableManager extends RootTableManager< hidden: hidden, blocked: blocked, verified: verified, - archived: archived, deleted: deleted, alsoBestFriend: alsoBestFriend, deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes, @@ -6569,7 +6649,6 @@ class $$ContactsTableTableManager extends RootTableManager< Value hidden = const Value.absent(), Value blocked = const Value.absent(), Value verified = const Value.absent(), - Value archived = const Value.absent(), Value deleted = const Value.absent(), Value alsoBestFriend = const Value.absent(), Value deleteMessagesAfterXMinutes = const Value.absent(), @@ -6593,7 +6672,6 @@ class $$ContactsTableTableManager extends RootTableManager< hidden: hidden, blocked: blocked, verified: verified, - archived: archived, deleted: deleted, alsoBestFriend: alsoBestFriend, deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes, @@ -6739,6 +6817,7 @@ typedef $$MediaFilesTableCreateCompanionBuilder = MediaFilesCompanion Function({ required bool requiresAuthentication, Value reopenByContact, Value storedByContact, + Value?> reuploadRequestedBy, Value displayLimitInMilliseconds, Value downloadToken, Value encryptionKey, @@ -6755,6 +6834,7 @@ typedef $$MediaFilesTableUpdateCompanionBuilder = MediaFilesCompanion Function({ Value requiresAuthentication, Value reopenByContact, Value storedByContact, + Value?> reuploadRequestedBy, Value displayLimitInMilliseconds, Value downloadToken, Value encryptionKey, @@ -6823,6 +6903,11 @@ class $$MediaFilesTableFilterComposer column: $table.storedByContact, builder: (column) => ColumnFilters(column)); + ColumnWithTypeConverterFilters?, List, String> + get reuploadRequestedBy => $composableBuilder( + column: $table.reuploadRequestedBy, + builder: (column) => ColumnWithTypeConverterFilters(column)); + ColumnFilters get displayLimitInMilliseconds => $composableBuilder( column: $table.displayLimitInMilliseconds, builder: (column) => ColumnFilters(column)); @@ -6899,6 +6984,10 @@ class $$MediaFilesTableOrderingComposer column: $table.storedByContact, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get reuploadRequestedBy => $composableBuilder( + column: $table.reuploadRequestedBy, + builder: (column) => ColumnOrderings(column)); + ColumnOrderings get displayLimitInMilliseconds => $composableBuilder( column: $table.displayLimitInMilliseconds, builder: (column) => ColumnOrderings(column)); @@ -6955,6 +7044,10 @@ class $$MediaFilesTableAnnotationComposer GeneratedColumn get storedByContact => $composableBuilder( column: $table.storedByContact, builder: (column) => column); + GeneratedColumnWithTypeConverter?, String> + get reuploadRequestedBy => $composableBuilder( + column: $table.reuploadRequestedBy, builder: (column) => column); + GeneratedColumn get displayLimitInMilliseconds => $composableBuilder( column: $table.displayLimitInMilliseconds, builder: (column) => column); @@ -7025,6 +7118,7 @@ class $$MediaFilesTableTableManager extends RootTableManager< Value requiresAuthentication = const Value.absent(), Value reopenByContact = const Value.absent(), Value storedByContact = const Value.absent(), + Value?> reuploadRequestedBy = const Value.absent(), Value displayLimitInMilliseconds = const Value.absent(), Value downloadToken = const Value.absent(), Value encryptionKey = const Value.absent(), @@ -7041,6 +7135,7 @@ class $$MediaFilesTableTableManager extends RootTableManager< requiresAuthentication: requiresAuthentication, reopenByContact: reopenByContact, storedByContact: storedByContact, + reuploadRequestedBy: reuploadRequestedBy, displayLimitInMilliseconds: displayLimitInMilliseconds, downloadToken: downloadToken, encryptionKey: encryptionKey, @@ -7057,6 +7152,7 @@ class $$MediaFilesTableTableManager extends RootTableManager< required bool requiresAuthentication, Value reopenByContact = const Value.absent(), Value storedByContact = const Value.absent(), + Value?> reuploadRequestedBy = const Value.absent(), Value displayLimitInMilliseconds = const Value.absent(), Value downloadToken = const Value.absent(), Value encryptionKey = const Value.absent(), @@ -7073,6 +7169,7 @@ class $$MediaFilesTableTableManager extends RootTableManager< requiresAuthentication: requiresAuthentication, reopenByContact: reopenByContact, storedByContact: storedByContact, + reuploadRequestedBy: reuploadRequestedBy, displayLimitInMilliseconds: displayLimitInMilliseconds, downloadToken: downloadToken, encryptionKey: encryptionKey, @@ -7128,15 +7225,15 @@ typedef $$MediaFilesTableProcessedTableManager = ProcessedTableManager< PrefetchHooks Function({bool messagesRefs})>; typedef $$MessagesTableCreateCompanionBuilder = MessagesCompanion Function({ required String groupId, - required String messageId, + Value messageId, Value senderId, Value content, Value mediaId, Value quotesMessageId, Value isDeletedFromSender, Value isEdited, - Value acknowledgeByUser, - Value acknowledgeByServer, + Value ackByUser, + Value ackByServer, Value openedByCounter, Value openedAt, Value createdAt, @@ -7152,8 +7249,8 @@ typedef $$MessagesTableUpdateCompanionBuilder = MessagesCompanion Function({ Value quotesMessageId, Value isDeletedFromSender, Value isEdited, - Value acknowledgeByUser, - Value acknowledgeByServer, + Value ackByUser, + Value ackByServer, Value openedByCounter, Value openedAt, Value createdAt, @@ -7286,13 +7383,11 @@ class $$MessagesTableFilterComposer ColumnFilters get isEdited => $composableBuilder( column: $table.isEdited, builder: (column) => ColumnFilters(column)); - ColumnFilters get acknowledgeByUser => $composableBuilder( - column: $table.acknowledgeByUser, - builder: (column) => ColumnFilters(column)); + ColumnFilters get ackByUser => $composableBuilder( + column: $table.ackByUser, builder: (column) => ColumnFilters(column)); - ColumnFilters get acknowledgeByServer => $composableBuilder( - column: $table.acknowledgeByServer, - builder: (column) => ColumnFilters(column)); + ColumnFilters get ackByServer => $composableBuilder( + column: $table.ackByServer, builder: (column) => ColumnFilters(column)); ColumnFilters get openedByCounter => $composableBuilder( column: $table.openedByCounter, @@ -7456,13 +7551,11 @@ class $$MessagesTableOrderingComposer ColumnOrderings get isEdited => $composableBuilder( column: $table.isEdited, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get acknowledgeByUser => $composableBuilder( - column: $table.acknowledgeByUser, - builder: (column) => ColumnOrderings(column)); + ColumnOrderings get ackByUser => $composableBuilder( + column: $table.ackByUser, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get acknowledgeByServer => $composableBuilder( - column: $table.acknowledgeByServer, - builder: (column) => ColumnOrderings(column)); + ColumnOrderings get ackByServer => $composableBuilder( + column: $table.ackByServer, builder: (column) => ColumnOrderings(column)); ColumnOrderings get openedByCounter => $composableBuilder( column: $table.openedByCounter, @@ -7562,11 +7655,11 @@ class $$MessagesTableAnnotationComposer GeneratedColumn get isEdited => $composableBuilder(column: $table.isEdited, builder: (column) => column); - GeneratedColumn get acknowledgeByUser => $composableBuilder( - column: $table.acknowledgeByUser, builder: (column) => column); + GeneratedColumn get ackByUser => + $composableBuilder(column: $table.ackByUser, builder: (column) => column); - GeneratedColumn get acknowledgeByServer => $composableBuilder( - column: $table.acknowledgeByServer, builder: (column) => column); + GeneratedColumn get ackByServer => $composableBuilder( + column: $table.ackByServer, builder: (column) => column); GeneratedColumn get openedByCounter => $composableBuilder( column: $table.openedByCounter, builder: (column) => column); @@ -7741,8 +7834,8 @@ class $$MessagesTableTableManager extends RootTableManager< Value quotesMessageId = const Value.absent(), Value isDeletedFromSender = const Value.absent(), Value isEdited = const Value.absent(), - Value acknowledgeByUser = const Value.absent(), - Value acknowledgeByServer = const Value.absent(), + Value ackByUser = const Value.absent(), + Value ackByServer = const Value.absent(), Value openedByCounter = const Value.absent(), Value openedAt = const Value.absent(), Value createdAt = const Value.absent(), @@ -7758,8 +7851,8 @@ class $$MessagesTableTableManager extends RootTableManager< quotesMessageId: quotesMessageId, isDeletedFromSender: isDeletedFromSender, isEdited: isEdited, - acknowledgeByUser: acknowledgeByUser, - acknowledgeByServer: acknowledgeByServer, + ackByUser: ackByUser, + ackByServer: ackByServer, openedByCounter: openedByCounter, openedAt: openedAt, createdAt: createdAt, @@ -7768,15 +7861,15 @@ class $$MessagesTableTableManager extends RootTableManager< ), createCompanionCallback: ({ required String groupId, - required String messageId, + Value messageId = const Value.absent(), Value senderId = const Value.absent(), Value content = const Value.absent(), Value mediaId = const Value.absent(), Value quotesMessageId = const Value.absent(), Value isDeletedFromSender = const Value.absent(), Value isEdited = const Value.absent(), - Value acknowledgeByUser = const Value.absent(), - Value acknowledgeByServer = const Value.absent(), + Value ackByUser = const Value.absent(), + Value ackByServer = const Value.absent(), Value openedByCounter = const Value.absent(), Value openedAt = const Value.absent(), Value createdAt = const Value.absent(), @@ -7792,8 +7885,8 @@ class $$MessagesTableTableManager extends RootTableManager< quotesMessageId: quotesMessageId, isDeletedFromSender: isDeletedFromSender, isEdited: isEdited, - acknowledgeByUser: acknowledgeByUser, - acknowledgeByServer: acknowledgeByServer, + ackByUser: ackByUser, + ackByServer: ackByServer, openedByCounter: openedByCounter, openedAt: openedAt, createdAt: createdAt, @@ -8518,6 +8611,7 @@ typedef $$GroupsTableCreateCompanionBuilder = GroupsCompanion Function({ required bool isGroupAdmin, required bool isGroupOfTwo, Value pinned, + Value archived, Value lastMessageExchange, Value createdAt, Value rowid, @@ -8527,6 +8621,7 @@ typedef $$GroupsTableUpdateCompanionBuilder = GroupsCompanion Function({ Value isGroupAdmin, Value isGroupOfTwo, Value pinned, + Value archived, Value lastMessageExchange, Value createdAt, Value rowid, @@ -8552,6 +8647,9 @@ class $$GroupsTableFilterComposer extends Composer<_$TwonlyDB, $GroupsTable> { ColumnFilters get pinned => $composableBuilder( column: $table.pinned, builder: (column) => ColumnFilters(column)); + ColumnFilters get archived => $composableBuilder( + column: $table.archived, builder: (column) => ColumnFilters(column)); + ColumnFilters get lastMessageExchange => $composableBuilder( column: $table.lastMessageExchange, builder: (column) => ColumnFilters(column)); @@ -8582,6 +8680,9 @@ class $$GroupsTableOrderingComposer extends Composer<_$TwonlyDB, $GroupsTable> { ColumnOrderings get pinned => $composableBuilder( column: $table.pinned, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get archived => $composableBuilder( + column: $table.archived, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get lastMessageExchange => $composableBuilder( column: $table.lastMessageExchange, builder: (column) => ColumnOrderings(column)); @@ -8611,6 +8712,9 @@ class $$GroupsTableAnnotationComposer GeneratedColumn get pinned => $composableBuilder(column: $table.pinned, builder: (column) => column); + GeneratedColumn get archived => + $composableBuilder(column: $table.archived, builder: (column) => column); + GeneratedColumn get lastMessageExchange => $composableBuilder( column: $table.lastMessageExchange, builder: (column) => column); @@ -8645,6 +8749,7 @@ class $$GroupsTableTableManager extends RootTableManager< Value isGroupAdmin = const Value.absent(), Value isGroupOfTwo = const Value.absent(), Value pinned = const Value.absent(), + Value archived = const Value.absent(), Value lastMessageExchange = const Value.absent(), Value createdAt = const Value.absent(), Value rowid = const Value.absent(), @@ -8654,6 +8759,7 @@ class $$GroupsTableTableManager extends RootTableManager< isGroupAdmin: isGroupAdmin, isGroupOfTwo: isGroupOfTwo, pinned: pinned, + archived: archived, lastMessageExchange: lastMessageExchange, createdAt: createdAt, rowid: rowid, @@ -8663,6 +8769,7 @@ class $$GroupsTableTableManager extends RootTableManager< required bool isGroupAdmin, required bool isGroupOfTwo, Value pinned = const Value.absent(), + Value archived = const Value.absent(), Value lastMessageExchange = const Value.absent(), Value createdAt = const Value.absent(), Value rowid = const Value.absent(), @@ -8672,6 +8779,7 @@ class $$GroupsTableTableManager extends RootTableManager< isGroupAdmin: isGroupAdmin, isGroupOfTwo: isGroupOfTwo, pinned: pinned, + archived: archived, lastMessageExchange: lastMessageExchange, createdAt: createdAt, rowid: rowid, @@ -8965,6 +9073,7 @@ typedef $$ReceiptsTableCreateCompanionBuilder = ReceiptsCompanion Function({ Value messageId, required Uint8List message, Value contactWillSendsReceipt, + Value ackByServerAt, Value retryCount, Value lastRetry, Value createdAt, @@ -8976,6 +9085,7 @@ typedef $$ReceiptsTableUpdateCompanionBuilder = ReceiptsCompanion Function({ Value messageId, Value message, Value contactWillSendsReceipt, + Value ackByServerAt, Value retryCount, Value lastRetry, Value createdAt, @@ -9036,6 +9146,9 @@ class $$ReceiptsTableFilterComposer column: $table.contactWillSendsReceipt, builder: (column) => ColumnFilters(column)); + ColumnFilters get ackByServerAt => $composableBuilder( + column: $table.ackByServerAt, builder: (column) => ColumnFilters(column)); + ColumnFilters get retryCount => $composableBuilder( column: $table.retryCount, builder: (column) => ColumnFilters(column)); @@ -9105,6 +9218,10 @@ class $$ReceiptsTableOrderingComposer column: $table.contactWillSendsReceipt, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get ackByServerAt => $composableBuilder( + column: $table.ackByServerAt, + builder: (column) => ColumnOrderings(column)); + ColumnOrderings get retryCount => $composableBuilder( column: $table.retryCount, builder: (column) => ColumnOrderings(column)); @@ -9173,6 +9290,9 @@ class $$ReceiptsTableAnnotationComposer GeneratedColumn get contactWillSendsReceipt => $composableBuilder( column: $table.contactWillSendsReceipt, builder: (column) => column); + GeneratedColumn get ackByServerAt => $composableBuilder( + column: $table.ackByServerAt, builder: (column) => column); + GeneratedColumn get retryCount => $composableBuilder( column: $table.retryCount, builder: (column) => column); @@ -9251,6 +9371,7 @@ class $$ReceiptsTableTableManager extends RootTableManager< Value messageId = const Value.absent(), Value message = const Value.absent(), Value contactWillSendsReceipt = const Value.absent(), + Value ackByServerAt = const Value.absent(), Value retryCount = const Value.absent(), Value lastRetry = const Value.absent(), Value createdAt = const Value.absent(), @@ -9262,6 +9383,7 @@ class $$ReceiptsTableTableManager extends RootTableManager< messageId: messageId, message: message, contactWillSendsReceipt: contactWillSendsReceipt, + ackByServerAt: ackByServerAt, retryCount: retryCount, lastRetry: lastRetry, createdAt: createdAt, @@ -9273,6 +9395,7 @@ class $$ReceiptsTableTableManager extends RootTableManager< Value messageId = const Value.absent(), required Uint8List message, Value contactWillSendsReceipt = const Value.absent(), + Value ackByServerAt = const Value.absent(), Value retryCount = const Value.absent(), Value lastRetry = const Value.absent(), Value createdAt = const Value.absent(), @@ -9284,6 +9407,7 @@ class $$ReceiptsTableTableManager extends RootTableManager< messageId: messageId, message: message, contactWillSendsReceipt: contactWillSendsReceipt, + ackByServerAt: ackByServerAt, retryCount: retryCount, lastRetry: lastRetry, createdAt: createdAt, diff --git a/lib/src/model/protobuf/client/generated/messages.pb.dart b/lib/src/model/protobuf/client/generated/messages.pb.dart index bc9d4bd..2facb77 100644 --- a/lib/src/model/protobuf/client/generated/messages.pb.dart +++ b/lib/src/model/protobuf/client/generated/messages.pb.dart @@ -218,6 +218,7 @@ class EncryptedContent_TextMessage extends $pb.GeneratedMessage { factory EncryptedContent_TextMessage({ $core.String? senderMessageId, $core.String? text, + $fixnum.Int64? timestamp, $core.String? quoteMessageId, }) { final $result = create(); @@ -227,6 +228,9 @@ class EncryptedContent_TextMessage extends $pb.GeneratedMessage { if (text != null) { $result.text = text; } + if (timestamp != null) { + $result.timestamp = timestamp; + } if (quoteMessageId != null) { $result.quoteMessageId = quoteMessageId; } @@ -239,7 +243,8 @@ class EncryptedContent_TextMessage extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'EncryptedContent.TextMessage', createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'senderMessageId', protoName: 'senderMessageId') ..aOS(2, _omitFieldNames ? '' : 'text') - ..aOS(3, _omitFieldNames ? '' : 'quoteMessageId', protoName: 'quoteMessageId') + ..aInt64(3, _omitFieldNames ? '' : 'timestamp') + ..aOS(4, _omitFieldNames ? '' : 'quoteMessageId', protoName: 'quoteMessageId') ..hasRequiredFields = false ; @@ -283,13 +288,22 @@ class EncryptedContent_TextMessage extends $pb.GeneratedMessage { void clearText() => clearField(2); @$pb.TagNumber(3) - $core.String get quoteMessageId => $_getSZ(2); + $fixnum.Int64 get timestamp => $_getI64(2); @$pb.TagNumber(3) - set quoteMessageId($core.String v) { $_setString(2, v); } + set timestamp($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) - $core.bool hasQuoteMessageId() => $_has(2); + $core.bool hasTimestamp() => $_has(2); @$pb.TagNumber(3) - void clearQuoteMessageId() => clearField(3); + void clearTimestamp() => clearField(3); + + @$pb.TagNumber(4) + $core.String get quoteMessageId => $_getSZ(3); + @$pb.TagNumber(4) + set quoteMessageId($core.String v) { $_setString(3, v); } + @$pb.TagNumber(4) + $core.bool hasQuoteMessageId() => $_has(3); + @$pb.TagNumber(4) + void clearQuoteMessageId() => clearField(4); } class EncryptedContent_Reaction extends $pb.GeneratedMessage { @@ -374,6 +388,7 @@ class EncryptedContent_MessageUpdate extends $pb.GeneratedMessage { factory EncryptedContent_MessageUpdate({ EncryptedContent_MessageUpdate_Type? type, $core.String? senderMessageId, + $core.Iterable<$core.String>? multipleSenderMessageIds, $core.String? text, $fixnum.Int64? timestamp, }) { @@ -384,6 +399,9 @@ class EncryptedContent_MessageUpdate extends $pb.GeneratedMessage { if (senderMessageId != null) { $result.senderMessageId = senderMessageId; } + if (multipleSenderMessageIds != null) { + $result.multipleSenderMessageIds.addAll(multipleSenderMessageIds); + } if (text != null) { $result.text = text; } @@ -399,8 +417,9 @@ class EncryptedContent_MessageUpdate extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'EncryptedContent.MessageUpdate', createEmptyInstance: create) ..e(1, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, defaultOrMaker: EncryptedContent_MessageUpdate_Type.DELETE, valueOf: EncryptedContent_MessageUpdate_Type.valueOf, enumValues: EncryptedContent_MessageUpdate_Type.values) ..aOS(2, _omitFieldNames ? '' : 'senderMessageId', protoName: 'senderMessageId') - ..aOS(3, _omitFieldNames ? '' : 'text') - ..aInt64(4, _omitFieldNames ? '' : 'timestamp') + ..pPS(3, _omitFieldNames ? '' : 'multipleSenderMessageIds', protoName: 'multipleSenderMessageIds') + ..aOS(4, _omitFieldNames ? '' : 'text') + ..aInt64(5, _omitFieldNames ? '' : 'timestamp') ..hasRequiredFields = false ; @@ -444,22 +463,25 @@ class EncryptedContent_MessageUpdate extends $pb.GeneratedMessage { void clearSenderMessageId() => clearField(2); @$pb.TagNumber(3) - $core.String get text => $_getSZ(2); - @$pb.TagNumber(3) - set text($core.String v) { $_setString(2, v); } - @$pb.TagNumber(3) - $core.bool hasText() => $_has(2); - @$pb.TagNumber(3) - void clearText() => clearField(3); + $core.List<$core.String> get multipleSenderMessageIds => $_getList(2); @$pb.TagNumber(4) - $fixnum.Int64 get timestamp => $_getI64(3); + $core.String get text => $_getSZ(3); @$pb.TagNumber(4) - set timestamp($fixnum.Int64 v) { $_setInt64(3, v); } + set text($core.String v) { $_setString(3, v); } @$pb.TagNumber(4) - $core.bool hasTimestamp() => $_has(3); + $core.bool hasText() => $_has(3); @$pb.TagNumber(4) - void clearTimestamp() => clearField(4); + void clearText() => clearField(4); + + @$pb.TagNumber(5) + $fixnum.Int64 get timestamp => $_getI64(4); + @$pb.TagNumber(5) + set timestamp($fixnum.Int64 v) { $_setInt64(4, v); } + @$pb.TagNumber(5) + $core.bool hasTimestamp() => $_has(4); + @$pb.TagNumber(5) + void clearTimestamp() => clearField(5); } class EncryptedContent_Media extends $pb.GeneratedMessage { @@ -468,6 +490,8 @@ class EncryptedContent_Media extends $pb.GeneratedMessage { EncryptedContent_Media_Type? type, $fixnum.Int64? displayLimitInMilliseconds, $core.bool? requiresAuthentication, + $fixnum.Int64? timestamp, + $core.String? quoteMessageId, $core.List<$core.int>? downloadToken, $core.List<$core.int>? encryptionKey, $core.List<$core.int>? encryptionMac, @@ -486,6 +510,12 @@ class EncryptedContent_Media extends $pb.GeneratedMessage { if (requiresAuthentication != null) { $result.requiresAuthentication = requiresAuthentication; } + if (timestamp != null) { + $result.timestamp = timestamp; + } + if (quoteMessageId != null) { + $result.quoteMessageId = quoteMessageId; + } if (downloadToken != null) { $result.downloadToken = downloadToken; } @@ -506,13 +536,15 @@ class EncryptedContent_Media extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'EncryptedContent.Media', createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'senderMessageId', protoName: 'senderMessageId') - ..e(2, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, defaultOrMaker: EncryptedContent_Media_Type.IMAGE, valueOf: EncryptedContent_Media_Type.valueOf, enumValues: EncryptedContent_Media_Type.values) + ..e(2, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, defaultOrMaker: EncryptedContent_Media_Type.REUPLOAD, valueOf: EncryptedContent_Media_Type.valueOf, enumValues: EncryptedContent_Media_Type.values) ..aInt64(3, _omitFieldNames ? '' : 'displayLimitInMilliseconds', protoName: 'displayLimitInMilliseconds') ..aOB(4, _omitFieldNames ? '' : 'requiresAuthentication', protoName: 'requiresAuthentication') - ..a<$core.List<$core.int>>(5, _omitFieldNames ? '' : 'downloadToken', $pb.PbFieldType.OY, protoName: 'downloadToken') - ..a<$core.List<$core.int>>(6, _omitFieldNames ? '' : 'encryptionKey', $pb.PbFieldType.OY, protoName: 'encryptionKey') - ..a<$core.List<$core.int>>(7, _omitFieldNames ? '' : 'encryptionMac', $pb.PbFieldType.OY, protoName: 'encryptionMac') - ..a<$core.List<$core.int>>(8, _omitFieldNames ? '' : 'encryptionNonce', $pb.PbFieldType.OY, protoName: 'encryptionNonce') + ..aInt64(5, _omitFieldNames ? '' : 'timestamp') + ..aOS(6, _omitFieldNames ? '' : 'quoteMessageId', protoName: 'quoteMessageId') + ..a<$core.List<$core.int>>(7, _omitFieldNames ? '' : 'downloadToken', $pb.PbFieldType.OY, protoName: 'downloadToken') + ..a<$core.List<$core.int>>(8, _omitFieldNames ? '' : 'encryptionKey', $pb.PbFieldType.OY, protoName: 'encryptionKey') + ..a<$core.List<$core.int>>(9, _omitFieldNames ? '' : 'encryptionMac', $pb.PbFieldType.OY, protoName: 'encryptionMac') + ..a<$core.List<$core.int>>(10, _omitFieldNames ? '' : 'encryptionNonce', $pb.PbFieldType.OY, protoName: 'encryptionNonce') ..hasRequiredFields = false ; @@ -574,40 +606,58 @@ class EncryptedContent_Media extends $pb.GeneratedMessage { void clearRequiresAuthentication() => clearField(4); @$pb.TagNumber(5) - $core.List<$core.int> get downloadToken => $_getN(4); + $fixnum.Int64 get timestamp => $_getI64(4); @$pb.TagNumber(5) - set downloadToken($core.List<$core.int> v) { $_setBytes(4, v); } + set timestamp($fixnum.Int64 v) { $_setInt64(4, v); } @$pb.TagNumber(5) - $core.bool hasDownloadToken() => $_has(4); + $core.bool hasTimestamp() => $_has(4); @$pb.TagNumber(5) - void clearDownloadToken() => clearField(5); + void clearTimestamp() => clearField(5); @$pb.TagNumber(6) - $core.List<$core.int> get encryptionKey => $_getN(5); + $core.String get quoteMessageId => $_getSZ(5); @$pb.TagNumber(6) - set encryptionKey($core.List<$core.int> v) { $_setBytes(5, v); } + set quoteMessageId($core.String v) { $_setString(5, v); } @$pb.TagNumber(6) - $core.bool hasEncryptionKey() => $_has(5); + $core.bool hasQuoteMessageId() => $_has(5); @$pb.TagNumber(6) - void clearEncryptionKey() => clearField(6); + void clearQuoteMessageId() => clearField(6); @$pb.TagNumber(7) - $core.List<$core.int> get encryptionMac => $_getN(6); + $core.List<$core.int> get downloadToken => $_getN(6); @$pb.TagNumber(7) - set encryptionMac($core.List<$core.int> v) { $_setBytes(6, v); } + set downloadToken($core.List<$core.int> v) { $_setBytes(6, v); } @$pb.TagNumber(7) - $core.bool hasEncryptionMac() => $_has(6); + $core.bool hasDownloadToken() => $_has(6); @$pb.TagNumber(7) - void clearEncryptionMac() => clearField(7); + void clearDownloadToken() => clearField(7); @$pb.TagNumber(8) - $core.List<$core.int> get encryptionNonce => $_getN(7); + $core.List<$core.int> get encryptionKey => $_getN(7); @$pb.TagNumber(8) - set encryptionNonce($core.List<$core.int> v) { $_setBytes(7, v); } + set encryptionKey($core.List<$core.int> v) { $_setBytes(7, v); } @$pb.TagNumber(8) - $core.bool hasEncryptionNonce() => $_has(7); + $core.bool hasEncryptionKey() => $_has(7); @$pb.TagNumber(8) - void clearEncryptionNonce() => clearField(8); + void clearEncryptionKey() => clearField(8); + + @$pb.TagNumber(9) + $core.List<$core.int> get encryptionMac => $_getN(8); + @$pb.TagNumber(9) + set encryptionMac($core.List<$core.int> v) { $_setBytes(8, v); } + @$pb.TagNumber(9) + $core.bool hasEncryptionMac() => $_has(8); + @$pb.TagNumber(9) + void clearEncryptionMac() => clearField(9); + + @$pb.TagNumber(10) + $core.List<$core.int> get encryptionNonce => $_getN(9); + @$pb.TagNumber(10) + set encryptionNonce($core.List<$core.int> v) { $_setBytes(9, v); } + @$pb.TagNumber(10) + $core.bool hasEncryptionNonce() => $_has(9); + @$pb.TagNumber(10) + void clearEncryptionNonce() => clearField(10); } class EncryptedContent_MediaUpdate extends $pb.GeneratedMessage { @@ -807,6 +857,7 @@ class EncryptedContent_PushKeys extends $pb.GeneratedMessage { EncryptedContent_PushKeys_Type? type, $fixnum.Int64? keyId, $core.List<$core.int>? key, + $fixnum.Int64? createdAt, }) { final $result = create(); if (type != null) { @@ -818,6 +869,9 @@ class EncryptedContent_PushKeys extends $pb.GeneratedMessage { if (key != null) { $result.key = key; } + if (createdAt != null) { + $result.createdAt = createdAt; + } return $result; } EncryptedContent_PushKeys._() : super(); @@ -828,6 +882,7 @@ class EncryptedContent_PushKeys extends $pb.GeneratedMessage { ..e(1, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, defaultOrMaker: EncryptedContent_PushKeys_Type.REQUEST, valueOf: EncryptedContent_PushKeys_Type.valueOf, enumValues: EncryptedContent_PushKeys_Type.values) ..aInt64(2, _omitFieldNames ? '' : 'keyId', protoName: 'keyId') ..a<$core.List<$core.int>>(3, _omitFieldNames ? '' : 'key', $pb.PbFieldType.OY) + ..aInt64(4, _omitFieldNames ? '' : 'createdAt', protoName: 'createdAt') ..hasRequiredFields = false ; @@ -878,6 +933,15 @@ class EncryptedContent_PushKeys extends $pb.GeneratedMessage { $core.bool hasKey() => $_has(2); @$pb.TagNumber(3) void clearKey() => clearField(3); + + @$pb.TagNumber(4) + $fixnum.Int64 get createdAt => $_getI64(3); + @$pb.TagNumber(4) + set createdAt($fixnum.Int64 v) { $_setInt64(3, v); } + @$pb.TagNumber(4) + $core.bool hasCreatedAt() => $_has(3); + @$pb.TagNumber(4) + void clearCreatedAt() => clearField(4); } class EncryptedContent_FlameSync extends $pb.GeneratedMessage { diff --git a/lib/src/model/protobuf/client/generated/messages.pbenum.dart b/lib/src/model/protobuf/client/generated/messages.pbenum.dart index 37118a9..4651437 100644 --- a/lib/src/model/protobuf/client/generated/messages.pbenum.dart +++ b/lib/src/model/protobuf/client/generated/messages.pbenum.dart @@ -18,12 +18,14 @@ class Message_Type extends $pb.ProtobufEnum { static const Message_Type PLAINTEXT_CONTENT = Message_Type._(1, _omitEnumNames ? '' : 'PLAINTEXT_CONTENT'); static const Message_Type CIPHERTEXT = Message_Type._(2, _omitEnumNames ? '' : 'CIPHERTEXT'); static const Message_Type PREKEY_BUNDLE = Message_Type._(3, _omitEnumNames ? '' : 'PREKEY_BUNDLE'); + static const Message_Type TEST_NOTIFICATION = Message_Type._(4, _omitEnumNames ? '' : 'TEST_NOTIFICATION'); static const $core.List values = [ SENDER_DELIVERY_RECEIPT, PLAINTEXT_CONTENT, CIPHERTEXT, PREKEY_BUNDLE, + TEST_NOTIFICATION, ]; static final $core.Map<$core.int, Message_Type> _byValue = $pb.ProtobufEnum.initByValue(values); @@ -65,11 +67,13 @@ class EncryptedContent_MessageUpdate_Type extends $pb.ProtobufEnum { } class EncryptedContent_Media_Type extends $pb.ProtobufEnum { - static const EncryptedContent_Media_Type IMAGE = EncryptedContent_Media_Type._(0, _omitEnumNames ? '' : 'IMAGE'); - static const EncryptedContent_Media_Type VIDEO = EncryptedContent_Media_Type._(1, _omitEnumNames ? '' : 'VIDEO'); - static const EncryptedContent_Media_Type GIF = EncryptedContent_Media_Type._(2, _omitEnumNames ? '' : 'GIF'); + static const EncryptedContent_Media_Type REUPLOAD = EncryptedContent_Media_Type._(0, _omitEnumNames ? '' : 'REUPLOAD'); + static const EncryptedContent_Media_Type IMAGE = EncryptedContent_Media_Type._(1, _omitEnumNames ? '' : 'IMAGE'); + static const EncryptedContent_Media_Type VIDEO = EncryptedContent_Media_Type._(2, _omitEnumNames ? '' : 'VIDEO'); + static const EncryptedContent_Media_Type GIF = EncryptedContent_Media_Type._(3, _omitEnumNames ? '' : 'GIF'); static const $core.List values = [ + REUPLOAD, IMAGE, VIDEO, GIF, diff --git a/lib/src/model/protobuf/client/generated/messages.pbjson.dart b/lib/src/model/protobuf/client/generated/messages.pbjson.dart index 9da2b0c..ef30eb5 100644 --- a/lib/src/model/protobuf/client/generated/messages.pbjson.dart +++ b/lib/src/model/protobuf/client/generated/messages.pbjson.dart @@ -37,6 +37,7 @@ const Message_Type$json = { {'1': 'PLAINTEXT_CONTENT', '2': 1}, {'1': 'CIPHERTEXT', '2': 2}, {'1': 'PREKEY_BUNDLE', '2': 3}, + {'1': 'TEST_NOTIFICATION', '2': 4}, ], }; @@ -45,9 +46,10 @@ final $typed_data.Uint8List messageDescriptor = $convert.base64Decode( 'CgdNZXNzYWdlEiEKBHR5cGUYASABKA4yDS5NZXNzYWdlLlR5cGVSBHR5cGUSHAoJcmVjZWlwdE' 'lkGAIgASgJUglyZWNlaXB0SWQSLwoQZW5jcnlwdGVkQ29udGVudBgDIAEoDEgAUhBlbmNyeXB0' 'ZWRDb250ZW50iAEBEkIKEHBsYWludGV4dENvbnRlbnQYBCABKAsyES5QbGFpbnRleHRDb250ZW' - '50SAFSEHBsYWludGV4dENvbnRlbnSIAQEiXQoEVHlwZRIbChdTRU5ERVJfREVMSVZFUllfUkVD' + '50SAFSEHBsYWludGV4dENvbnRlbnSIAQEidAoEVHlwZRIbChdTRU5ERVJfREVMSVZFUllfUkVD' 'RUlQVBAAEhUKEVBMQUlOVEVYVF9DT05URU5UEAESDgoKQ0lQSEVSVEVYVBACEhEKDVBSRUtFWV' - '9CVU5ETEUQA0ITChFfZW5jcnlwdGVkQ29udGVudEITChFfcGxhaW50ZXh0Q29udGVudA=='); + '9CVU5ETEUQAxIVChFURVNUX05PVElGSUNBVElPThAEQhMKEV9lbmNyeXB0ZWRDb250ZW50QhMK' + 'EV9wbGFpbnRleHRDb250ZW50'); @$core.Deprecated('Use plaintextContentDescriptor instead') const PlaintextContent$json = { @@ -126,7 +128,8 @@ const EncryptedContent_TextMessage$json = { '2': [ {'1': 'senderMessageId', '3': 1, '4': 1, '5': 9, '10': 'senderMessageId'}, {'1': 'text', '3': 2, '4': 1, '5': 9, '10': 'text'}, - {'1': 'quoteMessageId', '3': 3, '4': 1, '5': 9, '9': 0, '10': 'quoteMessageId', '17': true}, + {'1': 'timestamp', '3': 3, '4': 1, '5': 3, '10': 'timestamp'}, + {'1': 'quoteMessageId', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'quoteMessageId', '17': true}, ], '8': [ {'1': '_quoteMessageId'}, @@ -152,14 +155,15 @@ const EncryptedContent_MessageUpdate$json = { '1': 'MessageUpdate', '2': [ {'1': 'type', '3': 1, '4': 1, '5': 14, '6': '.EncryptedContent.MessageUpdate.Type', '10': 'type'}, - {'1': 'senderMessageId', '3': 2, '4': 1, '5': 9, '10': 'senderMessageId'}, - {'1': 'text', '3': 3, '4': 1, '5': 9, '9': 0, '10': 'text', '17': true}, - {'1': 'timestamp', '3': 4, '4': 1, '5': 3, '9': 1, '10': 'timestamp', '17': true}, + {'1': 'senderMessageId', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'senderMessageId', '17': true}, + {'1': 'multipleSenderMessageIds', '3': 3, '4': 3, '5': 9, '10': 'multipleSenderMessageIds'}, + {'1': 'text', '3': 4, '4': 1, '5': 9, '9': 1, '10': 'text', '17': true}, + {'1': 'timestamp', '3': 5, '4': 1, '5': 3, '10': 'timestamp'}, ], '4': [EncryptedContent_MessageUpdate_Type$json], '8': [ + {'1': '_senderMessageId'}, {'1': '_text'}, - {'1': '_timestamp'}, ], }; @@ -181,14 +185,17 @@ const EncryptedContent_Media$json = { {'1': 'type', '3': 2, '4': 1, '5': 14, '6': '.EncryptedContent.Media.Type', '10': 'type'}, {'1': 'displayLimitInMilliseconds', '3': 3, '4': 1, '5': 3, '9': 0, '10': 'displayLimitInMilliseconds', '17': true}, {'1': 'requiresAuthentication', '3': 4, '4': 1, '5': 8, '10': 'requiresAuthentication'}, - {'1': 'downloadToken', '3': 5, '4': 1, '5': 12, '9': 1, '10': 'downloadToken', '17': true}, - {'1': 'encryptionKey', '3': 6, '4': 1, '5': 12, '9': 2, '10': 'encryptionKey', '17': true}, - {'1': 'encryptionMac', '3': 7, '4': 1, '5': 12, '9': 3, '10': 'encryptionMac', '17': true}, - {'1': 'encryptionNonce', '3': 8, '4': 1, '5': 12, '9': 4, '10': 'encryptionNonce', '17': true}, + {'1': 'timestamp', '3': 5, '4': 1, '5': 3, '10': 'timestamp'}, + {'1': 'quoteMessageId', '3': 6, '4': 1, '5': 9, '9': 1, '10': 'quoteMessageId', '17': true}, + {'1': 'downloadToken', '3': 7, '4': 1, '5': 12, '9': 2, '10': 'downloadToken', '17': true}, + {'1': 'encryptionKey', '3': 8, '4': 1, '5': 12, '9': 3, '10': 'encryptionKey', '17': true}, + {'1': 'encryptionMac', '3': 9, '4': 1, '5': 12, '9': 4, '10': 'encryptionMac', '17': true}, + {'1': 'encryptionNonce', '3': 10, '4': 1, '5': 12, '9': 5, '10': 'encryptionNonce', '17': true}, ], '4': [EncryptedContent_Media_Type$json], '8': [ {'1': '_displayLimitInMilliseconds'}, + {'1': '_quoteMessageId'}, {'1': '_downloadToken'}, {'1': '_encryptionKey'}, {'1': '_encryptionMac'}, @@ -200,9 +207,10 @@ const EncryptedContent_Media$json = { const EncryptedContent_Media_Type$json = { '1': 'Type', '2': [ - {'1': 'IMAGE', '2': 0}, - {'1': 'VIDEO', '2': 1}, - {'1': 'GIF', '2': 2}, + {'1': 'REUPLOAD', '2': 0}, + {'1': 'IMAGE', '2': 1}, + {'1': 'VIDEO', '2': 2}, + {'1': 'GIF', '2': 3}, ], }; @@ -276,11 +284,13 @@ const EncryptedContent_PushKeys$json = { {'1': 'type', '3': 1, '4': 1, '5': 14, '6': '.EncryptedContent.PushKeys.Type', '10': 'type'}, {'1': 'keyId', '3': 2, '4': 1, '5': 3, '9': 0, '10': 'keyId', '17': true}, {'1': 'key', '3': 3, '4': 1, '5': 12, '9': 1, '10': 'key', '17': true}, + {'1': 'createdAt', '3': 4, '4': 1, '5': 3, '9': 2, '10': 'createdAt', '17': true}, ], '4': [EncryptedContent_PushKeys_Type$json], '8': [ {'1': '_keyId'}, {'1': '_key'}, + {'1': '_createdAt'}, ], }; @@ -317,42 +327,47 @@ final $typed_data.Uint8List encryptedContentDescriptor = $convert.base64Decode( 'N0UmVxdWVzdEgHUg5jb250YWN0UmVxdWVzdIgBARI+CglmbGFtZVN5bmMYCiABKAsyGy5FbmNy' 'eXB0ZWRDb250ZW50LkZsYW1lU3luY0gIUglmbGFtZVN5bmOIAQESOwoIcHVzaEtleXMYCyABKA' 'syGi5FbmNyeXB0ZWRDb250ZW50LlB1c2hLZXlzSAlSCHB1c2hLZXlziAEBEjsKCHJlYWN0aW9u' - 'GAwgASgLMhouRW5jcnlwdGVkQ29udGVudC5SZWFjdGlvbkgKUghyZWFjdGlvbogBARqLAQoLVG' + 'GAwgASgLMhouRW5jcnlwdGVkQ29udGVudC5SZWFjdGlvbkgKUghyZWFjdGlvbogBARqpAQoLVG' 'V4dE1lc3NhZ2USKAoPc2VuZGVyTWVzc2FnZUlkGAEgASgJUg9zZW5kZXJNZXNzYWdlSWQSEgoE' - 'dGV4dBgCIAEoCVIEdGV4dBIrCg5xdW90ZU1lc3NhZ2VJZBgDIAEoCUgAUg5xdW90ZU1lc3NhZ2' - 'VJZIgBAUIRCg9fcXVvdGVNZXNzYWdlSWQagQEKCFJlYWN0aW9uEigKD3RhcmdldE1lc3NhZ2VJ' - 'ZBgBIAEoCVIPdGFyZ2V0TWVzc2FnZUlkEhkKBWVtb2ppGAIgASgJSABSBWVtb2ppiAEBEhsKBn' - 'JlbW92ZRgDIAEoCEgBUgZyZW1vdmWIAQFCCAoGX2Vtb2ppQgkKB19yZW1vdmUa9QEKDU1lc3Nh' - 'Z2VVcGRhdGUSOAoEdHlwZRgBIAEoDjIkLkVuY3J5cHRlZENvbnRlbnQuTWVzc2FnZVVwZGF0ZS' - '5UeXBlUgR0eXBlEigKD3NlbmRlck1lc3NhZ2VJZBgCIAEoCVIPc2VuZGVyTWVzc2FnZUlkEhcK' - 'BHRleHQYAyABKAlIAFIEdGV4dIgBARIhCgl0aW1lc3RhbXAYBCABKANIAVIJdGltZXN0YW1wiA' - 'EBIi0KBFR5cGUSCgoGREVMRVRFEAASDQoJRURJVF9URVhUEAESCgoGT1BFTkVEEAJCBwoFX3Rl' - 'eHRCDAoKX3RpbWVzdGFtcBqgBAoFTWVkaWESKAoPc2VuZGVyTWVzc2FnZUlkGAEgASgJUg9zZW' - '5kZXJNZXNzYWdlSWQSMAoEdHlwZRgCIAEoDjIcLkVuY3J5cHRlZENvbnRlbnQuTWVkaWEuVHlw' - 'ZVIEdHlwZRJDChpkaXNwbGF5TGltaXRJbk1pbGxpc2Vjb25kcxgDIAEoA0gAUhpkaXNwbGF5TG' - 'ltaXRJbk1pbGxpc2Vjb25kc4gBARI2ChZyZXF1aXJlc0F1dGhlbnRpY2F0aW9uGAQgASgIUhZy' - 'ZXF1aXJlc0F1dGhlbnRpY2F0aW9uEikKDWRvd25sb2FkVG9rZW4YBSABKAxIAVINZG93bmxvYW' - 'RUb2tlbogBARIpCg1lbmNyeXB0aW9uS2V5GAYgASgMSAJSDWVuY3J5cHRpb25LZXmIAQESKQoN' - 'ZW5jcnlwdGlvbk1hYxgHIAEoDEgDUg1lbmNyeXB0aW9uTWFjiAEBEi0KD2VuY3J5cHRpb25Ob2' - '5jZRgIIAEoDEgEUg9lbmNyeXB0aW9uTm9uY2WIAQEiJQoEVHlwZRIJCgVJTUFHRRAAEgkKBVZJ' - 'REVPEAESBwoDR0lGEAJCHQobX2Rpc3BsYXlMaW1pdEluTWlsbGlzZWNvbmRzQhAKDl9kb3dubG' - '9hZFRva2VuQhAKDl9lbmNyeXB0aW9uS2V5QhAKDl9lbmNyeXB0aW9uTWFjQhIKEF9lbmNyeXB0' - 'aW9uTm9uY2UapwEKC01lZGlhVXBkYXRlEjYKBHR5cGUYASABKA4yIi5FbmNyeXB0ZWRDb250ZW' - '50Lk1lZGlhVXBkYXRlLlR5cGVSBHR5cGUSKAoPdGFyZ2V0TWVzc2FnZUlkGAIgASgJUg90YXJn' - 'ZXRNZXNzYWdlSWQiNgoEVHlwZRIMCghSRU9QRU5FRBAAEgoKBlNUT1JFRBABEhQKEERFQ1JZUF' - 'RJT05fRVJST1IQAhp4Cg5Db250YWN0UmVxdWVzdBI5CgR0eXBlGAEgASgOMiUuRW5jcnlwdGVk' - 'Q29udGVudC5Db250YWN0UmVxdWVzdC5UeXBlUgR0eXBlIisKBFR5cGUSCwoHUkVRVUVTVBAAEg' - 'oKBlJFSkVDVBABEgoKBkFDQ0VQVBACGtIBCg1Db250YWN0VXBkYXRlEjgKBHR5cGUYASABKA4y' - 'JC5FbmNyeXB0ZWRDb250ZW50LkNvbnRhY3RVcGRhdGUuVHlwZVIEdHlwZRIhCglhdmF0YXJTdm' - 'cYAiABKAlIAFIJYXZhdGFyU3ZniAEBEiUKC2Rpc3BsYXlOYW1lGAMgASgJSAFSC2Rpc3BsYXlO' - 'YW1liAEBIh8KBFR5cGUSCwoHUkVRVUVTVBAAEgoKBlVQREFURRABQgwKCl9hdmF0YXJTdmdCDg' - 'oMX2Rpc3BsYXlOYW1lGqQBCghQdXNoS2V5cxIzCgR0eXBlGAEgASgOMh8uRW5jcnlwdGVkQ29u' - 'dGVudC5QdXNoS2V5cy5UeXBlUgR0eXBlEhkKBWtleUlkGAIgASgDSABSBWtleUlkiAEBEhUKA2' - 'tleRgDIAEoDEgBUgNrZXmIAQEiHwoEVHlwZRILCgdSRVFVRVNUEAASCgoGVVBEQVRFEAFCCAoG' - 'X2tleUlkQgYKBF9rZXkahwEKCUZsYW1lU3luYxIiCgxmbGFtZUNvdW50ZXIYASABKANSDGZsYW' - '1lQ291bnRlchI2ChZsYXN0RmxhbWVDb3VudGVyQ2hhbmdlGAIgASgDUhZsYXN0RmxhbWVDb3Vu' - 'dGVyQ2hhbmdlEh4KCmJlc3RGcmllbmQYAyABKAhSCmJlc3RGcmllbmRCCgoIX2dyb3VwSWRCFw' - 'oVX3NlbmRlclByb2ZpbGVDb3VudGVyQg4KDF90ZXh0TWVzc2FnZUIQCg5fbWVzc2FnZVVwZGF0' - 'ZUIICgZfbWVkaWFCDgoMX21lZGlhVXBkYXRlQhAKDl9jb250YWN0VXBkYXRlQhEKD19jb250YW' - 'N0UmVxdWVzdEIMCgpfZmxhbWVTeW5jQgsKCV9wdXNoS2V5c0ILCglfcmVhY3Rpb24='); + 'dGV4dBgCIAEoCVIEdGV4dBIcCgl0aW1lc3RhbXAYAyABKANSCXRpbWVzdGFtcBIrCg5xdW90ZU' + '1lc3NhZ2VJZBgEIAEoCUgAUg5xdW90ZU1lc3NhZ2VJZIgBAUIRCg9fcXVvdGVNZXNzYWdlSWQa' + 'gQEKCFJlYWN0aW9uEigKD3RhcmdldE1lc3NhZ2VJZBgBIAEoCVIPdGFyZ2V0TWVzc2FnZUlkEh' + 'kKBWVtb2ppGAIgASgJSABSBWVtb2ppiAEBEhsKBnJlbW92ZRgDIAEoCEgBUgZyZW1vdmWIAQFC' + 'CAoGX2Vtb2ppQgkKB19yZW1vdmUatwIKDU1lc3NhZ2VVcGRhdGUSOAoEdHlwZRgBIAEoDjIkLk' + 'VuY3J5cHRlZENvbnRlbnQuTWVzc2FnZVVwZGF0ZS5UeXBlUgR0eXBlEi0KD3NlbmRlck1lc3Nh' + 'Z2VJZBgCIAEoCUgAUg9zZW5kZXJNZXNzYWdlSWSIAQESOgoYbXVsdGlwbGVTZW5kZXJNZXNzYW' + 'dlSWRzGAMgAygJUhhtdWx0aXBsZVNlbmRlck1lc3NhZ2VJZHMSFwoEdGV4dBgEIAEoCUgBUgR0' + 'ZXh0iAEBEhwKCXRpbWVzdGFtcBgFIAEoA1IJdGltZXN0YW1wIi0KBFR5cGUSCgoGREVMRVRFEA' + 'ASDQoJRURJVF9URVhUEAESCgoGT1BFTkVEEAJCEgoQX3NlbmRlck1lc3NhZ2VJZEIHCgVfdGV4' + 'dBqMBQoFTWVkaWESKAoPc2VuZGVyTWVzc2FnZUlkGAEgASgJUg9zZW5kZXJNZXNzYWdlSWQSMA' + 'oEdHlwZRgCIAEoDjIcLkVuY3J5cHRlZENvbnRlbnQuTWVkaWEuVHlwZVIEdHlwZRJDChpkaXNw' + 'bGF5TGltaXRJbk1pbGxpc2Vjb25kcxgDIAEoA0gAUhpkaXNwbGF5TGltaXRJbk1pbGxpc2Vjb2' + '5kc4gBARI2ChZyZXF1aXJlc0F1dGhlbnRpY2F0aW9uGAQgASgIUhZyZXF1aXJlc0F1dGhlbnRp' + 'Y2F0aW9uEhwKCXRpbWVzdGFtcBgFIAEoA1IJdGltZXN0YW1wEisKDnF1b3RlTWVzc2FnZUlkGA' + 'YgASgJSAFSDnF1b3RlTWVzc2FnZUlkiAEBEikKDWRvd25sb2FkVG9rZW4YByABKAxIAlINZG93' + 'bmxvYWRUb2tlbogBARIpCg1lbmNyeXB0aW9uS2V5GAggASgMSANSDWVuY3J5cHRpb25LZXmIAQ' + 'ESKQoNZW5jcnlwdGlvbk1hYxgJIAEoDEgEUg1lbmNyeXB0aW9uTWFjiAEBEi0KD2VuY3J5cHRp' + 'b25Ob25jZRgKIAEoDEgFUg9lbmNyeXB0aW9uTm9uY2WIAQEiMwoEVHlwZRIMCghSRVVQTE9BRB' + 'AAEgkKBUlNQUdFEAESCQoFVklERU8QAhIHCgNHSUYQA0IdChtfZGlzcGxheUxpbWl0SW5NaWxs' + 'aXNlY29uZHNCEQoPX3F1b3RlTWVzc2FnZUlkQhAKDl9kb3dubG9hZFRva2VuQhAKDl9lbmNyeX' + 'B0aW9uS2V5QhAKDl9lbmNyeXB0aW9uTWFjQhIKEF9lbmNyeXB0aW9uTm9uY2UapwEKC01lZGlh' + 'VXBkYXRlEjYKBHR5cGUYASABKA4yIi5FbmNyeXB0ZWRDb250ZW50Lk1lZGlhVXBkYXRlLlR5cG' + 'VSBHR5cGUSKAoPdGFyZ2V0TWVzc2FnZUlkGAIgASgJUg90YXJnZXRNZXNzYWdlSWQiNgoEVHlw' + 'ZRIMCghSRU9QRU5FRBAAEgoKBlNUT1JFRBABEhQKEERFQ1JZUFRJT05fRVJST1IQAhp4Cg5Db2' + '50YWN0UmVxdWVzdBI5CgR0eXBlGAEgASgOMiUuRW5jcnlwdGVkQ29udGVudC5Db250YWN0UmVx' + 'dWVzdC5UeXBlUgR0eXBlIisKBFR5cGUSCwoHUkVRVUVTVBAAEgoKBlJFSkVDVBABEgoKBkFDQ0' + 'VQVBACGtIBCg1Db250YWN0VXBkYXRlEjgKBHR5cGUYASABKA4yJC5FbmNyeXB0ZWRDb250ZW50' + 'LkNvbnRhY3RVcGRhdGUuVHlwZVIEdHlwZRIhCglhdmF0YXJTdmcYAiABKAlIAFIJYXZhdGFyU3' + 'ZniAEBEiUKC2Rpc3BsYXlOYW1lGAMgASgJSAFSC2Rpc3BsYXlOYW1liAEBIh8KBFR5cGUSCwoH' + 'UkVRVUVTVBAAEgoKBlVQREFURRABQgwKCl9hdmF0YXJTdmdCDgoMX2Rpc3BsYXlOYW1lGtUBCg' + 'hQdXNoS2V5cxIzCgR0eXBlGAEgASgOMh8uRW5jcnlwdGVkQ29udGVudC5QdXNoS2V5cy5UeXBl' + 'UgR0eXBlEhkKBWtleUlkGAIgASgDSABSBWtleUlkiAEBEhUKA2tleRgDIAEoDEgBUgNrZXmIAQ' + 'ESIQoJY3JlYXRlZEF0GAQgASgDSAJSCWNyZWF0ZWRBdIgBASIfCgRUeXBlEgsKB1JFUVVFU1QQ' + 'ABIKCgZVUERBVEUQAUIICgZfa2V5SWRCBgoEX2tleUIMCgpfY3JlYXRlZEF0GocBCglGbGFtZV' + 'N5bmMSIgoMZmxhbWVDb3VudGVyGAEgASgDUgxmbGFtZUNvdW50ZXISNgoWbGFzdEZsYW1lQ291' + 'bnRlckNoYW5nZRgCIAEoA1IWbGFzdEZsYW1lQ291bnRlckNoYW5nZRIeCgpiZXN0RnJpZW5kGA' + 'MgASgIUgpiZXN0RnJpZW5kQgoKCF9ncm91cElkQhcKFV9zZW5kZXJQcm9maWxlQ291bnRlckIO' + 'CgxfdGV4dE1lc3NhZ2VCEAoOX21lc3NhZ2VVcGRhdGVCCAoGX21lZGlhQg4KDF9tZWRpYVVwZG' + 'F0ZUIQCg5fY29udGFjdFVwZGF0ZUIRCg9fY29udGFjdFJlcXVlc3RCDAoKX2ZsYW1lU3luY0IL' + 'CglfcHVzaEtleXNCCwoJX3JlYWN0aW9u'); diff --git a/lib/src/model/protobuf/client/generated/push_notification.pb.dart b/lib/src/model/protobuf/client/generated/push_notification.pb.dart index c0e8a0d..eb929fd 100644 --- a/lib/src/model/protobuf/client/generated/push_notification.pb.dart +++ b/lib/src/model/protobuf/client/generated/push_notification.pb.dart @@ -113,7 +113,7 @@ class EncryptedPushNotification extends $pb.GeneratedMessage { class PushNotification extends $pb.GeneratedMessage { factory PushNotification({ PushKind? kind, - $fixnum.Int64? messageId, + $core.String? messageId, $core.String? reactionContent, }) { final $result = create(); @@ -134,7 +134,7 @@ class PushNotification extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PushNotification', createEmptyInstance: create) ..e(1, _omitFieldNames ? '' : 'kind', $pb.PbFieldType.OE, defaultOrMaker: PushKind.reaction, valueOf: PushKind.valueOf, enumValues: PushKind.values) - ..aInt64(2, _omitFieldNames ? '' : 'messageId', protoName: 'messageId') + ..aOS(2, _omitFieldNames ? '' : 'messageId', protoName: 'messageId') ..aOS(3, _omitFieldNames ? '' : 'reactionContent', protoName: 'reactionContent') ..hasRequiredFields = false ; @@ -170,9 +170,9 @@ class PushNotification extends $pb.GeneratedMessage { void clearKind() => clearField(1); @$pb.TagNumber(2) - $fixnum.Int64 get messageId => $_getI64(1); + $core.String get messageId => $_getSZ(1); @$pb.TagNumber(2) - set messageId($fixnum.Int64 v) { $_setInt64(1, v); } + set messageId($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasMessageId() => $_has(1); @$pb.TagNumber(2) @@ -237,7 +237,7 @@ class PushUser extends $pb.GeneratedMessage { $fixnum.Int64? userId, $core.String? displayName, $core.bool? blocked, - $fixnum.Int64? lastMessageId, + $core.String? lastMessageId, $core.Iterable? pushKeys, }) { final $result = create(); @@ -266,7 +266,7 @@ class PushUser extends $pb.GeneratedMessage { ..aInt64(1, _omitFieldNames ? '' : 'userId', protoName: 'userId') ..aOS(2, _omitFieldNames ? '' : 'displayName', protoName: 'displayName') ..aOB(3, _omitFieldNames ? '' : 'blocked') - ..aInt64(4, _omitFieldNames ? '' : 'lastMessageId', protoName: 'lastMessageId') + ..aOS(4, _omitFieldNames ? '' : 'lastMessageId', protoName: 'lastMessageId') ..pc(5, _omitFieldNames ? '' : 'pushKeys', $pb.PbFieldType.PM, protoName: 'pushKeys', subBuilder: PushKey.create) ..hasRequiredFields = false ; @@ -320,9 +320,9 @@ class PushUser extends $pb.GeneratedMessage { void clearBlocked() => clearField(3); @$pb.TagNumber(4) - $fixnum.Int64 get lastMessageId => $_getI64(3); + $core.String get lastMessageId => $_getSZ(3); @$pb.TagNumber(4) - set lastMessageId($fixnum.Int64 v) { $_setInt64(3, v); } + set lastMessageId($core.String v) { $_setString(3, v); } @$pb.TagNumber(4) $core.bool hasLastMessageId() => $_has(3); @$pb.TagNumber(4) diff --git a/lib/src/model/protobuf/client/generated/push_notification.pbjson.dart b/lib/src/model/protobuf/client/generated/push_notification.pbjson.dart index d66d5aa..8ff6dc0 100644 --- a/lib/src/model/protobuf/client/generated/push_notification.pbjson.dart +++ b/lib/src/model/protobuf/client/generated/push_notification.pbjson.dart @@ -64,7 +64,7 @@ const PushNotification$json = { '1': 'PushNotification', '2': [ {'1': 'kind', '3': 1, '4': 1, '5': 14, '6': '.PushKind', '10': 'kind'}, - {'1': 'messageId', '3': 2, '4': 1, '5': 3, '9': 0, '10': 'messageId', '17': true}, + {'1': 'messageId', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'messageId', '17': true}, {'1': 'reactionContent', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'reactionContent', '17': true}, ], '8': [ @@ -76,7 +76,7 @@ const PushNotification$json = { /// Descriptor for `PushNotification`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List pushNotificationDescriptor = $convert.base64Decode( 'ChBQdXNoTm90aWZpY2F0aW9uEh0KBGtpbmQYASABKA4yCS5QdXNoS2luZFIEa2luZBIhCgltZX' - 'NzYWdlSWQYAiABKANIAFIJbWVzc2FnZUlkiAEBEi0KD3JlYWN0aW9uQ29udGVudBgDIAEoCUgB' + 'NzYWdlSWQYAiABKAlIAFIJbWVzc2FnZUlkiAEBEi0KD3JlYWN0aW9uQ29udGVudBgDIAEoCUgB' 'Ug9yZWFjdGlvbkNvbnRlbnSIAQFCDAoKX21lc3NhZ2VJZEISChBfcmVhY3Rpb25Db250ZW50'); @$core.Deprecated('Use pushUsersDescriptor instead') @@ -98,7 +98,7 @@ const PushUser$json = { {'1': 'userId', '3': 1, '4': 1, '5': 3, '10': 'userId'}, {'1': 'displayName', '3': 2, '4': 1, '5': 9, '10': 'displayName'}, {'1': 'blocked', '3': 3, '4': 1, '5': 8, '10': 'blocked'}, - {'1': 'lastMessageId', '3': 4, '4': 1, '5': 3, '9': 0, '10': 'lastMessageId', '17': true}, + {'1': 'lastMessageId', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'lastMessageId', '17': true}, {'1': 'pushKeys', '3': 5, '4': 3, '5': 11, '6': '.PushKey', '10': 'pushKeys'}, ], '8': [ @@ -110,7 +110,7 @@ const PushUser$json = { final $typed_data.Uint8List pushUserDescriptor = $convert.base64Decode( 'CghQdXNoVXNlchIWCgZ1c2VySWQYASABKANSBnVzZXJJZBIgCgtkaXNwbGF5TmFtZRgCIAEoCV' 'ILZGlzcGxheU5hbWUSGAoHYmxvY2tlZBgDIAEoCFIHYmxvY2tlZBIpCg1sYXN0TWVzc2FnZUlk' - 'GAQgASgDSABSDWxhc3RNZXNzYWdlSWSIAQESJAoIcHVzaEtleXMYBSADKAsyCC5QdXNoS2V5Ug' + 'GAQgASgJSABSDWxhc3RNZXNzYWdlSWSIAQESJAoIcHVzaEtleXMYBSADKAsyCC5QdXNoS2V5Ug' 'hwdXNoS2V5c0IQCg5fbGFzdE1lc3NhZ2VJZA=='); @$core.Deprecated('Use pushKeyDescriptor instead') diff --git a/lib/src/model/protobuf/client/messages.proto b/lib/src/model/protobuf/client/messages.proto index 39b3105..d8dc45d 100644 --- a/lib/src/model/protobuf/client/messages.proto +++ b/lib/src/model/protobuf/client/messages.proto @@ -6,6 +6,7 @@ message Message { PLAINTEXT_CONTENT = 1; CIPHERTEXT = 2; PREKEY_BUNDLE = 3; + TEST_NOTIFICATION = 4; } Type type = 1; string receiptId = 2; @@ -46,7 +47,8 @@ message EncryptedContent { message TextMessage { string senderMessageId = 1; string text = 2; - optional string quoteMessageId = 3; + int64 timestamp = 3; + optional string quoteMessageId = 4; } message Reaction { @@ -62,27 +64,31 @@ message EncryptedContent { OPENED = 2; } Type type = 1; - string senderMessageId = 2; - optional string text = 3; - optional int64 timestamp = 4; + optional string senderMessageId = 2; + repeated string multipleSenderMessageIds = 3; + optional string text = 4; + int64 timestamp = 5; } message Media { enum Type { - IMAGE = 0; - VIDEO = 1; - GIF = 2; + REUPLOAD = 0; + IMAGE = 1; + VIDEO = 2; + GIF = 3; } string senderMessageId = 1; Type type = 2; optional int64 displayLimitInMilliseconds = 3; bool requiresAuthentication = 4; + int64 timestamp = 5; + optional string quoteMessageId = 6; - optional bytes downloadToken = 5; - optional bytes encryptionKey = 6; - optional bytes encryptionMac = 7; - optional bytes encryptionNonce = 8; + optional bytes downloadToken = 7; + optional bytes encryptionKey = 8; + optional bytes encryptionMac = 9; + optional bytes encryptionNonce = 10; } message MediaUpdate { @@ -124,6 +130,7 @@ message EncryptedContent { Type type = 1; optional int64 keyId = 2; optional bytes key = 3; + optional int64 createdAt = 4; } message FlameSync { diff --git a/lib/src/model/protobuf/client/push_notification.proto b/lib/src/model/protobuf/client/push_notification.proto index 3c19946..0abeedb 100644 --- a/lib/src/model/protobuf/client/push_notification.proto +++ b/lib/src/model/protobuf/client/push_notification.proto @@ -26,7 +26,7 @@ enum PushKind { message PushNotification { PushKind kind = 1; - optional int64 messageId = 2; + optional string messageId = 2; optional string reactionContent = 3; } @@ -39,7 +39,7 @@ message PushUser { int64 userId = 1; string displayName = 2; bool blocked = 3; - optional int64 lastMessageId = 4; + optional string lastMessageId = 4; repeated PushKey pushKeys = 5; } diff --git a/lib/src/services/api.service.dart b/lib/src/services/api.service.dart index 8a54cff..07b2dcd 100644 --- a/lib/src/services/api.service.dart +++ b/lib/src/services/api.service.dart @@ -114,7 +114,7 @@ class ApiService { _channel = null; isAuthenticated = false; globalCallbackConnectionState(isConnected: false); - await twonlyDB.messagesDao.resetPendingDownloadState(); + await twonlyDB.mediaFilesDao.resetPendingDownloadState(); } Future startReconnectionTimer() async { diff --git a/lib/src/services/api/media_download.dart b/lib/src/services/api/media_download.dart index 0c2708d..61887ed 100644 --- a/lib/src/services/api/media_download.dart +++ b/lib/src/services/api/media_download.dart @@ -119,7 +119,7 @@ Future handleDownloadStatusUpdateInternal( Mutex protectDownload = Mutex(); -Future startDownloadMedia(Message message, bool force) async { +Future startDownloadMedia(MediaFile media, bool force) async { Log.info( 'Download blocked for ${message.messageId} because of network state.', ); diff --git a/lib/src/services/api/messages.dart b/lib/src/services/api/messages.dart index 08cbb6c..a76fcc3 100644 --- a/lib/src/services/api/messages.dart +++ b/lib/src/services/api/messages.dart @@ -1,163 +1,153 @@ import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:cryptography_plus/cryptography_plus.dart'; import 'package:drift/drift.dart'; -import 'package:fixnum/fixnum.dart'; +import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:mutex/mutex.dart'; import 'package:twonly/globals.dart'; -import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/model/json/message_old.dart'; import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart'; import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart' as pb; -import 'package:twonly/src/model/protobuf/push_notification/push_notification.pb.dart'; -import 'package:twonly/src/services/api/server_messages.dart' - show messageGetsAck; +import 'package:twonly/src/model/protobuf/client/generated/push_notification.pb.dart'; import 'package:twonly/src/services/notifications/pushkeys.notifications.dart'; import 'package:twonly/src/services/signal/encryption.signal.dart'; import 'package:twonly/src/utils/log.dart'; +import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/storage.dart'; final lockRetransmission = Mutex(); Future tryTransmitMessages() async { return lockRetransmission.protect(() async { - final retransIds = - await twonlyDB.messageRetransmissionDao.getRetransmitAbleMessages(); + final receipts = await twonlyDB.receiptsDao.getReceiptsNotAckByServer(); - Log.info('Retransmitting ${retransIds.length} text messages'); + if (receipts.isEmpty) return; - if (retransIds.isEmpty) return; + Log.info('Reuploading ${receipts.length} messages to the server.'); - for (final retransId in retransIds) { - await sendRetransmitMessage(retransId); + for (final receipt in receipts) { + await tryToSendCompleteMessage(receipt: receipt); } }); } -Future tryToSendCompleteMessage(String receiptId) async { +Future tryToSendCompleteMessage({ + String? receiptId, + Receipt? receipt, + bool reupload = false, +}) async { try { - final retrans = await twonlyDB.messageRetransmissionDao - .getRetransmissionById(retransId) - .getSingleOrNull(); - - /// SET THE Message().receiptID !!!!!!! - /// ALSO THE encryptedContent is NOT YET ENCRYPTED! - - if (retrans == null) { - Log.error('$retransId not found in database'); - return; - } - - if (retrans.acknowledgeByServerAt != null) { - Log.error('$retransId message already retransmitted'); - return; - } - - final json = MessageJson.fromJson( - jsonDecode( - utf8.decode( - gzip.decode(retrans.plaintextContent), - ), - ) as Map, - ); - - Log.info('Retransmitting $retransId: ${json.kind} to ${retrans.contactId}'); - - final contact = await twonlyDB.contactsDao - .getContactByUserId(retrans.contactId) - .getSingleOrNull(); - if (contact == null || contact.deleted) { - Log.warn('Contact deleted $retransId or not found in database.'); - await twonlyDB.messageRetransmissionDao - .deleteRetransmissionById(retransId); - if (retrans.messageId != null) { - await twonlyDB.messagesDao.updateMessageByMessageId( - retrans.messageId!, - const MessagesCompanion(errorWhileSending: Value(true)), - ); + if (receiptId == null && receipt == null) return; + if (receipt == null) { + receipt = await twonlyDB.receiptsDao.getReceiptById(receiptId!); + if (receipt == null) { + Log.error('Receipt $receiptId not found.'); + return; } + } + receiptId = receipt.receiptId; + + if (reupload) { + await twonlyDB.receiptsDao.updateReceipt( + receiptId, + const ReceiptsCompanion( + ackByServerAt: Value(null), + ), + ); + } + + if (receipt.ackByServerAt != null) { + Log.error('$receiptId message already uploaded!'); return; } - final encryptedBytes = await signalEncryptMessage( - retrans.contactId, - retrans.plaintextContent, + Log.info('Uploading $receiptId (Message to ${receipt.contactId})'); + + final message = pb.Message.fromBuffer(receipt.message) + ..receiptId = receiptId; + + final encryptedContent = + pb.EncryptedContent.fromBuffer(message.encryptedContent); + + var pushData = await getPushDataFromEncryptedContent( + receipt.contactId, + receipt.messageId, + encryptedContent, ); - if (encryptedBytes == null) { - Log.error('Could not encrypt the message. Aborting and trying again.'); - return; + if (message.type == pb.Message_Type.TEST_NOTIFICATION) { + pushData = (PushNotification()..kind = PushKind.testNotification) + .writeToBuffer(); } - final encryptedHash = (await Sha256().hash(encryptedBytes)).bytes; - - await twonlyDB.messageRetransmissionDao.updateRetransmission( - retransId, - MessageRetransmissionsCompanion( - encryptedHash: Value(Uint8List.fromList(encryptedHash)), - ), - ); + if (message.type == pb.Message_Type.CIPHERTEXT) { + final cipherText = await signalEncryptMessage( + receipt.contactId, + Uint8List.fromList(message.encryptedContent), + ); + if (cipherText == null) { + Log.error('Could not encrypt the message. Aborting and trying again.'); + return; + } + message.encryptedContent = cipherText.serialize(); + switch (cipherText.getType()) { + case CiphertextMessage.prekeyType: + message.type = pb.Message_Type.PREKEY_BUNDLE; + case CiphertextMessage.whisperType: + message.type = pb.Message_Type.CIPHERTEXT; + default: + Log.error('Invalid ciphertext type: ${cipherText.getType()}.'); + return; + } + } final resp = await apiService.sendTextMessage( - retrans.contactId, - encryptedBytes, - retrans.pushData, + receipt.contactId, + message.writeToBuffer(), + pushData, ); - var retry = true; - if (resp.isError) { - Log.error('Could not retransmit message.'); + Log.error('Could not transmit message $receiptId got ${resp.error}.'); if (resp.error == ErrorCode.UserIdNotFound) { - retry = false; - if (retrans.messageId != null) { - await twonlyDB.messagesDao.updateMessageByMessageId( - retrans.messageId!, - const MessagesCompanion(errorWhileSending: Value(true)), - ); - } + await twonlyDB.receiptsDao.deleteReceipt(receiptId); await twonlyDB.contactsDao.updateContact( - retrans.contactId, + receipt.contactId, const ContactsCompanion(deleted: Value(true)), ); + return; } } if (resp.isSuccess) { - retry = false; - if (retrans.messageId != null) { - await twonlyDB.messagesDao.updateMessageByMessageId( - retrans.messageId!, + if (receipt.messageId != null) { + await twonlyDB.messagesDao.updateMessageId( + receipt.messageId!, const MessagesCompanion( - acknowledgeByServer: Value(true), - errorWhileSending: Value(false), + ackByServer: Value(true), ), ); } - } - - if (!retry) { - if (!messageGetsAck(json.kind)) { - await twonlyDB.messageRetransmissionDao - .deleteRetransmissionById(retransId); + if (!receipt.contactWillSendsReceipt) { + await twonlyDB.receiptsDao.deleteReceipt(receiptId); } else { - await twonlyDB.messageRetransmissionDao.updateRetransmission( - retransId, - MessageRetransmissionsCompanion( - acknowledgeByServerAt: Value(DateTime.now()), - retryCount: Value(retrans.retryCount + 1), + await twonlyDB.receiptsDao.updateReceipt( + receiptId, + ReceiptsCompanion( + ackByServerAt: Value(DateTime.now()), + retryCount: Value(receipt.retryCount + 1), lastRetry: Value(DateTime.now()), ), ); } } } catch (e) { - Log.error('error resending message: $e'); - await twonlyDB.messageRetransmissionDao.deleteRetransmissionById(retransId); + Log.error('Unknown Error when sending message: $e'); + if (receiptId != null) { + await twonlyDB.receiptsDao.deleteReceipt(receiptId); + } + if (receipt != null) { + await twonlyDB.receiptsDao.deleteReceipt(receipt.receiptId); + } } } @@ -177,78 +167,31 @@ Future sendCipherText( ); if (receipt != null) { - await tryToSendCompleteMessage(receipt.receiptId); + await tryToSendCompleteMessage(receipt: receipt); } } -// Future sendTextMessage( -// int target, -// TextMessageContent content, -// PushNotification? pushNotification, -// ) async { -// final messageSendAt = DateTime.now(); -// DateTime? openedAt; - -// if (pushNotification != null && pushNotification.hasReactionContent()) { -// openedAt = DateTime.now(); -// } - -// final messageId = await twonlyDB.messagesDao.insertMessage( -// MessagesCompanion( -// contactId: Value(target), -// kind: const Value(MessageKind.textMessage), -// sendAt: Value(messageSendAt), -// responseToOtherMessageId: Value(content.responseToMessageId), -// responseToMessageId: Value(content.responseToOtherMessageId), -// downloadState: const Value(DownloadState.downloaded), -// openedAt: Value(openedAt), -// contentJson: Value( -// jsonEncode(content.toJson()), -// ), -// ), -// ); - -// if (messageId == null) return; - -// if (pushNotification != null && !pushNotification.hasReactionContent()) { -// pushNotification.messageId = Int64(messageId); -// } - -// final msg = MessageJson( -// kind: MessageKind.textMessage, -// messageSenderId: messageId, -// content: content, -// timestamp: messageSendAt, -// ); - -// await encryptAndSendMessageAsync( -// messageId, -// target, -// msg, -// pushNotification: pushNotification, -// ); -// } - Future notifyContactAboutOpeningMessage( - int fromUserId, - List messageOtherIds, + int contactId, + List messageOtherIds, ) async { var biggestMessageId = messageOtherIds.first; for (final messageOtherId in messageOtherIds) { - if (messageOtherId > biggestMessageId) biggestMessageId = messageOtherId; - await encryptAndSendMessageAsync( - null, - fromUserId, - MessageJson( - kind: MessageKind.opened, - messageReceiverId: messageOtherId, - content: MessageContent(), - timestamp: DateTime.now(), - ), - ); + if (isUUIDNewer(messageOtherId, biggestMessageId)) { + biggestMessageId = messageOtherId; + } } - await updateLastMessageId(fromUserId, biggestMessageId); + await sendCipherText( + contactId, + pb.EncryptedContent( + messageUpdate: pb.EncryptedContent_MessageUpdate( + type: pb.EncryptedContent_MessageUpdate_Type.OPENED, + multipleSenderMessageIds: messageOtherIds, + ), + ), + ); + await updateLastMessageId(contactId, biggestMessageId); } Future notifyContactsAboutProfileChange({int? onlyToContact}) async { @@ -256,11 +199,13 @@ Future notifyContactsAboutProfileChange({int? onlyToContact}) async { if (user == null) return; if (user.avatarSvg == null) return; - final encryptedContent = pb.EncryptedContent() - ..contactUpdate = (pb.EncryptedContent_ContactUpdate() - ..type = pb.EncryptedContent_ContactUpdate_Type.UPDATE - ..avatarSvg = user.avatarSvg! - ..displayName = user.displayName); + final encryptedContent = pb.EncryptedContent( + contactUpdate: pb.EncryptedContent_ContactUpdate( + type: pb.EncryptedContent_ContactUpdate_Type.UPDATE, + avatarSvg: user.avatarSvg, + displayName: user.displayName, + ), + ); if (onlyToContact != null) { await sendCipherText(onlyToContact, encryptedContent); diff --git a/lib/src/services/api/server_messages.dart b/lib/src/services/api/server_messages.dart index 953924c..58b75ca 100644 --- a/lib/src/services/api/server_messages.dart +++ b/lib/src/services/api/server_messages.dart @@ -65,7 +65,7 @@ Future handleNewMessage(int fromUserId, Uint8List body) async { Log.info( 'Got decryption error: ${message.plaintextContent.decryptionErrorMessage.type} for $receiptId', ); - await tryToSendCompleteMessage(receiptId); + await tryToSendCompleteMessage(receiptId: receiptId, reupload: true); } case Message_Type.CIPHERTEXT: @@ -97,8 +97,10 @@ Future handleNewMessage(int fromUserId, Uint8List body) async { contactWillSendsReceipt: const Value(false), ), ); - await tryToSendCompleteMessage(receiptId); + await tryToSendCompleteMessage(receiptId: receiptId); } + case Message_Type.TEST_NOTIFICATION: + return; } } diff --git a/lib/src/services/api/server_messages/contact.server_messages.dart b/lib/src/services/api/server_messages/contact.server_messages.dart index aff4c79..d305800 100644 --- a/lib/src/services/api/server_messages/contact.server_messages.dart +++ b/lib/src/services/api/server_messages/contact.server_messages.dart @@ -9,6 +9,7 @@ import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/services/api/utils.dart'; import 'package:twonly/src/services/notifications/pushkeys.notifications.dart'; import 'package:twonly/src/services/notifications/setup.notifications.dart'; +import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; Future handleContactRequest( @@ -17,6 +18,7 @@ Future handleContactRequest( ) async { switch (contactRequest.type) { case EncryptedContent_ContactRequest_Type.REQUEST: + Log.info('Got a contact request from $fromUserId'); // Request the username by the server so an attacker can not // forge the displayed username in the contact request final username = await apiService.getUsername(fromUserId); @@ -33,6 +35,7 @@ Future handleContactRequest( } await setupNotificationWithUsers(); case EncryptedContent_ContactRequest_Type.ACCEPT: + Log.info('Got a contact accept from $fromUserId'); await twonlyDB.contactsDao.updateContact( fromUserId, const ContactsCompanion( @@ -41,19 +44,23 @@ Future handleContactRequest( ), ); case EncryptedContent_ContactRequest_Type.REJECT: + Log.info('Got a contact reject from $fromUserId'); await twonlyDB.contactsDao.deleteContactByUserId(fromUserId); } } Future handleContactUpdate( - int fromUserId, - EncryptedContent_ContactUpdate contactUpdate, - int? senderProfileCounter) async { + int fromUserId, + EncryptedContent_ContactUpdate contactUpdate, + int? senderProfileCounter, +) async { switch (contactUpdate.type) { case EncryptedContent_ContactUpdate_Type.REQUEST: + Log.info('Got a contact update request from $fromUserId'); await notifyContactsAboutProfileChange(onlyToContact: fromUserId); case EncryptedContent_ContactUpdate_Type.UPDATE: + Log.info('Got a contact update $fromUserId'); if (contactUpdate.hasAvatarSvg() && contactUpdate.hasDisplayName() && senderProfileCounter != null) { @@ -74,6 +81,7 @@ Future handleFlameSync( int contactId, EncryptedContent_FlameSync flameSync, ) async { + Log.info('Got a flameSync from $contactId'); final contact = await twonlyDB.contactsDao .getContactByUserId(contactId) .getSingleOrNull(); diff --git a/lib/src/services/api/server_messages/media.server_messages.dart b/lib/src/services/api/server_messages/media.server_messages.dart index 7b2583b..741c774 100644 --- a/lib/src/services/api/server_messages/media.server_messages.dart +++ b/lib/src/services/api/server_messages/media.server_messages.dart @@ -1,92 +1,158 @@ +import 'dart:async'; +import 'package:drift/drift.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/database/tables/mediafiles.table.dart'; +import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart'; +import 'package:twonly/src/services/api/media_download.dart'; +import 'package:twonly/src/services/api/utils.dart'; +import 'package:twonly/src/services/mediafile.service.dart'; +import 'package:twonly/src/services/thumbnail.service.dart'; +import 'package:twonly/src/utils/log.dart'; -Future handleMedia(int fromUserId, String groupId, EncryptedContent_Media media) async { -TODO -} +Future handleMedia( + int fromUserId, + String groupId, + EncryptedContent_Media media, +) async { + Log.info( + 'Got a media message: ${media.senderMessageId} from $groupId with type ${media.type}', + ); -Future handleMediaUpdate(int fromUserId, String groupId, EncryptedContent_MediaUpdate mediaUpdate) async { -TODO + late MediaType mediaType; + switch (media.type) { + case EncryptedContent_Media_Type.REUPLOAD: + final message = await twonlyDB.messagesDao + .getMessageById(media.senderMessageId) + .getSingleOrNull(); + if (message == null || + message.senderId != fromUserId || + message.mediaId == null) { + return; + } + // in case there was already a downloaded file delete it... + await removeMediaFile(message.mediaId!); - // switch (message.kind) { - // case MessageKind.receiveMediaError: - // if (message.messageReceiverId != null) { - // final openedMessage = await twonlyDB.messagesDao - // .getMessageByIdAndContactId(fromUserId, message.messageReceiverId!) - // .getSingleOrNull(); - - // if (openedMessage != null) { - // /// message found - - // /// checks if - // /// 1. this was a media upload - // /// 2. the media was not already retransmitted - // /// 3. the media was send in the last two days - // if (openedMessage.mediaUploadId != null && - // openedMessage.mediaRetransmissionState == - // MediaRetransmitting.none && - // openedMessage.sendAt - // .isAfter(DateTime.now().subtract(const Duration(days: 2)))) { - // // reset the media upload state to pending, - // // this will cause the media to be re-encrypted again - // await twonlyDB.mediaUploadsDao.updateMediaUpload( - // openedMessage.mediaUploadId!, - // const MediaUploadsCompanion( - // state: Value( - // UploadState.pending, - // ), - // ), - // ); - // // reset the message upload so the upload will be done again - // await twonlyDB.messagesDao.updateMessageByOtherUser( - // fromUserId, - // message.messageReceiverId!, - // const MessagesCompanion( - // downloadState: Value(DownloadState.pending), - // mediaRetransmissionState: - // Value(MediaRetransmitting.retransmitted), - // ), - // ); - // unawaited(retryMediaUpload(false)); - // } else { - // await twonlyDB.messagesDao.updateMessageByOtherUser( - // fromUserId, - // message.messageReceiverId!, - // const MessagesCompanion( - // errorWhileSending: Value(true), - // ), - // ); - // } - // } - // } - - - if (message.kind == MessageKind.storedMediaFile) { - if (message.messageReceiverId != null) { - /// stored media file just updates the message - await twonlyDB.messagesDao.updateMessageByOtherUser( - fromUserId, - message.messageReceiverId!, - const MessagesCompanion( - mediaStored: Value(true), - errorWhileSending: Value(false), + await twonlyDB.mediaFilesDao.updateMedia( + message.mediaId!, + MediaFilesCompanion( + downloadState: const Value(DownloadState.pending), + downloadToken: Value(Uint8List.fromList(media.downloadToken)), + encryptionKey: Value(Uint8List.fromList(media.encryptionKey)), + encryptionMac: Value(Uint8List.fromList(media.encryptionMac)), + encryptionNonce: Value(Uint8List.fromList(media.encryptionNonce)), ), ); - final msg = await twonlyDB.messagesDao - .getMessageByIdAndContactId( - fromUserId, - message.messageReceiverId!, - ) - .getSingleOrNull(); - if (msg != null && msg.mediaUploadId != null) { - final filePath = await getMediaFilePath(msg.mediaUploadId, 'send'); - if (filePath.contains('mp4')) { - unawaited(createThumbnailsForVideo(File(filePath))); - } else { - unawaited(createThumbnailsForImage(File(filePath))); - } + + final mediaFile = + await twonlyDB.mediaFilesDao.getMediaFileById(message.mediaId!); + + if (mediaFile != null) { + unawaited(startDownloadMedia(mediaFile, false)); } - } - } else if (message.content != null) {} + + return; + case EncryptedContent_Media_Type.IMAGE: + mediaType = MediaType.image; + case EncryptedContent_Media_Type.VIDEO: + mediaType = MediaType.video; + case EncryptedContent_Media_Type.GIF: + mediaType = MediaType.gif; + } + + final mediaFile = await twonlyDB.mediaFilesDao.insertMedia( + MediaFilesCompanion( + downloadState: const Value(DownloadState.pending), + type: Value(mediaType), + requiresAuthentication: Value(media.requiresAuthentication), + displayLimitInMilliseconds: Value( + media.hasDisplayLimitInMilliseconds() + ? media.displayLimitInMilliseconds.toInt() + : null, + ), + downloadToken: Value(Uint8List.fromList(media.downloadToken)), + encryptionKey: Value(Uint8List.fromList(media.encryptionKey)), + encryptionMac: Value(Uint8List.fromList(media.encryptionMac)), + encryptionNonce: Value(Uint8List.fromList(media.encryptionNonce)), + createdAt: Value(fromTimestamp(media.timestamp)), + ), + ); + + if (mediaFile == null) { + return; + } + + final message = await twonlyDB.messagesDao.insertMessage( + MessagesCompanion( + messageId: Value(media.senderMessageId), + senderId: Value(fromUserId), + groupId: Value(groupId), + mediaId: Value(mediaFile.mediaId), + ackByServer: const Value(true), + ackByUser: const Value(true), + quotesMessageId: Value( + media.hasQuoteMessageId() ? media.quoteMessageId : null, + ), + createdAt: Value(fromTimestamp(media.timestamp)), + ), + ); + if (message != null) { + Log.info('Inserted a new media message with ID: ${message.messageId}'); + await twonlyDB.contactsDao.incFlameCounter( + fromUserId, + true, + fromTimestamp(media.timestamp), + ); + + unawaited(startDownloadMedia(mediaFile, false)); + } +} + +Future handleMediaUpdate( + int fromUserId, + String groupId, + EncryptedContent_MediaUpdate mediaUpdate, +) async { + final message = await twonlyDB.messagesDao + .getMessageById(mediaUpdate.targetMessageId) + .getSingleOrNull(); + if (message == null || message.mediaId == null) return; + final mediaFile = + await twonlyDB.mediaFilesDao.getMediaFileById(message.mediaId!); + if (mediaFile == null) return; + + switch (mediaUpdate.type) { + case EncryptedContent_MediaUpdate_Type.REOPENED: + Log.info('Got media file reopened ${mediaFile.mediaId}'); + await twonlyDB.mediaFilesDao.updateMedia( + mediaFile.mediaId, + const MediaFilesCompanion( + reopenByContact: Value(true), + ), + ); + case EncryptedContent_MediaUpdate_Type.STORED: + Log.info('Got media file stored ${mediaFile.mediaId}'); + await twonlyDB.mediaFilesDao.updateMedia( + mediaFile.mediaId, + const MediaFilesCompanion( + storedByContact: Value(true), + ), + ); + + unawaited(createThumbnailForMediaFile(mediaFile)); + + case EncryptedContent_MediaUpdate_Type.DECRYPTION_ERROR: + Log.info('Got media file decryption error ${mediaFile.mediaId}'); + final reuploadRequestedBy = mediaFile.reuploadRequestedBy ?? []; + reuploadRequestedBy.add(fromUserId); + await twonlyDB.mediaFilesDao.updateMedia( + mediaFile.mediaId, + MediaFilesCompanion( + uploadState: const Value(UploadState.pending), + reuploadRequestedBy: Value(reuploadRequestedBy), + ), + ); + } } diff --git a/lib/src/services/api/server_messages/messages.server_messages.dart b/lib/src/services/api/server_messages/messages.server_messages.dart index 6a65873..297aa0e 100644 --- a/lib/src/services/api/server_messages/messages.server_messages.dart +++ b/lib/src/services/api/server_messages/messages.server_messages.dart @@ -10,12 +10,15 @@ Future handleMessageUpdate( ) async { switch (messageUpdate.type) { case EncryptedContent_MessageUpdate_Type.OPENED: - Log.info('Opened message ${messageUpdate.senderMessageId}'); - await twonlyDB.messagesDao.handleMessageOpened( - groupId, - messageUpdate.senderMessageId, - fromTimestamp(messageUpdate.timestamp), - ); + Log.info( + 'Opened message ${messageUpdate.multipleSenderMessageIds.length}'); + for (final senderMessageId in messageUpdate.multipleSenderMessageIds) { + await twonlyDB.messagesDao.handleMessageOpened( + groupId, + senderMessageId, + fromTimestamp(messageUpdate.timestamp), + ); + } case EncryptedContent_MessageUpdate_Type.DELETE: Log.info('Delete message ${messageUpdate.senderMessageId}'); await twonlyDB.messagesDao.handleMessageDeletion( diff --git a/lib/src/services/api/server_messages/pushkeys.server_messages.dart b/lib/src/services/api/server_messages/pushkeys.server_messages.dart index 4e755ff..6e3cb4d 100644 --- a/lib/src/services/api/server_messages/pushkeys.server_messages.dart +++ b/lib/src/services/api/server_messages/pushkeys.server_messages.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart'; import 'package:twonly/src/services/notifications/pushkeys.notifications.dart'; +import 'package:twonly/src/utils/log.dart'; DateTime lastPushKeyRequest = DateTime.now().subtract(const Duration(hours: 1)); @@ -11,6 +12,7 @@ Future handlePushKey( ) async { switch (pushKeys.type) { case EncryptedContent_PushKeys_Type.REQUEST: + Log.info('Got a pushkey request from $contactId'); if (lastPushKeyRequest .isBefore(DateTime.now().subtract(const Duration(seconds: 60)))) { lastPushKeyRequest = DateTime.now(); @@ -18,6 +20,7 @@ Future handlePushKey( } case EncryptedContent_PushKeys_Type.UPDATE: + Log.info('Got a pushkey update from $contactId'); await handleNewPushKey(contactId, pushKeys.keyId.toInt(), pushKeys.key); } } diff --git a/lib/src/services/api/server_messages/reaction.server_message.dart b/lib/src/services/api/server_messages/reaction.server_message.dart index 733457c..892a27d 100644 --- a/lib/src/services/api/server_messages/reaction.server_message.dart +++ b/lib/src/services/api/server_messages/reaction.server_message.dart @@ -1,11 +1,13 @@ import 'package:twonly/globals.dart'; import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart'; +import 'package:twonly/src/utils/log.dart'; Future handleReaction( int fromUserId, String groupId, EncryptedContent_Reaction reaction, ) async { + Log.info('Got a reaction from $fromUserId'); if (reaction.hasRemove()) { if (reaction.remove) { await twonlyDB.reactionsDao diff --git a/lib/src/services/api/server_messages/text_message.server_messages.dart b/lib/src/services/api/server_messages/text_message.server_messages.dart index df9140c..c5cef42 100644 --- a/lib/src/services/api/server_messages/text_message.server_messages.dart +++ b/lib/src/services/api/server_messages/text_message.server_messages.dart @@ -1,125 +1,34 @@ +import 'package:drift/drift.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart'; +import 'package:twonly/src/services/api/utils.dart'; +import 'package:twonly/src/utils/log.dart'; Future handleTextMessage( int fromUserId, String groupId, EncryptedContent_TextMessage textMessage, ) async { - TODO - // final content = message.content!; - // // when a message is received doubled ignore it... + Log.info( + 'Got a text message: ${textMessage.senderMessageId} from $groupId', + ); - // final openedMessage = await twonlyDB.messagesDao - // .getMessageByOtherMessageId(fromUserId, message.messageSenderId!) - // .getSingleOrNull(); - - // if (openedMessage != null) { - // if (openedMessage.errorWhileSending) { - // await twonlyDB.messagesDao - // .deleteMessagesByMessageId(openedMessage.messageId); - // } else { - // Log.error( - // 'Got a duplicated message from other user: ${message.messageSenderId!}', - // ); - // final ok = client.Response_Ok()..none = true; - // return client.Response()..ok = ok; - // } - // } - - // int? responseToMessageId; - // int? responseToOtherMessageId; - // int? messageId; - - // var acknowledgeByUser = false; - // DateTime? openedAt; - - // if (message.kind == MessageKind.reopenedMedia) { - // acknowledgeByUser = true; - // openedAt = DateTime.now(); - // } - - // if (content is TextMessageContent) { - // responseToMessageId = content.responseToMessageId; - // responseToOtherMessageId = content.responseToOtherMessageId; - - // if (responseToMessageId != null || responseToOtherMessageId != null) { - // // reactions are shown in the notification directly... - // if (isEmoji(content.text)) { - // openedAt = DateTime.now(); - // } - // } - // } - // if (content is ReopenedMediaFileContent) { - // responseToMessageId = content.messageId; - // } - - // if (responseToMessageId != null) { - // await twonlyDB.messagesDao.updateMessageByOtherUser( - // fromUserId, - // responseToMessageId, - // MessagesCompanion( - // errorWhileSending: const Value(false), - // openedAt: Value( - // DateTime.now(), - // ), // when a user reacted to the media file, it should be marked as opened - // ), - // ); - // } - - // final contentJson = jsonEncode(content.toJson()); - // final update = MessagesCompanion( - // contactId: Value(fromUserId), - // kind: Value(message.kind), - // messageOtherId: Value(message.messageSenderId), - // contentJson: Value(contentJson), - // acknowledgeByServer: const Value(true), - // acknowledgeByUser: Value(acknowledgeByUser), - // responseToMessageId: Value(responseToMessageId), - // responseToOtherMessageId: Value(responseToOtherMessageId), - // openedAt: Value(openedAt), - // downloadState: Value( - // message.kind == MessageKind.media - // ? DownloadState.pending - // : DownloadState.downloaded, - // ), - // sendAt: Value(message.timestamp), - // ); - - // messageId = await twonlyDB.messagesDao.insertMessage( - // update, - // ); - - // if (messageId == null) { - // Log.error('could not insert message into db'); - // return client.Response()..error = ErrorCode.InternalError; - // } - - // Log.info('Inserted a new message with id: $messageId'); - - // if (message.kind == MessageKind.media) { - // await twonlyDB.contactsDao.incFlameCounter( - // fromUserId, - // true, - // message.timestamp, - // ); - - // final msg = await twonlyDB.messagesDao - // .getMessageByMessageId(messageId) - // .getSingleOrNull(); - // if (msg != null) { - // unawaited(startDownloadMedia(msg, false)); - // } - // } - // } else { - // Log.error('Content is not defined $message'); - // } - - // // unarchive contact when receiving a new message - // await twonlyDB.contactsDao.updateContact( - // fromUserId, - // const ContactsCompanion( - // archived: Value(false), - // ), - // ); - // return null; + final message = await twonlyDB.messagesDao.insertMessage( + MessagesCompanion( + messageId: Value(textMessage.senderMessageId), + senderId: Value(fromUserId), + groupId: Value(groupId), + content: Value(textMessage.text), + ackByServer: const Value(true), + ackByUser: const Value(true), + quotesMessageId: Value( + textMessage.hasQuoteMessageId() ? textMessage.quoteMessageId : null, + ), + createdAt: Value(fromTimestamp(textMessage.timestamp)), + ), + ); + if (message != null) { + Log.info('Inserted a new text message with ID: ${message.messageId}'); + } } diff --git a/lib/src/services/notifications/background.notifications.dart b/lib/src/services/notifications/background.notifications.dart index 294fd03..fde1e92 100644 --- a/lib/src/services/notifications/background.notifications.dart +++ b/lib/src/services/notifications/background.notifications.dart @@ -7,7 +7,7 @@ import 'package:cryptography_plus/cryptography_plus.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:path_provider/path_provider.dart'; import 'package:twonly/src/constants/secure_storage_keys.dart'; -import 'package:twonly/src/model/protobuf/push_notification/push_notification.pb.dart'; +import 'package:twonly/src/model/protobuf/client/generated/push_notification.pbenum.dart'; import 'package:twonly/src/services/notifications/pushkeys.notifications.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/views/camera/share_image_editor_view.dart' diff --git a/lib/src/services/notifications/pushkeys.notifications.dart b/lib/src/services/notifications/pushkeys.notifications.dart index 562da78..1abf6fc 100644 --- a/lib/src/services/notifications/pushkeys.notifications.dart +++ b/lib/src/services/notifications/pushkeys.notifications.dart @@ -7,15 +7,17 @@ import 'package:cryptography_plus/cryptography_plus.dart'; import 'package:fixnum/fixnum.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:hashlib/random.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/constants/secure_storage_keys.dart'; import 'package:twonly/src/database/daos/contacts.dao.dart'; -import 'package:twonly/src/database/tables/messages_table.dart'; +import 'package:twonly/src/database/tables/mediafiles.table.dart'; import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/model/json/message_old.dart' as my; -import 'package:twonly/src/model/protobuf/push_notification/push_notification.pb.dart'; +import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart'; +import 'package:twonly/src/model/protobuf/client/generated/push_notification.pb.dart'; import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/utils/log.dart'; +import 'package:twonly/src/utils/misc.dart'; /// This function must be called after the database is setup Future setupNotificationWithUsers({ @@ -104,19 +106,14 @@ Future setupNotificationWithUsers({ } Future sendNewPushKey(int userId, PushKey pushKey) async { - await encryptAndSendMessageAsync( - null, + await sendCipherText( userId, - my.MessageJson( - kind: MessageKind.pushKey, - content: my.PushKeyContent( - keyId: pushKey.id.toInt(), - key: pushKey.key, - ), - timestamp: DateTime.fromMillisecondsSinceEpoch( - pushKey.createdAtUnixTimestamp.toInt(), - ), - ), + EncryptedContent() + ..pushKeys = (EncryptedContent_PushKeys() + ..type = EncryptedContent_PushKeys_Type.UPDATE + ..key = pushKey.key + ..keyId = pushKey.id + ..createdAt = pushKey.createdAtUnixTimestamp), ); } @@ -132,7 +129,7 @@ Future updatePushUser(Contact contact) async { displayName: getContactDisplayName(contact), pushKeys: [], blocked: contact.blocked, - lastMessageId: Int64(), + lastMessageId: uuid.v7(), ), ); } else { @@ -160,7 +157,7 @@ Future handleNewPushKey(int fromUserId, int keyId, List key) async { displayName: getContactDisplayName(contact), pushKeys: [], blocked: contact.blocked, - lastMessageId: Int64(), + lastMessageId: uuid.v7(), ), ); pushUser = pushKeys.firstWhereOrNull((x) => x.userId == fromUserId); @@ -174,8 +171,8 @@ Future handleNewPushKey(int fromUserId, int keyId, List key) async { pushUser!.pushKeys.clear(); pushUser.pushKeys.add( PushKey( - id: Int64(pushKey.keyId), - key: pushKey.key, + id: Int64(keyId), + key: key, createdAtUnixTimestamp: Int64(DateTime.now().millisecondsSinceEpoch), ), ); @@ -183,7 +180,7 @@ Future handleNewPushKey(int fromUserId, int keyId, List key) async { await setPushKeys(SecureStorageKeys.sendingPushKeys, pushKeys); } -Future updateLastMessageId(int fromUserId, int messageId) async { +Future updateLastMessageId(int fromUserId, String messageId) async { final pushUsers = await getPushKeys(SecureStorageKeys.receivingPushKeys); final pushUser = pushUsers.firstWhereOrNull((x) => x.userId == fromUserId); @@ -192,15 +189,103 @@ Future updateLastMessageId(int fromUserId, int messageId) async { return; } - if (pushUser.lastMessageId < Int64(messageId)) { - pushUser.lastMessageId = Int64(messageId); + if (isUUIDNewer(messageId, pushUser.lastMessageId)) { + pushUser.lastMessageId = messageId; await setPushKeys(SecureStorageKeys.receivingPushKeys, pushUsers); } } +Future getPushDataFromEncryptedContent( + int toUserId, + String? messageId, + EncryptedContent content, +) async { + late PushKind kind; + String? reactionContent; + + if (content.hasReaction()) { + if (content.reaction.remove) return null; + + final msg = await twonlyDB.messagesDao + .getMessageById(content.reaction.targetMessageId) + .getSingleOrNull(); + if (msg == null) return null; + if (msg.content != null) { + kind = PushKind.reactionToText; + } else if (msg.mediaId != null) { + final media = await twonlyDB.mediaFilesDao.getMediaFileById(msg.mediaId!); + if (media == null) return null; + switch (media.type) { + case MediaType.image: + kind = PushKind.reactionToImage; + case MediaType.video: + kind = PushKind.reactionToVideo; + case MediaType.gif: + kind = PushKind.reaction; + } + } + reactionContent = content.reaction.emoji; + } + + if (content.hasTextMessage()) { + kind = PushKind.text; + if (content.textMessage.hasQuoteMessageId()) { + kind = PushKind.response; + } + } + if (content.hasMedia()) { + switch (content.media.type) { + case EncryptedContent_Media_Type.IMAGE: + kind = PushKind.image; + case EncryptedContent_Media_Type.VIDEO: + kind = PushKind.video; + // ignore: no_default_cases + default: + return null; + } + if (content.media.requiresAuthentication) { + kind = PushKind.twonly; + } + } + + if (content.hasContactRequest()) { + switch (content.contactRequest.type) { + case EncryptedContent_ContactRequest_Type.REQUEST: + kind = PushKind.contactRequest; + case EncryptedContent_ContactRequest_Type.ACCEPT: + kind = PushKind.acceptRequest; + case EncryptedContent_ContactRequest_Type.REJECT: + return null; + } + } + + if (content.hasMediaUpdate()) { + switch (content.mediaUpdate.type) { + case EncryptedContent_MediaUpdate_Type.REOPENED: + kind = PushKind.reopenedMedia; + case EncryptedContent_MediaUpdate_Type.STORED: + kind = PushKind.storedMediaFile; + case EncryptedContent_MediaUpdate_Type.DECRYPTION_ERROR: + return null; + } + } + + final pushNotification = PushNotification()..kind = kind; + if (reactionContent != null) { + pushNotification.reactionContent = reactionContent; + } + if (messageId != null) { + pushNotification.messageId = messageId; + } + return encryptPushNotification(toUserId, pushNotification); +} + /// this will trigger a push notification /// push notification only containing the message kind and username -Future getPushData(int toUserId, PushNotification content) async { +Future encryptPushNotification( + int toUserId, + PushNotification content, +) async { final pushKeys = await getPushKeys(SecureStorageKeys.sendingPushKeys); var key = 'InsecureOnlyUsedForAddingContact'.codeUnits; @@ -218,14 +303,12 @@ Future getPushData(int toUserId, PushNotification content) async { // this will be enforced after every app uses this system... :/ // return null; Log.error('Using insecure key as the receiver does not send a push key!'); - await encryptAndSendMessageAsync( - null, + + await sendCipherText( toUserId, - my.MessageJson( - kind: MessageKind.requestPushKey, - content: my.MessageContent(), - timestamp: DateTime.now(), - ), + EncryptedContent() + ..pushKeys = (EncryptedContent_PushKeys() + ..type = EncryptedContent_PushKeys_Type.REQUEST), ); } } else { diff --git a/lib/src/services/signal/encryption.signal.dart b/lib/src/services/signal/encryption.signal.dart index 1338663..50aad34 100644 --- a/lib/src/services/signal/encryption.signal.dart +++ b/lib/src/services/signal/encryption.signal.dart @@ -7,16 +7,15 @@ import 'package:twonly/src/services/signal/consts.signal.dart'; import 'package:twonly/src/services/signal/prekeys.signal.dart'; import 'package:twonly/src/services/signal/utils.signal.dart'; import 'package:twonly/src/utils/log.dart'; -import 'package:twonly/src/utils/misc.dart'; /// This caused some troubles, so protection the encryption... final lockingSignalEncryption = Mutex(); -Future signalEncryptMessage( +Future signalEncryptMessage( int target, Uint8List plaintextContent, ) async { - return lockingSignalEncryption.protect(() async { + return lockingSignalEncryption.protect(() async { try { final signalStore = (await getSignalStore())!; final address = SignalProtocolAddress(target.toString(), defaultDeviceId); @@ -75,14 +74,7 @@ Future signalEncryptMessage( Log.error('did not get the identity of the remote address'); } } - - final ciphertext = await session.encrypt(plaintextContent); - - final b = BytesBuilder() - ..add(ciphertext.serialize()) - ..add(intToBytes(ciphertext.getType())); - - return b.takeBytes(); + return await session.encrypt(plaintextContent); } catch (e) { Log.error(e.toString()); return null; diff --git a/lib/src/services/thumbnail.service.dart b/lib/src/services/thumbnail.service.dart index e1311e7..a40d07c 100644 --- a/lib/src/services/thumbnail.service.dart +++ b/lib/src/services/thumbnail.service.dart @@ -2,9 +2,23 @@ import 'dart:io'; import 'package:flutter_image_compress/flutter_image_compress.dart'; import 'package:path/path.dart'; +import 'package:twonly/src/database/tables/mediafiles.table.dart'; +import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:video_thumbnail/video_thumbnail.dart'; + +Future createThumbnailForMediaFile(MediaFile media) async { + + switch (media.type) { + case MediaType.image: + TODO + break; + default: + } + +} + Future createThumbnailsForImage(File file) async { final fileExtension = file.path.split('.').last.toLowerCase(); if (fileExtension != 'png') { diff --git a/lib/src/utils/misc.dart b/lib/src/utils/misc.dart index 63d2475..1f1973d 100644 --- a/lib/src/utils/misc.dart +++ b/lib/src/utils/misc.dart @@ -267,3 +267,9 @@ MediaMessageContent? getMediaContent(Message message) { return null; } } + +bool isUUIDNewer(String uuid1, String uuid2) { + final timestamp1 = int.parse(uuid1.substring(0, 8), radix: 16); + final timestamp2 = int.parse(uuid2.substring(0, 8), radix: 16); + return timestamp1 > timestamp2; +} diff --git a/lib/src/views/settings/notification.view.dart b/lib/src/views/settings/notification.view.dart index db9be48..49b4e72 100644 --- a/lib/src/views/settings/notification.view.dart +++ b/lib/src/views/settings/notification.view.dart @@ -1,13 +1,12 @@ import 'dart:io'; - -import 'package:fixnum/fixnum.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:hashlib/random.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/constants/secure_storage_keys.dart'; -import 'package:twonly/src/model/protobuf/push_notification/push_notification.pbserver.dart'; +import 'package:twonly/src/model/protobuf/client/generated/push_notification.pb.dart'; import 'package:twonly/src/services/fcm.service.dart'; import 'package:twonly/src/services/notifications/pushkeys.notifications.dart'; import 'package:twonly/src/utils/misc.dart'; @@ -52,10 +51,10 @@ class NotificationView extends StatelessWidget { if (run) { final user = await getUser(); if (user != null) { - final pushData = await getPushData( + final pushData = await encryptPushNotification( user.userId, PushNotification( - messageId: Int64(), + messageId: uuid.v4(), kind: PushKind.testNotification, ), ); diff --git a/test/unit_test.dart b/test/unit_test.dart index 36e6252..8d4c715 100644 --- a/test/unit_test.dart +++ b/test/unit_test.dart @@ -1,9 +1,11 @@ import 'dart:convert'; +import 'dart:io'; import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:hashlib/random.dart'; import 'package:twonly/src/services/api/media_upload.dart'; +import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/pow.dart'; import 'package:twonly/src/views/components/animate_icon.dart'; @@ -40,5 +42,11 @@ void main() { final uv4String = utf8.decode(uv4Bytes.cast()); expect(uv4String, uv4); }); + test('comparing uui7', () async { + final uv7Old = uuid.v7(); + sleep(const Duration(milliseconds: 1000)); + final uv7New = uuid.v7(); + expect(isUUIDNewer(uv7New, uv7Old), true); + }); }); }