diff --git a/lib/src/database/daos/contacts.dao.dart b/lib/src/database/daos/contacts.dao.dart index 54e70ab..58e6b69 100644 --- a/lib/src/database/daos/contacts.dao.dart +++ b/lib/src/database/daos/contacts.dao.dart @@ -97,6 +97,10 @@ class ContactsDao extends DatabaseAccessor with _$ContactsDaoMixin { return select(contacts)..where((t) => t.userId.equals(userId)); } + Future> getContactsByUsername(String username) async { + return (select(contacts)..where((t) => t.username.equals(username))).get(); + } + Future deleteContactByUserId(int userId) { return (delete(contacts)..where((t) => t.userId.equals(userId))).go(); } diff --git a/lib/src/database/daos/groups.dao.dart b/lib/src/database/daos/groups.dao.dart index 3747ab4..6456434 100644 --- a/lib/src/database/daos/groups.dao.dart +++ b/lib/src/database/daos/groups.dao.dart @@ -31,4 +31,17 @@ class GroupsDao extends DatabaseAccessor with _$GroupsDaoMixin { return (select(groupMembers)..where((t) => t.groupId.equals(groupId))) .get(); } + + Future> getDirectChat(int userId) async { + final query = (select(groups).join([ + leftOuterJoin( + groupMembers, + groupMembers.groupId.equalsExp(groups.groupId) & + groupMembers.contactId.equals(userId), + ), + ]) + ..where(groups.isGroupOfTwo.equals(true))); + + return query.map((row) => row.readTable(groups)).get(); + } } diff --git a/lib/src/database/daos/messages.dao.dart b/lib/src/database/daos/messages.dao.dart index 0483dd8..7a0726f 100644 --- a/lib/src/database/daos/messages.dao.dart +++ b/lib/src/database/daos/messages.dao.dart @@ -16,6 +16,7 @@ part 'messages.dao.g.dart'; Contacts, MediaFiles, MessageHistories, + MessageActions, Groups, ], ) @@ -192,11 +193,10 @@ class MessagesDao extends DatabaseAccessor with _$MessagesDaoMixin { (t) => t.messageId.equals(messageId) & t.senderId.equals(contactId), )) .write( - MessagesCompanion( - isDeletedFromSender: const Value(true), - content: const Value(null), - modifiedAt: Value(timestamp), - mediaId: const Value(null), + const MessagesCompanion( + isDeletedFromSender: Value(true), + content: Value(null), + mediaId: Value(null), ), ); } @@ -215,6 +215,7 @@ class MessagesDao extends DatabaseAccessor with _$MessagesDaoMixin { MessageHistoriesCompanion( messageId: Value(messageId), content: Value(msg.content), + createdAt: Value(timestamp), ), ); await (update(messages) @@ -224,29 +225,36 @@ class MessagesDao extends DatabaseAccessor with _$MessagesDaoMixin { .write( MessagesCompanion( content: Value(text), - modifiedAt: Value(timestamp), ), ); } Future handleMessageOpened( - String groupId, + int contactId, String messageId, DateTime timestamp, ) async { - final msg = await getMessageById(messageId).getSingleOrNull(); - if (msg == null) return; - await (update(messages) - ..where( - (t) => - t.groupId.equals(groupId) & - t.messageId.equals(messageId) & - t.senderId.isNull(), - )) - .write( - MessagesCompanion( - openedAt: Value(timestamp), - openedByCounter: Value(msg.openedByCounter + 1), + await into(messageActions).insert( + MessageActionsCompanion( + messageId: Value(messageId), + contactId: Value(contactId), + type: const Value(MessageActionType.ackByUserAt), + actionAt: Value(timestamp), + ), + ); + } + + Future handleMessageAckByServer( + int contactId, + String messageId, + DateTime timestamp, + ) async { + await into(messageActions).insert( + MessageActionsCompanion( + messageId: Value(messageId), + contactId: Value(contactId), + type: const Value(MessageActionType.ackByServerAt), + actionAt: Value(timestamp), ), ); } diff --git a/lib/src/database/daos/messages.dao.g.dart b/lib/src/database/daos/messages.dao.g.dart index e763f72..74bd53f 100644 --- a/lib/src/database/daos/messages.dao.g.dart +++ b/lib/src/database/daos/messages.dao.g.dart @@ -10,4 +10,5 @@ mixin _$MessagesDaoMixin on DatabaseAccessor { $MessagesTable get messages => attachedDatabase.messages; $MessageHistoriesTable get messageHistories => attachedDatabase.messageHistories; + $MessageActionsTable get messageActions => attachedDatabase.messageActions; } diff --git a/lib/src/database/daos/receipts.dao.dart b/lib/src/database/daos/receipts.dao.dart index df65eb5..01df2f9 100644 --- a/lib/src/database/daos/receipts.dao.dart +++ b/lib/src/database/daos/receipts.dao.dart @@ -6,7 +6,7 @@ import 'package:twonly/src/utils/log.dart'; part 'receipts.dao.g.dart'; -@DriftAccessor(tables: [Receipts, Messages]) +@DriftAccessor(tables: [Receipts, Messages, MessageActions]) class ReceiptsDao extends DatabaseAccessor with _$ReceiptsDaoMixin { // this constructor is required so that the main database can create an instance // of this object. @@ -24,11 +24,11 @@ class ReceiptsDao extends DatabaseAccessor with _$ReceiptsDaoMixin { if (receipt == null) return; if (receipt.messageId != null) { - await (update(messages) - ..where((t) => t.messageId.equals(receipt.messageId!))) - .write( - const MessagesCompanion( - ackByUser: Value(true), + await into(messageActions).insert( + MessageActionsCompanion( + messageId: Value(receipt.messageId!), + contactId: Value(fromUserId), + type: const Value(MessageActionType.ackByUserAt), ), ); } @@ -81,6 +81,10 @@ class ReceiptsDao extends DatabaseAccessor with _$ReceiptsDaoMixin { .get(); } + Stream> watchAll() { + return select(receipts).watch(); + } + Future updateReceipt( String receiptId, ReceiptsCompanion updates, diff --git a/lib/src/database/daos/receipts.dao.g.dart b/lib/src/database/daos/receipts.dao.g.dart index 5a06998..d495737 100644 --- a/lib/src/database/daos/receipts.dao.g.dart +++ b/lib/src/database/daos/receipts.dao.g.dart @@ -9,4 +9,5 @@ mixin _$ReceiptsDaoMixin on DatabaseAccessor { $MediaFilesTable get mediaFiles => attachedDatabase.mediaFiles; $MessagesTable get messages => attachedDatabase.messages; $ReceiptsTable get receipts => attachedDatabase.receipts; + $MessageActionsTable get messageActions => attachedDatabase.messageActions; } diff --git a/lib/src/database/tables/messages.table.dart b/lib/src/database/tables/messages.table.dart index 28438c8..faf0053 100644 --- a/lib/src/database/tables/messages.table.dart +++ b/lib/src/database/tables/messages.table.dart @@ -30,28 +30,50 @@ class Messages extends Table { BoolColumn get isEdited => 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()(); DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); - DateTimeColumn get modifiedAt => - dateTime().nullable().withDefault(currentDateAndTime)(); @override Set get primaryKey => {messageId}; } -@DataClassName('MessageHistory') -class MessageHistories extends Table { +enum MessageActionType { + openedAt, + modifiedAt, + ackByUserAt, + ackByServerAt, +} + +@DataClassName('MessageAction') +class MessageActions extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get messageId => text().references(Messages, #messageId, onDelete: KeyAction.cascade)(); + IntColumn get contactId => + integer().references(Contacts, #contactId, onDelete: KeyAction.cascade)(); + + TextColumn get type => textEnum()(); + DateTimeColumn get actionAt => dateTime().withDefault(currentDateAndTime)(); + + @override + Set get primaryKey => {id}; +} + +@DataClassName('MessageHistory') +class MessageHistories extends Table { + IntColumn get id => integer().autoIncrement()(); + + TextColumn get messageId => + text().references(Messages, #messageId, onDelete: KeyAction.cascade)(); + + IntColumn get contactId => + integer().references(Contacts, #contactId, onDelete: KeyAction.cascade)(); + TextColumn get content => text().nullable()(); DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); @override - Set get primaryKey => {messageId, createdAt}; + Set get primaryKey => {id}; } diff --git a/lib/src/database/twonly.db.dart b/lib/src/database/twonly.db.dart index 1594ce8..1e121c1 100644 --- a/lib/src/database/twonly.db.dart +++ b/lib/src/database/twonly.db.dart @@ -42,6 +42,7 @@ part 'twonly.db.g.dart'; SignalSessionStores, SignalContactPreKeys, SignalContactSignedPreKeys, + MessageActions ], daos: [ MessagesDao, diff --git a/lib/src/database/twonly.db.g.dart b/lib/src/database/twonly.db.g.dart index 118a6d5..69e7a22 100644 --- a/lib/src/database/twonly.db.g.dart +++ b/lib/src/database/twonly.db.g.dart @@ -2314,40 +2314,6 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> { defaultConstraints: GeneratedColumn.constraintIsAlways('CHECK ("is_edited" IN (0, 1))'), defaultValue: const Constant(false)); - static const VerificationMeta _ackByUserMeta = - const VerificationMeta('ackByUser'); - @override - late final GeneratedColumn ackByUser = GeneratedColumn( - 'ack_by_user', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("ack_by_user" IN (0, 1))'), - defaultValue: const Constant(false)); - static const VerificationMeta _ackByServerMeta = - const VerificationMeta('ackByServer'); - @override - late final GeneratedColumn ackByServer = GeneratedColumn( - 'ack_by_server', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("ack_by_server" IN (0, 1))'), - defaultValue: const Constant(false)); - static const VerificationMeta _openedByCounterMeta = - const VerificationMeta('openedByCounter'); - @override - late final GeneratedColumn openedByCounter = GeneratedColumn( - 'opened_by_counter', aliasedName, false, - type: DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const Constant(0)); - static const VerificationMeta _openedAtMeta = - const VerificationMeta('openedAt'); - @override - late final GeneratedColumn openedAt = GeneratedColumn( - 'opened_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); static const VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); @override @@ -2356,14 +2322,6 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> { type: DriftSqlType.dateTime, requiredDuringInsert: false, defaultValue: currentDateAndTime); - static const VerificationMeta _modifiedAtMeta = - const VerificationMeta('modifiedAt'); - @override - late final GeneratedColumn modifiedAt = GeneratedColumn( - 'modified_at', aliasedName, true, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: currentDateAndTime); @override List get $columns => [ groupId, @@ -2376,12 +2334,7 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> { quotesMessageId, isDeletedFromSender, isEdited, - ackByUser, - ackByServer, - openedByCounter, - openedAt, - createdAt, - modifiedAt + createdAt ]; @override String get aliasedName => _alias ?? actualTableName; @@ -2443,38 +2396,10 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> { context.handle(_isEditedMeta, isEdited.isAcceptableOrUnknown(data['is_edited']!, _isEditedMeta)); } - if (data.containsKey('ack_by_user')) { - context.handle( - _ackByUserMeta, - ackByUser.isAcceptableOrUnknown( - data['ack_by_user']!, _ackByUserMeta)); - } - if (data.containsKey('ack_by_server')) { - context.handle( - _ackByServerMeta, - ackByServer.isAcceptableOrUnknown( - data['ack_by_server']!, _ackByServerMeta)); - } - if (data.containsKey('opened_by_counter')) { - context.handle( - _openedByCounterMeta, - openedByCounter.isAcceptableOrUnknown( - data['opened_by_counter']!, _openedByCounterMeta)); - } - if (data.containsKey('opened_at')) { - context.handle(_openedAtMeta, - openedAt.isAcceptableOrUnknown(data['opened_at']!, _openedAtMeta)); - } if (data.containsKey('created_at')) { context.handle(_createdAtMeta, createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta)); } - if (data.containsKey('modified_at')) { - context.handle( - _modifiedAtMeta, - modifiedAt.isAcceptableOrUnknown( - data['modified_at']!, _modifiedAtMeta)); - } return context; } @@ -2504,18 +2429,8 @@ 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'])!, - 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 - .read(DriftSqlType.dateTime, data['${effectivePrefix}opened_at']), createdAt: attachedDatabase.typeMapping .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - modifiedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}modified_at']), ); } @@ -2536,12 +2451,7 @@ class Message extends DataClass implements Insertable { final String? quotesMessageId; final bool isDeletedFromSender; final bool isEdited; - final bool ackByUser; - final bool ackByServer; - final int openedByCounter; - final DateTime? openedAt; final DateTime createdAt; - final DateTime? modifiedAt; const Message( {required this.groupId, required this.messageId, @@ -2553,12 +2463,7 @@ class Message extends DataClass implements Insertable { this.quotesMessageId, required this.isDeletedFromSender, required this.isEdited, - required this.ackByUser, - required this.ackByServer, - required this.openedByCounter, - this.openedAt, - required this.createdAt, - this.modifiedAt}); + required this.createdAt}); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2582,16 +2487,7 @@ class Message extends DataClass implements Insertable { } map['is_deleted_from_sender'] = Variable(isDeletedFromSender); map['is_edited'] = Variable(isEdited); - 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); - } map['created_at'] = Variable(createdAt); - if (!nullToAbsent || modifiedAt != null) { - map['modified_at'] = Variable(modifiedAt); - } return map; } @@ -2617,16 +2513,7 @@ class Message extends DataClass implements Insertable { : Value(quotesMessageId), isDeletedFromSender: Value(isDeletedFromSender), isEdited: Value(isEdited), - ackByUser: Value(ackByUser), - ackByServer: Value(ackByServer), - openedByCounter: Value(openedByCounter), - openedAt: openedAt == null && nullToAbsent - ? const Value.absent() - : Value(openedAt), createdAt: Value(createdAt), - modifiedAt: modifiedAt == null && nullToAbsent - ? const Value.absent() - : Value(modifiedAt), ); } @@ -2645,12 +2532,7 @@ class Message extends DataClass implements Insertable { isDeletedFromSender: serializer.fromJson(json['isDeletedFromSender']), isEdited: serializer.fromJson(json['isEdited']), - 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']), - modifiedAt: serializer.fromJson(json['modifiedAt']), ); } @override @@ -2667,12 +2549,7 @@ class Message extends DataClass implements Insertable { 'quotesMessageId': serializer.toJson(quotesMessageId), 'isDeletedFromSender': serializer.toJson(isDeletedFromSender), 'isEdited': serializer.toJson(isEdited), - 'ackByUser': serializer.toJson(ackByUser), - 'ackByServer': serializer.toJson(ackByServer), - 'openedByCounter': serializer.toJson(openedByCounter), - 'openedAt': serializer.toJson(openedAt), 'createdAt': serializer.toJson(createdAt), - 'modifiedAt': serializer.toJson(modifiedAt), }; } @@ -2687,12 +2564,7 @@ class Message extends DataClass implements Insertable { Value quotesMessageId = const Value.absent(), bool? isDeletedFromSender, bool? isEdited, - bool? ackByUser, - bool? ackByServer, - int? openedByCounter, - Value openedAt = const Value.absent(), - DateTime? createdAt, - Value modifiedAt = const Value.absent()}) => + DateTime? createdAt}) => Message( groupId: groupId ?? this.groupId, messageId: messageId ?? this.messageId, @@ -2707,12 +2579,7 @@ class Message extends DataClass implements Insertable { : this.quotesMessageId, isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, isEdited: isEdited ?? this.isEdited, - ackByUser: ackByUser ?? this.ackByUser, - ackByServer: ackByServer ?? this.ackByServer, - openedByCounter: openedByCounter ?? this.openedByCounter, - openedAt: openedAt.present ? openedAt.value : this.openedAt, createdAt: createdAt ?? this.createdAt, - modifiedAt: modifiedAt.present ? modifiedAt.value : this.modifiedAt, ); Message copyWithCompanion(MessagesCompanion data) { return Message( @@ -2733,16 +2600,7 @@ class Message extends DataClass implements Insertable { ? data.isDeletedFromSender.value : this.isDeletedFromSender, isEdited: data.isEdited.present ? data.isEdited.value : this.isEdited, - 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, - openedAt: data.openedAt.present ? data.openedAt.value : this.openedAt, createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, - modifiedAt: - data.modifiedAt.present ? data.modifiedAt.value : this.modifiedAt, ); } @@ -2759,12 +2617,7 @@ class Message extends DataClass implements Insertable { ..write('quotesMessageId: $quotesMessageId, ') ..write('isDeletedFromSender: $isDeletedFromSender, ') ..write('isEdited: $isEdited, ') - ..write('ackByUser: $ackByUser, ') - ..write('ackByServer: $ackByServer, ') - ..write('openedByCounter: $openedByCounter, ') - ..write('openedAt: $openedAt, ') - ..write('createdAt: $createdAt, ') - ..write('modifiedAt: $modifiedAt') + ..write('createdAt: $createdAt') ..write(')')) .toString(); } @@ -2781,12 +2634,7 @@ class Message extends DataClass implements Insertable { quotesMessageId, isDeletedFromSender, isEdited, - ackByUser, - ackByServer, - openedByCounter, - openedAt, - createdAt, - modifiedAt); + createdAt); @override bool operator ==(Object other) => identical(this, other) || @@ -2801,12 +2649,7 @@ class Message extends DataClass implements Insertable { other.quotesMessageId == this.quotesMessageId && other.isDeletedFromSender == this.isDeletedFromSender && other.isEdited == this.isEdited && - other.ackByUser == this.ackByUser && - other.ackByServer == this.ackByServer && - other.openedByCounter == this.openedByCounter && - other.openedAt == this.openedAt && - other.createdAt == this.createdAt && - other.modifiedAt == this.modifiedAt); + other.createdAt == this.createdAt); } class MessagesCompanion extends UpdateCompanion { @@ -2820,12 +2663,7 @@ class MessagesCompanion extends UpdateCompanion { final Value quotesMessageId; final Value isDeletedFromSender; final Value isEdited; - final Value ackByUser; - final Value ackByServer; - final Value openedByCounter; - final Value openedAt; final Value createdAt; - final Value modifiedAt; final Value rowid; const MessagesCompanion({ this.groupId = const Value.absent(), @@ -2838,12 +2676,7 @@ class MessagesCompanion extends UpdateCompanion { this.quotesMessageId = const Value.absent(), this.isDeletedFromSender = const Value.absent(), this.isEdited = 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(), }); MessagesCompanion.insert({ @@ -2857,12 +2690,7 @@ class MessagesCompanion extends UpdateCompanion { this.quotesMessageId = const Value.absent(), this.isDeletedFromSender = const Value.absent(), this.isEdited = 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); static Insertable custom({ @@ -2876,12 +2704,7 @@ class MessagesCompanion extends UpdateCompanion { Expression? quotesMessageId, Expression? isDeletedFromSender, Expression? isEdited, - Expression? ackByUser, - Expression? ackByServer, - Expression? openedByCounter, - Expression? openedAt, Expression? createdAt, - Expression? modifiedAt, Expression? rowid, }) { return RawValuesInsertable({ @@ -2896,12 +2719,7 @@ class MessagesCompanion extends UpdateCompanion { if (isDeletedFromSender != null) 'is_deleted_from_sender': isDeletedFromSender, if (isEdited != null) 'is_edited': isEdited, - 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, - if (modifiedAt != null) 'modified_at': modifiedAt, if (rowid != null) 'rowid': rowid, }); } @@ -2917,12 +2735,7 @@ class MessagesCompanion extends UpdateCompanion { Value? quotesMessageId, Value? isDeletedFromSender, Value? isEdited, - Value? ackByUser, - Value? ackByServer, - Value? openedByCounter, - Value? openedAt, Value? createdAt, - Value? modifiedAt, Value? rowid}) { return MessagesCompanion( groupId: groupId ?? this.groupId, @@ -2935,12 +2748,7 @@ class MessagesCompanion extends UpdateCompanion { quotesMessageId: quotesMessageId ?? this.quotesMessageId, isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender, isEdited: isEdited ?? this.isEdited, - ackByUser: ackByUser ?? this.ackByUser, - ackByServer: ackByServer ?? this.ackByServer, - openedByCounter: openedByCounter ?? this.openedByCounter, - openedAt: openedAt ?? this.openedAt, createdAt: createdAt ?? this.createdAt, - modifiedAt: modifiedAt ?? this.modifiedAt, rowid: rowid ?? this.rowid, ); } @@ -2978,24 +2786,9 @@ class MessagesCompanion extends UpdateCompanion { if (isEdited.present) { map['is_edited'] = Variable(isEdited.value); } - if (ackByUser.present) { - map['ack_by_user'] = Variable(ackByUser.value); - } - if (ackByServer.present) { - map['ack_by_server'] = Variable(ackByServer.value); - } - if (openedByCounter.present) { - map['opened_by_counter'] = Variable(openedByCounter.value); - } - if (openedAt.present) { - map['opened_at'] = Variable(openedAt.value); - } if (createdAt.present) { map['created_at'] = Variable(createdAt.value); } - if (modifiedAt.present) { - map['modified_at'] = Variable(modifiedAt.value); - } if (rowid.present) { map['rowid'] = Variable(rowid.value); } @@ -3015,12 +2808,7 @@ class MessagesCompanion extends UpdateCompanion { ..write('quotesMessageId: $quotesMessageId, ') ..write('isDeletedFromSender: $isDeletedFromSender, ') ..write('isEdited: $isEdited, ') - ..write('ackByUser: $ackByUser, ') - ..write('ackByServer: $ackByServer, ') - ..write('openedByCounter: $openedByCounter, ') - ..write('openedAt: $openedAt, ') ..write('createdAt: $createdAt, ') - ..write('modifiedAt: $modifiedAt, ') ..write('rowid: $rowid') ..write(')')) .toString(); @@ -3033,6 +2821,15 @@ class $MessageHistoriesTable extends MessageHistories final GeneratedDatabase attachedDatabase; final String? _alias; $MessageHistoriesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', aliasedName, false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT')); static const VerificationMeta _messageIdMeta = const VerificationMeta('messageId'); @override @@ -3042,6 +2839,12 @@ class $MessageHistoriesTable extends MessageHistories requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways( 'REFERENCES messages (message_id) ON DELETE CASCADE')); + static const VerificationMeta _contactIdMeta = + const VerificationMeta('contactId'); + @override + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); static const VerificationMeta _contentMeta = const VerificationMeta('content'); @override @@ -3057,7 +2860,8 @@ class $MessageHistoriesTable extends MessageHistories requiredDuringInsert: false, defaultValue: currentDateAndTime); @override - List get $columns => [messageId, content, createdAt]; + List get $columns => + [id, messageId, contactId, content, createdAt]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -3068,12 +2872,21 @@ class $MessageHistoriesTable extends MessageHistories {bool isInserting = false}) { final context = VerificationContext(); final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } if (data.containsKey('message_id')) { context.handle(_messageIdMeta, messageId.isAcceptableOrUnknown(data['message_id']!, _messageIdMeta)); } else if (isInserting) { context.missing(_messageIdMeta); } + if (data.containsKey('contact_id')) { + context.handle(_contactIdMeta, + contactId.isAcceptableOrUnknown(data['contact_id']!, _contactIdMeta)); + } else if (isInserting) { + context.missing(_contactIdMeta); + } if (data.containsKey('content')) { context.handle(_contentMeta, content.isAcceptableOrUnknown(data['content']!, _contentMeta)); @@ -3086,13 +2899,17 @@ class $MessageHistoriesTable extends MessageHistories } @override - Set get $primaryKey => {messageId, createdAt}; + Set get $primaryKey => {id}; @override MessageHistory map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return MessageHistory( + id: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}id'])!, messageId: attachedDatabase.typeMapping .read(DriftSqlType.string, data['${effectivePrefix}message_id'])!, + contactId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}contact_id'])!, content: attachedDatabase.typeMapping .read(DriftSqlType.string, data['${effectivePrefix}content']), createdAt: attachedDatabase.typeMapping @@ -3107,15 +2924,23 @@ class $MessageHistoriesTable extends MessageHistories } class MessageHistory extends DataClass implements Insertable { + final int id; final String messageId; + final int contactId; final String? content; final DateTime createdAt; const MessageHistory( - {required this.messageId, this.content, required this.createdAt}); + {required this.id, + required this.messageId, + required this.contactId, + this.content, + required this.createdAt}); @override Map toColumns(bool nullToAbsent) { final map = {}; + map['id'] = Variable(id); map['message_id'] = Variable(messageId); + map['contact_id'] = Variable(contactId); if (!nullToAbsent || content != null) { map['content'] = Variable(content); } @@ -3125,7 +2950,9 @@ class MessageHistory extends DataClass implements Insertable { MessageHistoriesCompanion toCompanion(bool nullToAbsent) { return MessageHistoriesCompanion( + id: Value(id), messageId: Value(messageId), + contactId: Value(contactId), content: content == null && nullToAbsent ? const Value.absent() : Value(content), @@ -3137,7 +2964,9 @@ class MessageHistory extends DataClass implements Insertable { {ValueSerializer? serializer}) { serializer ??= driftRuntimeOptions.defaultSerializer; return MessageHistory( + id: serializer.fromJson(json['id']), messageId: serializer.fromJson(json['messageId']), + contactId: serializer.fromJson(json['contactId']), content: serializer.fromJson(json['content']), createdAt: serializer.fromJson(json['createdAt']), ); @@ -3146,24 +2975,32 @@ class MessageHistory extends DataClass implements Insertable { Map toJson({ValueSerializer? serializer}) { serializer ??= driftRuntimeOptions.defaultSerializer; return { + 'id': serializer.toJson(id), 'messageId': serializer.toJson(messageId), + 'contactId': serializer.toJson(contactId), 'content': serializer.toJson(content), 'createdAt': serializer.toJson(createdAt), }; } MessageHistory copyWith( - {String? messageId, + {int? id, + String? messageId, + int? contactId, Value content = const Value.absent(), DateTime? createdAt}) => MessageHistory( + id: id ?? this.id, messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, content: content.present ? content.value : this.content, createdAt: createdAt ?? this.createdAt, ); MessageHistory copyWithCompanion(MessageHistoriesCompanion data) { return MessageHistory( + id: data.id.present ? data.id.value : this.id, messageId: data.messageId.present ? data.messageId.value : this.messageId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, content: data.content.present ? data.content.value : this.content, createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, ); @@ -3172,7 +3009,9 @@ class MessageHistory extends DataClass implements Insertable { @override String toString() { return (StringBuffer('MessageHistory(') + ..write('id: $id, ') ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') ..write('content: $content, ') ..write('createdAt: $createdAt') ..write(')')) @@ -3180,85 +3019,99 @@ class MessageHistory extends DataClass implements Insertable { } @override - int get hashCode => Object.hash(messageId, content, createdAt); + int get hashCode => Object.hash(id, messageId, contactId, content, createdAt); @override bool operator ==(Object other) => identical(this, other) || (other is MessageHistory && + other.id == this.id && other.messageId == this.messageId && + other.contactId == this.contactId && other.content == this.content && other.createdAt == this.createdAt); } class MessageHistoriesCompanion extends UpdateCompanion { + final Value id; final Value messageId; + final Value contactId; final Value content; final Value createdAt; - final Value rowid; const MessageHistoriesCompanion({ + this.id = const Value.absent(), this.messageId = const Value.absent(), + this.contactId = const Value.absent(), this.content = const Value.absent(), this.createdAt = const Value.absent(), - this.rowid = const Value.absent(), }); MessageHistoriesCompanion.insert({ + this.id = const Value.absent(), required String messageId, + required int contactId, this.content = const Value.absent(), this.createdAt = const Value.absent(), - this.rowid = const Value.absent(), - }) : messageId = Value(messageId); + }) : messageId = Value(messageId), + contactId = Value(contactId); static Insertable custom({ + Expression? id, Expression? messageId, + Expression? contactId, Expression? content, Expression? createdAt, - Expression? rowid, }) { return RawValuesInsertable({ + if (id != null) 'id': id, if (messageId != null) 'message_id': messageId, + if (contactId != null) 'contact_id': contactId, if (content != null) 'content': content, if (createdAt != null) 'created_at': createdAt, - if (rowid != null) 'rowid': rowid, }); } MessageHistoriesCompanion copyWith( - {Value? messageId, + {Value? id, + Value? messageId, + Value? contactId, Value? content, - Value? createdAt, - Value? rowid}) { + Value? createdAt}) { return MessageHistoriesCompanion( + id: id ?? this.id, messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, content: content ?? this.content, createdAt: createdAt ?? this.createdAt, - rowid: rowid ?? this.rowid, ); } @override Map toColumns(bool nullToAbsent) { final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } if (messageId.present) { map['message_id'] = Variable(messageId.value); } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } if (content.present) { map['content'] = Variable(content.value); } if (createdAt.present) { map['created_at'] = Variable(createdAt.value); } - if (rowid.present) { - map['rowid'] = Variable(rowid.value); - } return map; } @override String toString() { return (StringBuffer('MessageHistoriesCompanion(') + ..write('id: $id, ') ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') ..write('content: $content, ') - ..write('createdAt: $createdAt, ') - ..write('rowid: $rowid') + ..write('createdAt: $createdAt') ..write(')')) .toString(); } @@ -5928,6 +5781,311 @@ class SignalContactSignedPreKeysCompanion } } +class $MessageActionsTable extends MessageActions + with TableInfo<$MessageActionsTable, MessageAction> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $MessageActionsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', aliasedName, false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT')); + static const VerificationMeta _messageIdMeta = + const VerificationMeta('messageId'); + @override + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES messages (message_id) ON DELETE CASCADE')); + static const VerificationMeta _contactIdMeta = + const VerificationMeta('contactId'); + @override + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + @override + late final GeneratedColumnWithTypeConverter type = + GeneratedColumn('type', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true) + .withConverter( + $MessageActionsTable.$convertertype); + static const VerificationMeta _actionAtMeta = + const VerificationMeta('actionAt'); + @override + late final GeneratedColumn actionAt = GeneratedColumn( + 'action_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: currentDateAndTime); + @override + List get $columns => + [id, messageId, contactId, type, actionAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'message_actions'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } + if (data.containsKey('message_id')) { + context.handle(_messageIdMeta, + messageId.isAcceptableOrUnknown(data['message_id']!, _messageIdMeta)); + } else if (isInserting) { + context.missing(_messageIdMeta); + } + if (data.containsKey('contact_id')) { + context.handle(_contactIdMeta, + contactId.isAcceptableOrUnknown(data['contact_id']!, _contactIdMeta)); + } else if (isInserting) { + context.missing(_contactIdMeta); + } + if (data.containsKey('action_at')) { + context.handle(_actionAtMeta, + actionAt.isAcceptableOrUnknown(data['action_at']!, _actionAtMeta)); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + MessageAction map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MessageAction( + id: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}id'])!, + messageId: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}message_id'])!, + contactId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}contact_id'])!, + type: $MessageActionsTable.$convertertype.fromSql(attachedDatabase + .typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}type'])!), + actionAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}action_at'])!, + ); + } + + @override + $MessageActionsTable createAlias(String alias) { + return $MessageActionsTable(attachedDatabase, alias); + } + + static JsonTypeConverter2 $convertertype = + const EnumNameConverter(MessageActionType.values); +} + +class MessageAction extends DataClass implements Insertable { + final int id; + final String messageId; + final int contactId; + final MessageActionType type; + final DateTime actionAt; + const MessageAction( + {required this.id, + required this.messageId, + required this.contactId, + required this.type, + required this.actionAt}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['message_id'] = Variable(messageId); + map['contact_id'] = Variable(contactId); + { + map['type'] = + Variable($MessageActionsTable.$convertertype.toSql(type)); + } + map['action_at'] = Variable(actionAt); + return map; + } + + MessageActionsCompanion toCompanion(bool nullToAbsent) { + return MessageActionsCompanion( + id: Value(id), + messageId: Value(messageId), + contactId: Value(contactId), + type: Value(type), + actionAt: Value(actionAt), + ); + } + + factory MessageAction.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessageAction( + id: serializer.fromJson(json['id']), + messageId: serializer.fromJson(json['messageId']), + contactId: serializer.fromJson(json['contactId']), + type: $MessageActionsTable.$convertertype + .fromJson(serializer.fromJson(json['type'])), + actionAt: serializer.fromJson(json['actionAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'messageId': serializer.toJson(messageId), + 'contactId': serializer.toJson(contactId), + 'type': serializer + .toJson($MessageActionsTable.$convertertype.toJson(type)), + 'actionAt': serializer.toJson(actionAt), + }; + } + + MessageAction copyWith( + {int? id, + String? messageId, + int? contactId, + MessageActionType? type, + DateTime? actionAt}) => + MessageAction( + id: id ?? this.id, + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + ); + MessageAction copyWithCompanion(MessageActionsCompanion data) { + return MessageAction( + id: data.id.present ? data.id.value : this.id, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + type: data.type.present ? data.type.value : this.type, + actionAt: data.actionAt.present ? data.actionAt.value : this.actionAt, + ); + } + + @override + String toString() { + return (StringBuffer('MessageAction(') + ..write('id: $id, ') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('actionAt: $actionAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, messageId, contactId, type, actionAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessageAction && + other.id == this.id && + other.messageId == this.messageId && + other.contactId == this.contactId && + other.type == this.type && + other.actionAt == this.actionAt); +} + +class MessageActionsCompanion extends UpdateCompanion { + final Value id; + final Value messageId; + final Value contactId; + final Value type; + final Value actionAt; + const MessageActionsCompanion({ + this.id = const Value.absent(), + this.messageId = const Value.absent(), + this.contactId = const Value.absent(), + this.type = const Value.absent(), + this.actionAt = const Value.absent(), + }); + MessageActionsCompanion.insert({ + this.id = const Value.absent(), + required String messageId, + required int contactId, + required MessageActionType type, + this.actionAt = const Value.absent(), + }) : messageId = Value(messageId), + contactId = Value(contactId), + type = Value(type); + static Insertable custom({ + Expression? id, + Expression? messageId, + Expression? contactId, + Expression? type, + Expression? actionAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (messageId != null) 'message_id': messageId, + if (contactId != null) 'contact_id': contactId, + if (type != null) 'type': type, + if (actionAt != null) 'action_at': actionAt, + }); + } + + MessageActionsCompanion copyWith( + {Value? id, + Value? messageId, + Value? contactId, + Value? type, + Value? actionAt}) { + return MessageActionsCompanion( + id: id ?? this.id, + messageId: messageId ?? this.messageId, + contactId: contactId ?? this.contactId, + type: type ?? this.type, + actionAt: actionAt ?? this.actionAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (type.present) { + map['type'] = Variable( + $MessageActionsTable.$convertertype.toSql(type.value)); + } + if (actionAt.present) { + map['action_at'] = Variable(actionAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessageActionsCompanion(') + ..write('id: $id, ') + ..write('messageId: $messageId, ') + ..write('contactId: $contactId, ') + ..write('type: $type, ') + ..write('actionAt: $actionAt') + ..write(')')) + .toString(); + } +} + abstract class _$TwonlyDB extends GeneratedDatabase { _$TwonlyDB(QueryExecutor e) : super(e); $TwonlyDBManager get managers => $TwonlyDBManager(this); @@ -5952,6 +6110,7 @@ abstract class _$TwonlyDB extends GeneratedDatabase { $SignalContactPreKeysTable(this); late final $SignalContactSignedPreKeysTable signalContactSignedPreKeys = $SignalContactSignedPreKeysTable(this); + late final $MessageActionsTable messageActions = $MessageActionsTable(this); late final MessagesDao messagesDao = MessagesDao(this as TwonlyDB); late final ContactsDao contactsDao = ContactsDao(this as TwonlyDB); late final SignalDao signalDao = SignalDao(this as TwonlyDB); @@ -5977,7 +6136,8 @@ abstract class _$TwonlyDB extends GeneratedDatabase { signalSenderKeyStores, signalSessionStores, signalContactPreKeys, - signalContactSignedPreKeys + signalContactSignedPreKeys, + messageActions ]; @override StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules( @@ -6039,6 +6199,13 @@ abstract class _$TwonlyDB extends GeneratedDatabase { kind: UpdateKind.delete), ], ), + WritePropagation( + on: TableUpdateQuery.onTableName('messages', + limitUpdateKind: UpdateKind.delete), + result: [ + TableUpdate('message_actions', kind: UpdateKind.delete), + ], + ), ], ); } @@ -7657,12 +7824,7 @@ typedef $$MessagesTableCreateCompanionBuilder = MessagesCompanion Function({ Value quotesMessageId, Value isDeletedFromSender, Value isEdited, - Value ackByUser, - Value ackByServer, - Value openedByCounter, - Value openedAt, Value createdAt, - Value modifiedAt, Value rowid, }); typedef $$MessagesTableUpdateCompanionBuilder = MessagesCompanion Function({ @@ -7676,12 +7838,7 @@ typedef $$MessagesTableUpdateCompanionBuilder = MessagesCompanion Function({ Value quotesMessageId, Value isDeletedFromSender, Value isEdited, - Value ackByUser, - Value ackByServer, - Value openedByCounter, - Value openedAt, Value createdAt, - Value modifiedAt, Value rowid, }); @@ -7797,6 +7954,22 @@ final class $$MessagesTableReferences return ProcessedTableManager( manager.$state.copyWith(prefetchedData: cache)); } + + static MultiTypedResultKey<$MessageActionsTable, List> + _messageActionsRefsTable(_$TwonlyDB db) => + MultiTypedResultKey.fromTable(db.messageActions, + aliasName: $_aliasNameGenerator( + db.messages.messageId, db.messageActions.messageId)); + + $$MessageActionsTableProcessedTableManager get messageActionsRefs { + final manager = $$MessageActionsTableTableManager($_db, $_db.messageActions) + .filter((f) => f.messageId.messageId + .sqlEquals($_itemColumn('message_id')!)); + + final cache = $_typedResult.readTableOrNull(_messageActionsRefsTable($_db)); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache)); + } } class $$MessagesTableFilterComposer @@ -7827,25 +8000,9 @@ class $$MessagesTableFilterComposer ColumnFilters get isEdited => $composableBuilder( column: $table.isEdited, builder: (column) => ColumnFilters(column)); - ColumnFilters get ackByUser => $composableBuilder( - column: $table.ackByUser, builder: (column) => ColumnFilters(column)); - - ColumnFilters get ackByServer => $composableBuilder( - column: $table.ackByServer, builder: (column) => ColumnFilters(column)); - - ColumnFilters get openedByCounter => $composableBuilder( - column: $table.openedByCounter, - builder: (column) => ColumnFilters(column)); - - ColumnFilters get openedAt => $composableBuilder( - column: $table.openedAt, builder: (column) => ColumnFilters(column)); - ColumnFilters get createdAt => $composableBuilder( column: $table.createdAt, builder: (column) => ColumnFilters(column)); - ColumnFilters get modifiedAt => $composableBuilder( - column: $table.modifiedAt, builder: (column) => ColumnFilters(column)); - $$GroupsTableFilterComposer get groupId { final $$GroupsTableFilterComposer composer = $composerBuilder( composer: this, @@ -7988,6 +8145,27 @@ class $$MessagesTableFilterComposer )); return f(composer); } + + Expression messageActionsRefs( + Expression Function($$MessageActionsTableFilterComposer f) f) { + final $$MessageActionsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.messageId, + referencedTable: $db.messageActions, + getReferencedColumn: (t) => t.messageId, + builder: (joinBuilder, + {$addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer}) => + $$MessageActionsTableFilterComposer( + $db: $db, + $table: $db.messageActions, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + )); + return f(composer); + } } class $$MessagesTableOrderingComposer @@ -8019,25 +8197,9 @@ class $$MessagesTableOrderingComposer ColumnOrderings get isEdited => $composableBuilder( column: $table.isEdited, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get ackByUser => $composableBuilder( - column: $table.ackByUser, builder: (column) => ColumnOrderings(column)); - - ColumnOrderings get ackByServer => $composableBuilder( - column: $table.ackByServer, builder: (column) => ColumnOrderings(column)); - - ColumnOrderings get openedByCounter => $composableBuilder( - column: $table.openedByCounter, - builder: (column) => ColumnOrderings(column)); - - ColumnOrderings get openedAt => $composableBuilder( - column: $table.openedAt, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get createdAt => $composableBuilder( column: $table.createdAt, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get modifiedAt => $composableBuilder( - column: $table.modifiedAt, builder: (column) => ColumnOrderings(column)); - $$GroupsTableOrderingComposer get groupId { final $$GroupsTableOrderingComposer composer = $composerBuilder( composer: this, @@ -8146,24 +8308,9 @@ class $$MessagesTableAnnotationComposer GeneratedColumn get isEdited => $composableBuilder(column: $table.isEdited, builder: (column) => column); - GeneratedColumn get ackByUser => - $composableBuilder(column: $table.ackByUser, builder: (column) => column); - - GeneratedColumn get ackByServer => $composableBuilder( - column: $table.ackByServer, builder: (column) => column); - - GeneratedColumn get openedByCounter => $composableBuilder( - column: $table.openedByCounter, builder: (column) => column); - - GeneratedColumn get openedAt => - $composableBuilder(column: $table.openedAt, builder: (column) => column); - GeneratedColumn get createdAt => $composableBuilder(column: $table.createdAt, builder: (column) => column); - GeneratedColumn get modifiedAt => $composableBuilder( - column: $table.modifiedAt, builder: (column) => column); - $$GroupsTableAnnotationComposer get groupId { final $$GroupsTableAnnotationComposer composer = $composerBuilder( composer: this, @@ -8306,6 +8453,27 @@ class $$MessagesTableAnnotationComposer )); return f(composer); } + + Expression messageActionsRefs( + Expression Function($$MessageActionsTableAnnotationComposer a) f) { + final $$MessageActionsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.messageId, + referencedTable: $db.messageActions, + getReferencedColumn: (t) => t.messageId, + builder: (joinBuilder, + {$addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer}) => + $$MessageActionsTableAnnotationComposer( + $db: $db, + $table: $db.messageActions, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + )); + return f(composer); + } } class $$MessagesTableTableManager extends RootTableManager< @@ -8326,7 +8494,8 @@ class $$MessagesTableTableManager extends RootTableManager< bool quotesMessageId, bool messageHistoriesRefs, bool reactionsRefs, - bool receiptsRefs})> { + bool receiptsRefs, + bool messageActionsRefs})> { $$MessagesTableTableManager(_$TwonlyDB db, $MessagesTable table) : super(TableManagerState( db: db, @@ -8348,12 +8517,7 @@ class $$MessagesTableTableManager extends RootTableManager< Value quotesMessageId = const Value.absent(), Value isDeletedFromSender = const Value.absent(), Value isEdited = 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(), - Value modifiedAt = const Value.absent(), Value rowid = const Value.absent(), }) => MessagesCompanion( @@ -8367,12 +8531,7 @@ class $$MessagesTableTableManager extends RootTableManager< quotesMessageId: quotesMessageId, isDeletedFromSender: isDeletedFromSender, isEdited: isEdited, - ackByUser: ackByUser, - ackByServer: ackByServer, - openedByCounter: openedByCounter, - openedAt: openedAt, createdAt: createdAt, - modifiedAt: modifiedAt, rowid: rowid, ), createCompanionCallback: ({ @@ -8386,12 +8545,7 @@ class $$MessagesTableTableManager extends RootTableManager< Value quotesMessageId = const Value.absent(), Value isDeletedFromSender = const Value.absent(), Value isEdited = 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(), - Value modifiedAt = const Value.absent(), Value rowid = const Value.absent(), }) => MessagesCompanion.insert( @@ -8405,12 +8559,7 @@ class $$MessagesTableTableManager extends RootTableManager< quotesMessageId: quotesMessageId, isDeletedFromSender: isDeletedFromSender, isEdited: isEdited, - ackByUser: ackByUser, - ackByServer: ackByServer, - openedByCounter: openedByCounter, - openedAt: openedAt, createdAt: createdAt, - modifiedAt: modifiedAt, rowid: rowid, ), withReferenceMapper: (p0) => p0 @@ -8424,13 +8573,15 @@ class $$MessagesTableTableManager extends RootTableManager< quotesMessageId = false, messageHistoriesRefs = false, reactionsRefs = false, - receiptsRefs = false}) { + receiptsRefs = false, + messageActionsRefs = false}) { return PrefetchHooks( db: db, explicitlyWatchedTables: [ if (messageHistoriesRefs) db.messageHistories, if (reactionsRefs) db.reactions, - if (receiptsRefs) db.receipts + if (receiptsRefs) db.receipts, + if (messageActionsRefs) db.messageActions ], addJoins: < T extends TableManagerState< @@ -8528,6 +8679,19 @@ class $$MessagesTableTableManager extends RootTableManager< referencedItemsForCurrentItem: (item, referencedItems) => referencedItems .where((e) => e.messageId == item.messageId), + typedResults: items), + if (messageActionsRefs) + await $_getPrefetchedData( + currentTable: table, + referencedTable: $$MessagesTableReferences + ._messageActionsRefsTable(db), + managerFromTypedResult: (p0) => + $$MessagesTableReferences(db, table, p0) + .messageActionsRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems + .where((e) => e.messageId == item.messageId), typedResults: items) ]; }, @@ -8554,20 +8718,23 @@ typedef $$MessagesTableProcessedTableManager = ProcessedTableManager< bool quotesMessageId, bool messageHistoriesRefs, bool reactionsRefs, - bool receiptsRefs})>; + bool receiptsRefs, + bool messageActionsRefs})>; typedef $$MessageHistoriesTableCreateCompanionBuilder = MessageHistoriesCompanion Function({ + Value id, required String messageId, + required int contactId, Value content, Value createdAt, - Value rowid, }); typedef $$MessageHistoriesTableUpdateCompanionBuilder = MessageHistoriesCompanion Function({ + Value id, Value messageId, + Value contactId, Value content, Value createdAt, - Value rowid, }); final class $$MessageHistoriesTableReferences @@ -8600,6 +8767,12 @@ class $$MessageHistoriesTableFilterComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); + ColumnFilters get id => $composableBuilder( + column: $table.id, builder: (column) => ColumnFilters(column)); + + ColumnFilters get contactId => $composableBuilder( + column: $table.contactId, builder: (column) => ColumnFilters(column)); + ColumnFilters get content => $composableBuilder( column: $table.content, builder: (column) => ColumnFilters(column)); @@ -8636,6 +8809,12 @@ class $$MessageHistoriesTableOrderingComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get contactId => $composableBuilder( + column: $table.contactId, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get content => $composableBuilder( column: $table.content, builder: (column) => ColumnOrderings(column)); @@ -8672,6 +8851,12 @@ class $$MessageHistoriesTableAnnotationComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get contactId => + $composableBuilder(column: $table.contactId, builder: (column) => column); + GeneratedColumn get content => $composableBuilder(column: $table.content, builder: (column) => column); @@ -8723,28 +8908,32 @@ class $$MessageHistoriesTableTableManager extends RootTableManager< createComputedFieldComposer: () => $$MessageHistoriesTableAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ + Value id = const Value.absent(), Value messageId = const Value.absent(), + Value contactId = const Value.absent(), Value content = const Value.absent(), Value createdAt = const Value.absent(), - Value rowid = const Value.absent(), }) => MessageHistoriesCompanion( + id: id, messageId: messageId, + contactId: contactId, content: content, createdAt: createdAt, - rowid: rowid, ), createCompanionCallback: ({ + Value id = const Value.absent(), required String messageId, + required int contactId, Value content = const Value.absent(), Value createdAt = const Value.absent(), - Value rowid = const Value.absent(), }) => MessageHistoriesCompanion.insert( + id: id, messageId: messageId, + contactId: contactId, content: content, createdAt: createdAt, - rowid: rowid, ), withReferenceMapper: (p0) => p0 .map((e) => ( @@ -10965,6 +11154,279 @@ typedef $$SignalContactSignedPreKeysTableProcessedTableManager ), SignalContactSignedPreKey, PrefetchHooks Function({bool contactId})>; +typedef $$MessageActionsTableCreateCompanionBuilder = MessageActionsCompanion + Function({ + Value id, + required String messageId, + required int contactId, + required MessageActionType type, + Value actionAt, +}); +typedef $$MessageActionsTableUpdateCompanionBuilder = MessageActionsCompanion + Function({ + Value id, + Value messageId, + Value contactId, + Value type, + Value actionAt, +}); + +final class $$MessageActionsTableReferences + extends BaseReferences<_$TwonlyDB, $MessageActionsTable, MessageAction> { + $$MessageActionsTableReferences( + super.$_db, super.$_table, super.$_typedResult); + + static $MessagesTable _messageIdTable(_$TwonlyDB db) => + db.messages.createAlias($_aliasNameGenerator( + db.messageActions.messageId, db.messages.messageId)); + + $$MessagesTableProcessedTableManager get messageId { + final $_column = $_itemColumn('message_id')!; + + final manager = $$MessagesTableTableManager($_db, $_db.messages) + .filter((f) => f.messageId.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_messageIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item])); + } +} + +class $$MessageActionsTableFilterComposer + extends Composer<_$TwonlyDB, $MessageActionsTable> { + $$MessageActionsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, builder: (column) => ColumnFilters(column)); + + ColumnFilters get contactId => $composableBuilder( + column: $table.contactId, builder: (column) => ColumnFilters(column)); + + ColumnWithTypeConverterFilters + get type => $composableBuilder( + column: $table.type, + builder: (column) => ColumnWithTypeConverterFilters(column)); + + ColumnFilters get actionAt => $composableBuilder( + column: $table.actionAt, builder: (column) => ColumnFilters(column)); + + $$MessagesTableFilterComposer get messageId { + final $$MessagesTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.messageId, + referencedTable: $db.messages, + getReferencedColumn: (t) => t.messageId, + builder: (joinBuilder, + {$addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer}) => + $$MessagesTableFilterComposer( + $db: $db, + $table: $db.messages, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + )); + return composer; + } +} + +class $$MessageActionsTableOrderingComposer + extends Composer<_$TwonlyDB, $MessageActionsTable> { + $$MessageActionsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get contactId => $composableBuilder( + column: $table.contactId, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get type => $composableBuilder( + column: $table.type, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get actionAt => $composableBuilder( + column: $table.actionAt, builder: (column) => ColumnOrderings(column)); + + $$MessagesTableOrderingComposer get messageId { + final $$MessagesTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.messageId, + referencedTable: $db.messages, + getReferencedColumn: (t) => t.messageId, + builder: (joinBuilder, + {$addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer}) => + $$MessagesTableOrderingComposer( + $db: $db, + $table: $db.messages, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + )); + return composer; + } +} + +class $$MessageActionsTableAnnotationComposer + extends Composer<_$TwonlyDB, $MessageActionsTable> { + $$MessageActionsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get contactId => + $composableBuilder(column: $table.contactId, builder: (column) => column); + + GeneratedColumnWithTypeConverter get type => + $composableBuilder(column: $table.type, builder: (column) => column); + + GeneratedColumn get actionAt => + $composableBuilder(column: $table.actionAt, builder: (column) => column); + + $$MessagesTableAnnotationComposer get messageId { + final $$MessagesTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.messageId, + referencedTable: $db.messages, + getReferencedColumn: (t) => t.messageId, + builder: (joinBuilder, + {$addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer}) => + $$MessagesTableAnnotationComposer( + $db: $db, + $table: $db.messages, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + )); + return composer; + } +} + +class $$MessageActionsTableTableManager extends RootTableManager< + _$TwonlyDB, + $MessageActionsTable, + MessageAction, + $$MessageActionsTableFilterComposer, + $$MessageActionsTableOrderingComposer, + $$MessageActionsTableAnnotationComposer, + $$MessageActionsTableCreateCompanionBuilder, + $$MessageActionsTableUpdateCompanionBuilder, + (MessageAction, $$MessageActionsTableReferences), + MessageAction, + PrefetchHooks Function({bool messageId})> { + $$MessageActionsTableTableManager(_$TwonlyDB db, $MessageActionsTable table) + : super(TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$MessageActionsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$MessageActionsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$MessageActionsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: ({ + Value id = const Value.absent(), + Value messageId = const Value.absent(), + Value contactId = const Value.absent(), + Value type = const Value.absent(), + Value actionAt = const Value.absent(), + }) => + MessageActionsCompanion( + id: id, + messageId: messageId, + contactId: contactId, + type: type, + actionAt: actionAt, + ), + createCompanionCallback: ({ + Value id = const Value.absent(), + required String messageId, + required int contactId, + required MessageActionType type, + Value actionAt = const Value.absent(), + }) => + MessageActionsCompanion.insert( + id: id, + messageId: messageId, + contactId: contactId, + type: type, + actionAt: actionAt, + ), + withReferenceMapper: (p0) => p0 + .map((e) => ( + e.readTable(table), + $$MessageActionsTableReferences(db, table, e) + )) + .toList(), + prefetchHooksCallback: ({messageId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic>>(state) { + if (messageId) { + state = state.withJoin( + currentTable: table, + currentColumn: table.messageId, + referencedTable: + $$MessageActionsTableReferences._messageIdTable(db), + referencedColumn: $$MessageActionsTableReferences + ._messageIdTable(db) + .messageId, + ) as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + )); +} + +typedef $$MessageActionsTableProcessedTableManager = ProcessedTableManager< + _$TwonlyDB, + $MessageActionsTable, + MessageAction, + $$MessageActionsTableFilterComposer, + $$MessageActionsTableOrderingComposer, + $$MessageActionsTableAnnotationComposer, + $$MessageActionsTableCreateCompanionBuilder, + $$MessageActionsTableUpdateCompanionBuilder, + (MessageAction, $$MessageActionsTableReferences), + MessageAction, + PrefetchHooks Function({bool messageId})>; class $TwonlyDBManager { final _$TwonlyDB _db; @@ -11000,4 +11462,6 @@ class $TwonlyDBManager { get signalContactSignedPreKeys => $$SignalContactSignedPreKeysTableTableManager( _db, _db.signalContactSignedPreKeys); + $$MessageActionsTableTableManager get messageActions => + $$MessageActionsTableTableManager(_db, _db.messageActions); } diff --git a/lib/src/services/api/mediafiles/media_background.service.dart b/lib/src/services/api/mediafiles/media_background.service.dart index 018d17b..7b9102b 100644 --- a/lib/src/services/api/mediafiles/media_background.service.dart +++ b/lib/src/services/api/mediafiles/media_background.service.dart @@ -76,12 +76,22 @@ Future handleUploadStatusUpdate(TaskStatusUpdate update) async { ), ); - await twonlyDB.messagesDao.updateMessagesByMediaId( - media.mediaId, - const MessagesCompanion( - ackByServer: Value(true), - ), - ); + /// As the messages where send in a bulk acknowledge all messages. + + final messages = + await twonlyDB.messagesDao.getMessagesByMediaId(media.mediaId); + for (final message in messages) { + final contacts = + await twonlyDB.groupsDao.getGroupMembers(message.groupId); + for (final contact in contacts) { + await twonlyDB.messagesDao.handleMessageAckByServer( + contact.contactId, + message.messageId, + DateTime.now(), + ); + } + } + return; } Log.error( diff --git a/lib/src/services/api/messages.dart b/lib/src/services/api/messages.dart index c7a84dd..eaab030 100644 --- a/lib/src/services/api/messages.dart +++ b/lib/src/services/api/messages.dart @@ -1,5 +1,6 @@ import 'dart:async'; 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'; @@ -126,11 +127,10 @@ Future<(Uint8List, Uint8List?)?> tryToSendCompleteMessage({ if (resp.isSuccess) { if (receipt.messageId != null) { - await twonlyDB.messagesDao.updateMessageId( + await twonlyDB.messagesDao.handleMessageAckByServer( + receipt.contactId, receipt.messageId!, - const MessagesCompanion( - ackByServer: Value(true), - ), + DateTime.now(), ); } if (!receipt.contactWillSendsReceipt) { @@ -158,6 +158,37 @@ Future<(Uint8List, Uint8List?)?> tryToSendCompleteMessage({ return null; } +Future insertAndSendTextMessage( + String groupId, + String textMessage, +) async { + final message = await twonlyDB.messagesDao.insertMessage( + MessagesCompanion( + groupId: Value(groupId), + content: Value(textMessage), + ), + ); + if (message == null) { + Log.error('Could not insert message into database'); + return; + } + + final groupMembers = await twonlyDB.groupsDao.getGroupMembers(groupId); + + for (final groupMember in groupMembers) { + unawaited(sendCipherText( + groupMember.contactId, + pb.EncryptedContent( + textMessage: pb.EncryptedContent_TextMessage( + senderMessageId: message.messageId, + text: textMessage, + timestamp: Int64(message.createdAt.millisecondsSinceEpoch), + ), + ), + )); + } +} + Future<(Uint8List, Uint8List?)?> sendCipherText( int contactId, pb.EncryptedContent encryptedContent, { diff --git a/lib/src/services/api/server_messages.dart b/lib/src/services/api/server_messages.dart index 58b75ca..74aa8e5 100644 --- a/lib/src/services/api/server_messages.dart +++ b/lib/src/services/api/server_messages.dart @@ -160,7 +160,6 @@ Future handleEncryptedMessage( if (content.hasMessageUpdate()) { await handleMessageUpdate( fromUserId, - content.groupId, content.messageUpdate, ); return null; 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 ef7e433..0b03728 100644 --- a/lib/src/services/api/server_messages/media.server_messages.dart +++ b/lib/src/services/api/server_messages/media.server_messages.dart @@ -92,8 +92,6 @@ Future handleMedia( 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, ), 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 297aa0e..6c7347a 100644 --- a/lib/src/services/api/server_messages/messages.server_messages.dart +++ b/lib/src/services/api/server_messages/messages.server_messages.dart @@ -5,7 +5,6 @@ import 'package:twonly/src/utils/log.dart'; Future handleMessageUpdate( int contactId, - String groupId, EncryptedContent_MessageUpdate messageUpdate, ) async { switch (messageUpdate.type) { @@ -14,7 +13,7 @@ Future handleMessageUpdate( 'Opened message ${messageUpdate.multipleSenderMessageIds.length}'); for (final senderMessageId in messageUpdate.multipleSenderMessageIds) { await twonlyDB.messagesDao.handleMessageOpened( - groupId, + contactId, senderMessageId, fromTimestamp(messageUpdate.timestamp), ); 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 c5cef42..7efbdfd 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 @@ -20,8 +20,6 @@ Future handleTextMessage( 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, ), diff --git a/lib/src/views/settings/developer/automated_testing.view.dart b/lib/src/views/settings/developer/automated_testing.view.dart index 2587c7b..d2b55ee 100644 --- a/lib/src/views/settings/developer/automated_testing.view.dart +++ b/lib/src/views/settings/developer/automated_testing.view.dart @@ -3,8 +3,8 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:twonly/globals.dart'; -import 'package:twonly/src/model/json/message_old.dart'; import 'package:twonly/src/services/api/messages.dart'; +import 'package:twonly/src/utils/misc.dart'; class AutomatedTestingView extends StatefulWidget { const AutomatedTestingView({super.key}); @@ -36,25 +36,27 @@ class _AutomatedTestingViewState extends State { title: const Text('Sending a lot of messages.'), subtitle: Text(lotsOfMessagesStatus), onTap: () async { - await twonlyDB.messageRetransmissionDao - .clearRetransmissionTable(); + final username = await showUserNameDialog(context); + if (username == null) return; final contacts = - await twonlyDB.contactsDao.getAllNotBlockedContacts(); + await twonlyDB.contactsDao.getContactsByUsername(username); for (final contact in contacts) { - for (var i = 0; i < 200; i++) { - setState(() { - lotsOfMessagesStatus = - 'At message $i to ${contact.username}.'; - }); - await sendTextMessage( - contact.userId, - TextMessageContent( - text: 'TestMessage $i', - ), - null, - ); + final groups = + await twonlyDB.groupsDao.getDirectChat(contact.userId); + + for (final group in groups) { + for (var i = 0; i < 200; i++) { + setState(() { + lotsOfMessagesStatus = + 'At message $i to ${contact.username}.'; + }); + await insertAndSendTextMessage( + group.groupId, + 'Message $i.', + ); + } } } }, @@ -64,3 +66,37 @@ class _AutomatedTestingViewState extends State { ); } } + +Future showUserNameDialog( + BuildContext context, +) { + final controller = TextEditingController(); + + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Username'), + content: TextField( + controller: controller, + autofocus: true, + ), + actions: [ + TextButton( + child: Text(context.lang.cancel), + onPressed: () { + Navigator.of(context).pop(); // Close the dialog + }, + ), + TextButton( + child: Text(context.lang.ok), + onPressed: () { + Navigator.of(context) + .pop(controller.text); // Return the input text + }, + ), + ], + ); + }, + ); +} diff --git a/lib/src/views/settings/developer/retransmission_data.view.dart b/lib/src/views/settings/developer/retransmission_data.view.dart index 4889c52..66fe34d 100644 --- a/lib/src/views/settings/developer/retransmission_data.view.dart +++ b/lib/src/views/settings/developer/retransmission_data.view.dart @@ -1,14 +1,7 @@ import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:drift/drift.dart' hide Column; import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/model/json/message_old.dart'; -import 'package:twonly/src/services/api/messages.dart'; class RetransmissionDataView extends StatefulWidget { const RetransmissionDataView({super.key}); @@ -19,33 +12,22 @@ class RetransmissionDataView extends StatefulWidget { class RetransMsg { RetransMsg({ - required this.json, - required this.retrans, + required this.receipt, required this.contact, }); - final MessageJson json; - final MessageRetransmission retrans; + final Receipt receipt; final Contact? contact; static List fromRaw( - List retrans, + List receipts, Map contacts, ) { final res = []; - - for (final retrans in retrans) { - final json = MessageJson.fromJson( - jsonDecode( - utf8.decode( - gzip.decode(retrans.plaintextContent), - ), - ) as Map, - ); + for (final receipt in receipts) { res.add( RetransMsg( - json: json, - retrans: retrans, - contact: contacts[retrans.contactId], + receipt: receipt, + contact: contacts[receipt.contactId], ), ); } @@ -54,9 +36,9 @@ class RetransMsg { } class _RetransmissionDataViewState extends State { - List retransmissions = []; + List retransmissions = []; Map contacts = {}; - StreamSubscription>? subscriptionRetransmission; + StreamSubscription>? subscriptionRetransmission; StreamSubscription>? subscriptionContacts; List messages = []; @@ -85,7 +67,7 @@ class _RetransmissionDataViewState extends State { setState(() {}); }); subscriptionRetransmission = - twonlyDB.messageRetransmissionDao.watchAllMessages().listen((updated) { + twonlyDB.receiptsDao.watchAll().listen((updated) { retransmissions = updated; if (contacts.isNotEmpty) { messages = RetransMsg.fromRaw(retransmissions, contacts); @@ -108,7 +90,7 @@ class _RetransmissionDataViewState extends State { .map( (retrans) => ListTile( title: Text( - '${retrans.retrans.retransmissionId}: ${retrans.json.kind}', + retrans.receipt.receiptId, ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -117,64 +99,13 @@ class _RetransmissionDataViewState extends State { 'To ${retrans.contact?.username}', ), Text( - 'Server-Ack: ${retrans.retrans.acknowledgeByServerAt}', + 'Server-Ack: ${retrans.receipt.ackByServerAt}', ), Text( - 'Retry: ${retrans.retrans.retryCount} : ${retrans.retrans.lastRetry}', + 'Retry: ${retrans.receipt.retryCount} : ${retrans.receipt.lastRetry}', ), ], ), - trailing: SizedBox( - width: 80, - child: Row( - children: [ - SizedBox( - height: 20, - width: 40, - child: Center( - child: GestureDetector( - onDoubleTap: () async { - await twonlyDB.messageRetransmissionDao - .deleteRetransmissionById( - retrans.retrans.retransmissionId, - ); - }, - child: const FaIcon( - FontAwesomeIcons.trash, - size: 15, - ), - ), - ), - ), - SizedBox( - width: 40, - child: OutlinedButton( - style: ButtonStyle( - padding: WidgetStateProperty.all( - EdgeInsets.zero, - ), - ), - onPressed: () async { - await twonlyDB.messageRetransmissionDao - .updateRetransmission( - retrans.retrans.retransmissionId, - const MessageRetransmissionsCompanion( - acknowledgeByServerAt: Value(null), - ), - ); - await sendRetransmitMessage( - retrans.retrans.retransmissionId, - ); - }, - child: const FaIcon( - FontAwesomeIcons.arrowRotateLeft, - size: 15, - ), - ), - ), - ], - ), - ), ), ) .toList(), diff --git a/lib/src/views/settings/help/contact_us.view.dart b/lib/src/views/settings/help/contact_us.view.dart index ad6a570..52d644a 100644 --- a/lib/src/views/settings/help/contact_us.view.dart +++ b/lib/src/views/settings/help/contact_us.view.dart @@ -8,8 +8,6 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/constants/secure_storage_keys.dart'; import 'package:twonly/src/model/protobuf/api/http/http_requests.pb.dart'; -import 'package:twonly/src/services/api/mediafiles/upload.service.dart' - show createDownloadToken, uint8ListToHex; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/views/settings/help/contact_us/submit_message.view.dart'; @@ -32,7 +30,7 @@ class _ContactUsState extends State { Future uploadDebugLog() async { if (debugLogDownloadToken != null) return debugLogDownloadToken; - final downloadToken = createDownloadToken(); + final downloadToken = getRandomUint8List(32); final debugLog = await loadLogFile();