allow user deletion

This commit is contained in:
otsmr 2026-01-17 16:59:58 +01:00
parent b1802111f5
commit f91f2c2fb9
24 changed files with 7664 additions and 269 deletions

View file

@ -194,6 +194,14 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
.watch(); .watch();
} }
Stream<List<GroupMember>> watchContactGroupMember(int contactId) {
return (select(groupMembers)
..where(
(g) => g.contactId.equals(contactId),
))
.watch();
}
Stream<Group?> watchGroup(String groupId) { Stream<Group?> watchGroup(String groupId) {
return (select(groups)..where((t) => t.groupId.equals(groupId))) return (select(groups)..where((t) => t.groupId.equals(groupId)))
.watchSingleOrNull(); .watchSingleOrNull();

View file

@ -92,7 +92,9 @@ class ReceiptsDao extends DatabaseAccessor<TwonlyDB> with _$ReceiptsDaoMixin {
..where( ..where(
(t) => (t) =>
t.ackByServerAt.isNull() | t.ackByServerAt.isNull() |
t.markForRetry.isSmallerThanValue(markedRetriesTime), t.markForRetry.isSmallerThanValue(markedRetriesTime) |
t.markForRetryAfterAccepted
.isSmallerThanValue(markedRetriesTime),
)) ))
.get(); .get();
} }
@ -109,6 +111,19 @@ class ReceiptsDao extends DatabaseAccessor<TwonlyDB> with _$ReceiptsDaoMixin {
.write(updates); .write(updates);
} }
Future<void> updateReceiptWidthUserId(
int fromUserId,
String receiptId,
ReceiptsCompanion updates,
) async {
await (update(receipts)
..where(
(c) =>
c.receiptId.equals(receiptId) & c.contactId.equals(fromUserId),
))
.write(updates);
}
Future<void> markMessagesForRetry(int contactId) async { Future<void> markMessagesForRetry(int contactId) async {
await (update(receipts)..where((c) => c.contactId.equals(contactId))).write( await (update(receipts)..where((c) => c.contactId.equals(contactId))).write(
ReceiptsCompanion( ReceiptsCompanion(

File diff suppressed because one or more lines are too long

View file

@ -21,6 +21,7 @@ class Receipts extends Table {
boolean().withDefault(const Constant(true))(); boolean().withDefault(const Constant(true))();
DateTimeColumn get markForRetry => dateTime().nullable()(); DateTimeColumn get markForRetry => dateTime().nullable()();
DateTimeColumn get markForRetryAfterAccepted => dateTime().nullable()();
DateTimeColumn get ackByServerAt => dateTime().nullable()(); DateTimeColumn get ackByServerAt => dateTime().nullable()();

View file

@ -68,7 +68,7 @@ class TwonlyDB extends _$TwonlyDB {
TwonlyDB.forTesting(DatabaseConnection super.connection); TwonlyDB.forTesting(DatabaseConnection super.connection);
@override @override
int get schemaVersion => 5; int get schemaVersion => 6;
static QueryExecutor _openConnection() { static QueryExecutor _openConnection() {
return driftDatabase( return driftDatabase(
@ -111,6 +111,12 @@ class TwonlyDB extends _$TwonlyDB {
schema.mediaFiles.storedFileHash, schema.mediaFiles.storedFileHash,
); );
}, },
from5To6: (m, schema) async {
await m.addColumn(
schema.receipts,
schema.receipts.markForRetryAfterAccepted,
);
},
), ),
); );
} }

View file

@ -4598,6 +4598,13 @@ class $ReceiptsTable extends Receipts with TableInfo<$ReceiptsTable, Receipt> {
late final GeneratedColumn<DateTime> markForRetry = GeneratedColumn<DateTime>( late final GeneratedColumn<DateTime> markForRetry = GeneratedColumn<DateTime>(
'mark_for_retry', aliasedName, true, 'mark_for_retry', aliasedName, true,
type: DriftSqlType.dateTime, requiredDuringInsert: false); type: DriftSqlType.dateTime, requiredDuringInsert: false);
static const VerificationMeta _markForRetryAfterAcceptedMeta =
const VerificationMeta('markForRetryAfterAccepted');
@override
late final GeneratedColumn<DateTime> markForRetryAfterAccepted =
GeneratedColumn<DateTime>(
'mark_for_retry_after_accepted', aliasedName, true,
type: DriftSqlType.dateTime, requiredDuringInsert: false);
static const VerificationMeta _ackByServerAtMeta = static const VerificationMeta _ackByServerAtMeta =
const VerificationMeta('ackByServerAt'); const VerificationMeta('ackByServerAt');
@override @override
@ -4634,6 +4641,7 @@ class $ReceiptsTable extends Receipts with TableInfo<$ReceiptsTable, Receipt> {
message, message,
contactWillSendsReceipt, contactWillSendsReceipt,
markForRetry, markForRetry,
markForRetryAfterAccepted,
ackByServerAt, ackByServerAt,
retryCount, retryCount,
lastRetry, lastRetry,
@ -4684,6 +4692,13 @@ class $ReceiptsTable extends Receipts with TableInfo<$ReceiptsTable, Receipt> {
markForRetry.isAcceptableOrUnknown( markForRetry.isAcceptableOrUnknown(
data['mark_for_retry']!, _markForRetryMeta)); data['mark_for_retry']!, _markForRetryMeta));
} }
if (data.containsKey('mark_for_retry_after_accepted')) {
context.handle(
_markForRetryAfterAcceptedMeta,
markForRetryAfterAccepted.isAcceptableOrUnknown(
data['mark_for_retry_after_accepted']!,
_markForRetryAfterAcceptedMeta));
}
if (data.containsKey('ack_by_server_at')) { if (data.containsKey('ack_by_server_at')) {
context.handle( context.handle(
_ackByServerAtMeta, _ackByServerAtMeta,
@ -4726,6 +4741,9 @@ class $ReceiptsTable extends Receipts with TableInfo<$ReceiptsTable, Receipt> {
data['${effectivePrefix}contact_will_sends_receipt'])!, data['${effectivePrefix}contact_will_sends_receipt'])!,
markForRetry: attachedDatabase.typeMapping.read( markForRetry: attachedDatabase.typeMapping.read(
DriftSqlType.dateTime, data['${effectivePrefix}mark_for_retry']), DriftSqlType.dateTime, data['${effectivePrefix}mark_for_retry']),
markForRetryAfterAccepted: attachedDatabase.typeMapping.read(
DriftSqlType.dateTime,
data['${effectivePrefix}mark_for_retry_after_accepted']),
ackByServerAt: attachedDatabase.typeMapping.read( ackByServerAt: attachedDatabase.typeMapping.read(
DriftSqlType.dateTime, data['${effectivePrefix}ack_by_server_at']), DriftSqlType.dateTime, data['${effectivePrefix}ack_by_server_at']),
retryCount: attachedDatabase.typeMapping retryCount: attachedDatabase.typeMapping
@ -4752,6 +4770,7 @@ class Receipt extends DataClass implements Insertable<Receipt> {
final Uint8List message; final Uint8List message;
final bool contactWillSendsReceipt; final bool contactWillSendsReceipt;
final DateTime? markForRetry; final DateTime? markForRetry;
final DateTime? markForRetryAfterAccepted;
final DateTime? ackByServerAt; final DateTime? ackByServerAt;
final int retryCount; final int retryCount;
final DateTime? lastRetry; final DateTime? lastRetry;
@ -4763,6 +4782,7 @@ class Receipt extends DataClass implements Insertable<Receipt> {
required this.message, required this.message,
required this.contactWillSendsReceipt, required this.contactWillSendsReceipt,
this.markForRetry, this.markForRetry,
this.markForRetryAfterAccepted,
this.ackByServerAt, this.ackByServerAt,
required this.retryCount, required this.retryCount,
this.lastRetry, this.lastRetry,
@ -4780,6 +4800,10 @@ class Receipt extends DataClass implements Insertable<Receipt> {
if (!nullToAbsent || markForRetry != null) { if (!nullToAbsent || markForRetry != null) {
map['mark_for_retry'] = Variable<DateTime>(markForRetry); map['mark_for_retry'] = Variable<DateTime>(markForRetry);
} }
if (!nullToAbsent || markForRetryAfterAccepted != null) {
map['mark_for_retry_after_accepted'] =
Variable<DateTime>(markForRetryAfterAccepted);
}
if (!nullToAbsent || ackByServerAt != null) { if (!nullToAbsent || ackByServerAt != null) {
map['ack_by_server_at'] = Variable<DateTime>(ackByServerAt); map['ack_by_server_at'] = Variable<DateTime>(ackByServerAt);
} }
@ -4803,6 +4827,10 @@ class Receipt extends DataClass implements Insertable<Receipt> {
markForRetry: markForRetry == null && nullToAbsent markForRetry: markForRetry == null && nullToAbsent
? const Value.absent() ? const Value.absent()
: Value(markForRetry), : Value(markForRetry),
markForRetryAfterAccepted:
markForRetryAfterAccepted == null && nullToAbsent
? const Value.absent()
: Value(markForRetryAfterAccepted),
ackByServerAt: ackByServerAt == null && nullToAbsent ackByServerAt: ackByServerAt == null && nullToAbsent
? const Value.absent() ? const Value.absent()
: Value(ackByServerAt), : Value(ackByServerAt),
@ -4825,6 +4853,8 @@ class Receipt extends DataClass implements Insertable<Receipt> {
contactWillSendsReceipt: contactWillSendsReceipt:
serializer.fromJson<bool>(json['contactWillSendsReceipt']), serializer.fromJson<bool>(json['contactWillSendsReceipt']),
markForRetry: serializer.fromJson<DateTime?>(json['markForRetry']), markForRetry: serializer.fromJson<DateTime?>(json['markForRetry']),
markForRetryAfterAccepted:
serializer.fromJson<DateTime?>(json['markForRetryAfterAccepted']),
ackByServerAt: serializer.fromJson<DateTime?>(json['ackByServerAt']), ackByServerAt: serializer.fromJson<DateTime?>(json['ackByServerAt']),
retryCount: serializer.fromJson<int>(json['retryCount']), retryCount: serializer.fromJson<int>(json['retryCount']),
lastRetry: serializer.fromJson<DateTime?>(json['lastRetry']), lastRetry: serializer.fromJson<DateTime?>(json['lastRetry']),
@ -4842,6 +4872,8 @@ class Receipt extends DataClass implements Insertable<Receipt> {
'contactWillSendsReceipt': 'contactWillSendsReceipt':
serializer.toJson<bool>(contactWillSendsReceipt), serializer.toJson<bool>(contactWillSendsReceipt),
'markForRetry': serializer.toJson<DateTime?>(markForRetry), 'markForRetry': serializer.toJson<DateTime?>(markForRetry),
'markForRetryAfterAccepted':
serializer.toJson<DateTime?>(markForRetryAfterAccepted),
'ackByServerAt': serializer.toJson<DateTime?>(ackByServerAt), 'ackByServerAt': serializer.toJson<DateTime?>(ackByServerAt),
'retryCount': serializer.toJson<int>(retryCount), 'retryCount': serializer.toJson<int>(retryCount),
'lastRetry': serializer.toJson<DateTime?>(lastRetry), 'lastRetry': serializer.toJson<DateTime?>(lastRetry),
@ -4856,6 +4888,7 @@ class Receipt extends DataClass implements Insertable<Receipt> {
Uint8List? message, Uint8List? message,
bool? contactWillSendsReceipt, bool? contactWillSendsReceipt,
Value<DateTime?> markForRetry = const Value.absent(), Value<DateTime?> markForRetry = const Value.absent(),
Value<DateTime?> markForRetryAfterAccepted = const Value.absent(),
Value<DateTime?> ackByServerAt = const Value.absent(), Value<DateTime?> ackByServerAt = const Value.absent(),
int? retryCount, int? retryCount,
Value<DateTime?> lastRetry = const Value.absent(), Value<DateTime?> lastRetry = const Value.absent(),
@ -4869,6 +4902,9 @@ class Receipt extends DataClass implements Insertable<Receipt> {
contactWillSendsReceipt ?? this.contactWillSendsReceipt, contactWillSendsReceipt ?? this.contactWillSendsReceipt,
markForRetry: markForRetry:
markForRetry.present ? markForRetry.value : this.markForRetry, markForRetry.present ? markForRetry.value : this.markForRetry,
markForRetryAfterAccepted: markForRetryAfterAccepted.present
? markForRetryAfterAccepted.value
: this.markForRetryAfterAccepted,
ackByServerAt: ackByServerAt:
ackByServerAt.present ? ackByServerAt.value : this.ackByServerAt, ackByServerAt.present ? ackByServerAt.value : this.ackByServerAt,
retryCount: retryCount ?? this.retryCount, retryCount: retryCount ?? this.retryCount,
@ -4887,6 +4923,9 @@ class Receipt extends DataClass implements Insertable<Receipt> {
markForRetry: data.markForRetry.present markForRetry: data.markForRetry.present
? data.markForRetry.value ? data.markForRetry.value
: this.markForRetry, : this.markForRetry,
markForRetryAfterAccepted: data.markForRetryAfterAccepted.present
? data.markForRetryAfterAccepted.value
: this.markForRetryAfterAccepted,
ackByServerAt: data.ackByServerAt.present ackByServerAt: data.ackByServerAt.present
? data.ackByServerAt.value ? data.ackByServerAt.value
: this.ackByServerAt, : this.ackByServerAt,
@ -4906,6 +4945,7 @@ class Receipt extends DataClass implements Insertable<Receipt> {
..write('message: $message, ') ..write('message: $message, ')
..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ')
..write('markForRetry: $markForRetry, ') ..write('markForRetry: $markForRetry, ')
..write('markForRetryAfterAccepted: $markForRetryAfterAccepted, ')
..write('ackByServerAt: $ackByServerAt, ') ..write('ackByServerAt: $ackByServerAt, ')
..write('retryCount: $retryCount, ') ..write('retryCount: $retryCount, ')
..write('lastRetry: $lastRetry, ') ..write('lastRetry: $lastRetry, ')
@ -4922,6 +4962,7 @@ class Receipt extends DataClass implements Insertable<Receipt> {
$driftBlobEquality.hash(message), $driftBlobEquality.hash(message),
contactWillSendsReceipt, contactWillSendsReceipt,
markForRetry, markForRetry,
markForRetryAfterAccepted,
ackByServerAt, ackByServerAt,
retryCount, retryCount,
lastRetry, lastRetry,
@ -4936,6 +4977,7 @@ class Receipt extends DataClass implements Insertable<Receipt> {
$driftBlobEquality.equals(other.message, this.message) && $driftBlobEquality.equals(other.message, this.message) &&
other.contactWillSendsReceipt == this.contactWillSendsReceipt && other.contactWillSendsReceipt == this.contactWillSendsReceipt &&
other.markForRetry == this.markForRetry && other.markForRetry == this.markForRetry &&
other.markForRetryAfterAccepted == this.markForRetryAfterAccepted &&
other.ackByServerAt == this.ackByServerAt && other.ackByServerAt == this.ackByServerAt &&
other.retryCount == this.retryCount && other.retryCount == this.retryCount &&
other.lastRetry == this.lastRetry && other.lastRetry == this.lastRetry &&
@ -4949,6 +4991,7 @@ class ReceiptsCompanion extends UpdateCompanion<Receipt> {
final Value<Uint8List> message; final Value<Uint8List> message;
final Value<bool> contactWillSendsReceipt; final Value<bool> contactWillSendsReceipt;
final Value<DateTime?> markForRetry; final Value<DateTime?> markForRetry;
final Value<DateTime?> markForRetryAfterAccepted;
final Value<DateTime?> ackByServerAt; final Value<DateTime?> ackByServerAt;
final Value<int> retryCount; final Value<int> retryCount;
final Value<DateTime?> lastRetry; final Value<DateTime?> lastRetry;
@ -4961,6 +5004,7 @@ class ReceiptsCompanion extends UpdateCompanion<Receipt> {
this.message = const Value.absent(), this.message = const Value.absent(),
this.contactWillSendsReceipt = const Value.absent(), this.contactWillSendsReceipt = const Value.absent(),
this.markForRetry = const Value.absent(), this.markForRetry = const Value.absent(),
this.markForRetryAfterAccepted = const Value.absent(),
this.ackByServerAt = const Value.absent(), this.ackByServerAt = const Value.absent(),
this.retryCount = const Value.absent(), this.retryCount = const Value.absent(),
this.lastRetry = const Value.absent(), this.lastRetry = const Value.absent(),
@ -4974,6 +5018,7 @@ class ReceiptsCompanion extends UpdateCompanion<Receipt> {
required Uint8List message, required Uint8List message,
this.contactWillSendsReceipt = const Value.absent(), this.contactWillSendsReceipt = const Value.absent(),
this.markForRetry = const Value.absent(), this.markForRetry = const Value.absent(),
this.markForRetryAfterAccepted = const Value.absent(),
this.ackByServerAt = const Value.absent(), this.ackByServerAt = const Value.absent(),
this.retryCount = const Value.absent(), this.retryCount = const Value.absent(),
this.lastRetry = const Value.absent(), this.lastRetry = const Value.absent(),
@ -4989,6 +5034,7 @@ class ReceiptsCompanion extends UpdateCompanion<Receipt> {
Expression<Uint8List>? message, Expression<Uint8List>? message,
Expression<bool>? contactWillSendsReceipt, Expression<bool>? contactWillSendsReceipt,
Expression<DateTime>? markForRetry, Expression<DateTime>? markForRetry,
Expression<DateTime>? markForRetryAfterAccepted,
Expression<DateTime>? ackByServerAt, Expression<DateTime>? ackByServerAt,
Expression<int>? retryCount, Expression<int>? retryCount,
Expression<DateTime>? lastRetry, Expression<DateTime>? lastRetry,
@ -5003,6 +5049,8 @@ class ReceiptsCompanion extends UpdateCompanion<Receipt> {
if (contactWillSendsReceipt != null) if (contactWillSendsReceipt != null)
'contact_will_sends_receipt': contactWillSendsReceipt, 'contact_will_sends_receipt': contactWillSendsReceipt,
if (markForRetry != null) 'mark_for_retry': markForRetry, if (markForRetry != null) 'mark_for_retry': markForRetry,
if (markForRetryAfterAccepted != null)
'mark_for_retry_after_accepted': markForRetryAfterAccepted,
if (ackByServerAt != null) 'ack_by_server_at': ackByServerAt, if (ackByServerAt != null) 'ack_by_server_at': ackByServerAt,
if (retryCount != null) 'retry_count': retryCount, if (retryCount != null) 'retry_count': retryCount,
if (lastRetry != null) 'last_retry': lastRetry, if (lastRetry != null) 'last_retry': lastRetry,
@ -5018,6 +5066,7 @@ class ReceiptsCompanion extends UpdateCompanion<Receipt> {
Value<Uint8List>? message, Value<Uint8List>? message,
Value<bool>? contactWillSendsReceipt, Value<bool>? contactWillSendsReceipt,
Value<DateTime?>? markForRetry, Value<DateTime?>? markForRetry,
Value<DateTime?>? markForRetryAfterAccepted,
Value<DateTime?>? ackByServerAt, Value<DateTime?>? ackByServerAt,
Value<int>? retryCount, Value<int>? retryCount,
Value<DateTime?>? lastRetry, Value<DateTime?>? lastRetry,
@ -5031,6 +5080,8 @@ class ReceiptsCompanion extends UpdateCompanion<Receipt> {
contactWillSendsReceipt: contactWillSendsReceipt:
contactWillSendsReceipt ?? this.contactWillSendsReceipt, contactWillSendsReceipt ?? this.contactWillSendsReceipt,
markForRetry: markForRetry ?? this.markForRetry, markForRetry: markForRetry ?? this.markForRetry,
markForRetryAfterAccepted:
markForRetryAfterAccepted ?? this.markForRetryAfterAccepted,
ackByServerAt: ackByServerAt ?? this.ackByServerAt, ackByServerAt: ackByServerAt ?? this.ackByServerAt,
retryCount: retryCount ?? this.retryCount, retryCount: retryCount ?? this.retryCount,
lastRetry: lastRetry ?? this.lastRetry, lastRetry: lastRetry ?? this.lastRetry,
@ -5061,6 +5112,10 @@ class ReceiptsCompanion extends UpdateCompanion<Receipt> {
if (markForRetry.present) { if (markForRetry.present) {
map['mark_for_retry'] = Variable<DateTime>(markForRetry.value); map['mark_for_retry'] = Variable<DateTime>(markForRetry.value);
} }
if (markForRetryAfterAccepted.present) {
map['mark_for_retry_after_accepted'] =
Variable<DateTime>(markForRetryAfterAccepted.value);
}
if (ackByServerAt.present) { if (ackByServerAt.present) {
map['ack_by_server_at'] = Variable<DateTime>(ackByServerAt.value); map['ack_by_server_at'] = Variable<DateTime>(ackByServerAt.value);
} }
@ -5088,6 +5143,7 @@ class ReceiptsCompanion extends UpdateCompanion<Receipt> {
..write('message: $message, ') ..write('message: $message, ')
..write('contactWillSendsReceipt: $contactWillSendsReceipt, ') ..write('contactWillSendsReceipt: $contactWillSendsReceipt, ')
..write('markForRetry: $markForRetry, ') ..write('markForRetry: $markForRetry, ')
..write('markForRetryAfterAccepted: $markForRetryAfterAccepted, ')
..write('ackByServerAt: $ackByServerAt, ') ..write('ackByServerAt: $ackByServerAt, ')
..write('retryCount: $retryCount, ') ..write('retryCount: $retryCount, ')
..write('lastRetry: $lastRetry, ') ..write('lastRetry: $lastRetry, ')
@ -11771,6 +11827,7 @@ typedef $$ReceiptsTableCreateCompanionBuilder = ReceiptsCompanion Function({
required Uint8List message, required Uint8List message,
Value<bool> contactWillSendsReceipt, Value<bool> contactWillSendsReceipt,
Value<DateTime?> markForRetry, Value<DateTime?> markForRetry,
Value<DateTime?> markForRetryAfterAccepted,
Value<DateTime?> ackByServerAt, Value<DateTime?> ackByServerAt,
Value<int> retryCount, Value<int> retryCount,
Value<DateTime?> lastRetry, Value<DateTime?> lastRetry,
@ -11784,6 +11841,7 @@ typedef $$ReceiptsTableUpdateCompanionBuilder = ReceiptsCompanion Function({
Value<Uint8List> message, Value<Uint8List> message,
Value<bool> contactWillSendsReceipt, Value<bool> contactWillSendsReceipt,
Value<DateTime?> markForRetry, Value<DateTime?> markForRetry,
Value<DateTime?> markForRetryAfterAccepted,
Value<DateTime?> ackByServerAt, Value<DateTime?> ackByServerAt,
Value<int> retryCount, Value<int> retryCount,
Value<DateTime?> lastRetry, Value<DateTime?> lastRetry,
@ -11848,6 +11906,10 @@ class $$ReceiptsTableFilterComposer
ColumnFilters<DateTime> get markForRetry => $composableBuilder( ColumnFilters<DateTime> get markForRetry => $composableBuilder(
column: $table.markForRetry, builder: (column) => ColumnFilters(column)); column: $table.markForRetry, builder: (column) => ColumnFilters(column));
ColumnFilters<DateTime> get markForRetryAfterAccepted => $composableBuilder(
column: $table.markForRetryAfterAccepted,
builder: (column) => ColumnFilters(column));
ColumnFilters<DateTime> get ackByServerAt => $composableBuilder( ColumnFilters<DateTime> get ackByServerAt => $composableBuilder(
column: $table.ackByServerAt, builder: (column) => ColumnFilters(column)); column: $table.ackByServerAt, builder: (column) => ColumnFilters(column));
@ -11924,6 +11986,10 @@ class $$ReceiptsTableOrderingComposer
column: $table.markForRetry, column: $table.markForRetry,
builder: (column) => ColumnOrderings(column)); builder: (column) => ColumnOrderings(column));
ColumnOrderings<DateTime> get markForRetryAfterAccepted => $composableBuilder(
column: $table.markForRetryAfterAccepted,
builder: (column) => ColumnOrderings(column));
ColumnOrderings<DateTime> get ackByServerAt => $composableBuilder( ColumnOrderings<DateTime> get ackByServerAt => $composableBuilder(
column: $table.ackByServerAt, column: $table.ackByServerAt,
builder: (column) => ColumnOrderings(column)); builder: (column) => ColumnOrderings(column));
@ -11999,6 +12065,9 @@ class $$ReceiptsTableAnnotationComposer
GeneratedColumn<DateTime> get markForRetry => $composableBuilder( GeneratedColumn<DateTime> get markForRetry => $composableBuilder(
column: $table.markForRetry, builder: (column) => column); column: $table.markForRetry, builder: (column) => column);
GeneratedColumn<DateTime> get markForRetryAfterAccepted => $composableBuilder(
column: $table.markForRetryAfterAccepted, builder: (column) => column);
GeneratedColumn<DateTime> get ackByServerAt => $composableBuilder( GeneratedColumn<DateTime> get ackByServerAt => $composableBuilder(
column: $table.ackByServerAt, builder: (column) => column); column: $table.ackByServerAt, builder: (column) => column);
@ -12081,6 +12150,7 @@ class $$ReceiptsTableTableManager extends RootTableManager<
Value<Uint8List> message = const Value.absent(), Value<Uint8List> message = const Value.absent(),
Value<bool> contactWillSendsReceipt = const Value.absent(), Value<bool> contactWillSendsReceipt = const Value.absent(),
Value<DateTime?> markForRetry = const Value.absent(), Value<DateTime?> markForRetry = const Value.absent(),
Value<DateTime?> markForRetryAfterAccepted = const Value.absent(),
Value<DateTime?> ackByServerAt = const Value.absent(), Value<DateTime?> ackByServerAt = const Value.absent(),
Value<int> retryCount = const Value.absent(), Value<int> retryCount = const Value.absent(),
Value<DateTime?> lastRetry = const Value.absent(), Value<DateTime?> lastRetry = const Value.absent(),
@ -12094,6 +12164,7 @@ class $$ReceiptsTableTableManager extends RootTableManager<
message: message, message: message,
contactWillSendsReceipt: contactWillSendsReceipt, contactWillSendsReceipt: contactWillSendsReceipt,
markForRetry: markForRetry, markForRetry: markForRetry,
markForRetryAfterAccepted: markForRetryAfterAccepted,
ackByServerAt: ackByServerAt, ackByServerAt: ackByServerAt,
retryCount: retryCount, retryCount: retryCount,
lastRetry: lastRetry, lastRetry: lastRetry,
@ -12107,6 +12178,7 @@ class $$ReceiptsTableTableManager extends RootTableManager<
required Uint8List message, required Uint8List message,
Value<bool> contactWillSendsReceipt = const Value.absent(), Value<bool> contactWillSendsReceipt = const Value.absent(),
Value<DateTime?> markForRetry = const Value.absent(), Value<DateTime?> markForRetry = const Value.absent(),
Value<DateTime?> markForRetryAfterAccepted = const Value.absent(),
Value<DateTime?> ackByServerAt = const Value.absent(), Value<DateTime?> ackByServerAt = const Value.absent(),
Value<int> retryCount = const Value.absent(), Value<int> retryCount = const Value.absent(),
Value<DateTime?> lastRetry = const Value.absent(), Value<DateTime?> lastRetry = const Value.absent(),
@ -12120,6 +12192,7 @@ class $$ReceiptsTableTableManager extends RootTableManager<
message: message, message: message,
contactWillSendsReceipt: contactWillSendsReceipt, contactWillSendsReceipt: contactWillSendsReceipt,
markForRetry: markForRetry, markForRetry: markForRetry,
markForRetryAfterAccepted: markForRetryAfterAccepted,
ackByServerAt: ackByServerAt, ackByServerAt: ackByServerAt,
retryCount: retryCount, retryCount: retryCount,
lastRetry: lastRetry, lastRetry: lastRetry,

View file

@ -2393,11 +2393,423 @@ class Shape19 extends i0.VersionedTable {
i1.GeneratedColumn<DateTime> _column_103(String aliasedName) => i1.GeneratedColumn<DateTime> _column_103(String aliasedName) =>
i1.GeneratedColumn<DateTime>('mark_for_retry', aliasedName, true, i1.GeneratedColumn<DateTime>('mark_for_retry', aliasedName, true,
type: i1.DriftSqlType.dateTime); type: i1.DriftSqlType.dateTime);
final class Schema6 extends i0.VersionedSchema {
Schema6({required super.database}) : super(version: 6);
@override
late final List<i1.DatabaseSchemaEntity> entities = [
contacts,
groups,
mediaFiles,
messages,
messageHistories,
reactions,
groupMembers,
receipts,
receivedReceipts,
signalIdentityKeyStores,
signalPreKeyStores,
signalSenderKeyStores,
signalSessionStores,
signalContactPreKeys,
signalContactSignedPreKeys,
messageActions,
groupHistories,
];
late final Shape0 contacts = Shape0(
source: i0.VersionedTable(
entityName: 'contacts',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(user_id)',
],
columns: [
_column_0,
_column_1,
_column_2,
_column_3,
_column_4,
_column_5,
_column_6,
_column_7,
_column_8,
_column_9,
_column_10,
_column_11,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape17 groups = Shape17(
source: i0.VersionedTable(
entityName: 'groups',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(group_id)',
],
columns: [
_column_13,
_column_14,
_column_15,
_column_16,
_column_17,
_column_18,
_column_19,
_column_20,
_column_21,
_column_22,
_column_23,
_column_24,
_column_100,
_column_25,
_column_26,
_column_27,
_column_12,
_column_28,
_column_29,
_column_30,
_column_31,
_column_32,
_column_33,
_column_34,
_column_35,
],
attachedDatabase: database,
),
alias: null);
late final Shape18 mediaFiles = Shape18(
source: i0.VersionedTable(
entityName: 'media_files',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(media_id)',
],
columns: [
_column_36,
_column_37,
_column_38,
_column_39,
_column_40,
_column_41,
_column_42,
_column_43,
_column_44,
_column_45,
_column_46,
_column_47,
_column_48,
_column_49,
_column_102,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape3 messages = Shape3(
source: i0.VersionedTable(
entityName: 'messages',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(message_id)',
],
columns: [
_column_50,
_column_51,
_column_52,
_column_37,
_column_53,
_column_54,
_column_55,
_column_56,
_column_46,
_column_57,
_column_58,
_column_59,
_column_60,
_column_12,
_column_61,
_column_62,
_column_63,
],
attachedDatabase: database,
),
alias: null);
late final Shape4 messageHistories = Shape4(
source: i0.VersionedTable(
entityName: 'message_histories',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_64,
_column_65,
_column_66,
_column_53,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape5 reactions = Shape5(
source: i0.VersionedTable(
entityName: 'reactions',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(message_id, sender_id, emoji)',
],
columns: [
_column_65,
_column_67,
_column_68,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape6 groupMembers = Shape6(
source: i0.VersionedTable(
entityName: 'group_members',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(group_id, contact_id)',
],
columns: [
_column_50,
_column_69,
_column_70,
_column_71,
_column_72,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape20 receipts = Shape20(
source: i0.VersionedTable(
entityName: 'receipts',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(receipt_id)',
],
columns: [
_column_73,
_column_74,
_column_75,
_column_76,
_column_77,
_column_103,
_column_104,
_column_78,
_column_79,
_column_80,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape8 receivedReceipts = Shape8(
source: i0.VersionedTable(
entityName: 'received_receipts',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(receipt_id)',
],
columns: [
_column_73,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape9 signalIdentityKeyStores = Shape9(
source: i0.VersionedTable(
entityName: 'signal_identity_key_stores',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(device_id, name)',
],
columns: [
_column_81,
_column_82,
_column_83,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape10 signalPreKeyStores = Shape10(
source: i0.VersionedTable(
entityName: 'signal_pre_key_stores',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(pre_key_id)',
],
columns: [
_column_84,
_column_85,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape11 signalSenderKeyStores = Shape11(
source: i0.VersionedTable(
entityName: 'signal_sender_key_stores',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(sender_key_name)',
],
columns: [
_column_86,
_column_87,
],
attachedDatabase: database,
),
alias: null);
late final Shape12 signalSessionStores = Shape12(
source: i0.VersionedTable(
entityName: 'signal_session_stores',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(device_id, name)',
],
columns: [
_column_81,
_column_82,
_column_88,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape13 signalContactPreKeys = Shape13(
source: i0.VersionedTable(
entityName: 'signal_contact_pre_keys',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(contact_id, pre_key_id)',
],
columns: [
_column_74,
_column_84,
_column_85,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape14 signalContactSignedPreKeys = Shape14(
source: i0.VersionedTable(
entityName: 'signal_contact_signed_pre_keys',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(contact_id)',
],
columns: [
_column_74,
_column_89,
_column_90,
_column_91,
_column_12,
],
attachedDatabase: database,
),
alias: null);
late final Shape15 messageActions = Shape15(
source: i0.VersionedTable(
entityName: 'message_actions',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(message_id, contact_id, type)',
],
columns: [
_column_65,
_column_92,
_column_37,
_column_93,
],
attachedDatabase: database,
),
alias: null);
late final Shape16 groupHistories = Shape16(
source: i0.VersionedTable(
entityName: 'group_histories',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(group_history_id)',
],
columns: [
_column_94,
_column_50,
_column_95,
_column_101,
_column_97,
_column_98,
_column_99,
_column_37,
_column_93,
],
attachedDatabase: database,
),
alias: null);
}
class Shape20 extends i0.VersionedTable {
Shape20({required super.source, required super.alias}) : super.aliased();
i1.GeneratedColumn<String> get receiptId =>
columnsByName['receipt_id']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<int> get contactId =>
columnsByName['contact_id']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<String> get messageId =>
columnsByName['message_id']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<i2.Uint8List> get message =>
columnsByName['message']! as i1.GeneratedColumn<i2.Uint8List>;
i1.GeneratedColumn<bool> get contactWillSendsReceipt =>
columnsByName['contact_will_sends_receipt']! as i1.GeneratedColumn<bool>;
i1.GeneratedColumn<DateTime> get markForRetry =>
columnsByName['mark_for_retry']! as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<DateTime> get markForRetryAfterAccepted =>
columnsByName['mark_for_retry_after_accepted']!
as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<DateTime> get ackByServerAt =>
columnsByName['ack_by_server_at']! as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<int> get retryCount =>
columnsByName['retry_count']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<DateTime> get lastRetry =>
columnsByName['last_retry']! as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<DateTime> get createdAt =>
columnsByName['created_at']! as i1.GeneratedColumn<DateTime>;
}
i1.GeneratedColumn<DateTime> _column_104(String aliasedName) =>
i1.GeneratedColumn<DateTime>(
'mark_for_retry_after_accepted', aliasedName, true,
type: i1.DriftSqlType.dateTime);
i0.MigrationStepWithVersion migrationSteps({ i0.MigrationStepWithVersion migrationSteps({
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2, required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3, required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4, required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4,
required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5, required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5,
required Future<void> Function(i1.Migrator m, Schema6 schema) from5To6,
}) { }) {
return (currentVersion, database) async { return (currentVersion, database) async {
switch (currentVersion) { switch (currentVersion) {
@ -2421,6 +2833,11 @@ i0.MigrationStepWithVersion migrationSteps({
final migrator = i1.Migrator(database, schema); final migrator = i1.Migrator(database, schema);
await from4To5(migrator, schema); await from4To5(migrator, schema);
return 5; return 5;
case 5:
final schema = Schema6(database: database);
final migrator = i1.Migrator(database, schema);
await from5To6(migrator, schema);
return 6;
default: default:
throw ArgumentError.value('Unknown migration from $currentVersion'); throw ArgumentError.value('Unknown migration from $currentVersion');
} }
@ -2432,6 +2849,7 @@ i1.OnUpgrade stepByStep({
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3, required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4, required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4,
required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5, required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5,
required Future<void> Function(i1.Migrator m, Schema6 schema) from5To6,
}) => }) =>
i0.VersionedSchema.stepByStepHelper( i0.VersionedSchema.stepByStepHelper(
step: migrationSteps( step: migrationSteps(
@ -2439,4 +2857,5 @@ i1.OnUpgrade stepByStep({
from2To3: from2To3, from2To3: from2To3,
from3To4: from3To4, from3To4: from3To4,
from4To5: from4To5, from4To5: from4To5,
from5To6: from5To6,
)); ));

View file

@ -1021,7 +1021,7 @@ abstract class AppLocalizations {
/// No description provided for @contactRemoveBody. /// No description provided for @contactRemoveBody.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
/// **'Remove the user and permanently delete the chat and all associated media files. This will also delete YOUR ACCOUNT FROM YOUR CONTACT\'S PHONE.'** /// **'Permanently remove the user. If the user tries to send you a new message, you will have to accept the user again first.'**
String get contactRemoveBody; String get contactRemoveBody;
/// No description provided for @undo. /// No description provided for @undo.
@ -2925,6 +2925,12 @@ abstract class AppLocalizations {
/// In en, this message translates to: /// In en, this message translates to:
/// **'Store as default'** /// **'Store as default'**
String get storeAsDefault; String get storeAsDefault;
/// No description provided for @deleteUserErrorMessage.
///
/// In en, this message translates to:
/// **'You can only delete the contact once the direct chat has been deleted and the contact is no longer a member of a group.'**
String get deleteUserErrorMessage;
} }
class _AppLocalizationsDelegate class _AppLocalizationsDelegate

View file

@ -517,7 +517,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override @override
String get contactRemoveBody => String get contactRemoveBody =>
'Entferne den Benutzer und lösche den Chat sowie alle zugehörigen Mediendateien dauerhaft. Dadurch wird auch DEIN KONTO VON DEM TELEFON DEINES KONTAKTS gelöscht.'; 'Den Benutzer dauerhaft entfernen. Wenn der Benutzer versucht, dir eine neue Nachricht zu senden, musst du den Benutzer erst wieder akzeptieren.';
@override @override
String get undo => 'Rückgängig'; String get undo => 'Rückgängig';
@ -1627,4 +1627,8 @@ class AppLocalizationsDe extends AppLocalizations {
@override @override
String get storeAsDefault => 'Als Standard speichern'; String get storeAsDefault => 'Als Standard speichern';
@override
String get deleteUserErrorMessage =>
'Du kannst den Kontakt erst löschen, wenn der direkte Chat gelöscht wurde und der Kontakt nicht mehr Mitglied einer Gruppe ist.';
} }

View file

@ -512,7 +512,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get contactRemoveBody => String get contactRemoveBody =>
'Remove the user and permanently delete the chat and all associated media files. This will also delete YOUR ACCOUNT FROM YOUR CONTACT\'S PHONE.'; 'Permanently remove the user. If the user tries to send you a new message, you will have to accept the user again first.';
@override @override
String get undo => 'Undo'; String get undo => 'Undo';
@ -1615,4 +1615,8 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get storeAsDefault => 'Store as default'; String get storeAsDefault => 'Store as default';
@override
String get deleteUserErrorMessage =>
'You can only delete the contact once the direct chat has been deleted and the contact is no longer a member of a group.';
} }

View file

@ -512,7 +512,7 @@ class AppLocalizationsSv extends AppLocalizations {
@override @override
String get contactRemoveBody => String get contactRemoveBody =>
'Remove the user and permanently delete the chat and all associated media files. This will also delete YOUR ACCOUNT FROM YOUR CONTACT\'S PHONE.'; 'Permanently remove the user. If the user tries to send you a new message, you will have to accept the user again first.';
@override @override
String get undo => 'Undo'; String get undo => 'Undo';
@ -1615,4 +1615,8 @@ class AppLocalizationsSv extends AppLocalizations {
@override @override
String get storeAsDefault => 'Store as default'; String get storeAsDefault => 'Store as default';
@override
String get deleteUserErrorMessage =>
'You can only delete the contact once the direct chat has been deleted and the contact is no longer a member of a group.';
} }

@ -1 +1 @@
Subproject commit 775c0ffd9523177478681ecff4e8c4613bf57ee3 Subproject commit 4096b342802fc07be92070c7db6f46353790876b

View file

@ -311,6 +311,82 @@ class PlaintextContent extends $pb.GeneratedMessage {
PlaintextContent_RetryErrorMessage ensureRetryControlError() => $_ensure(1); PlaintextContent_RetryErrorMessage ensureRetryControlError() => $_ensure(1);
} }
class EncryptedContent_ErrorMessages extends $pb.GeneratedMessage {
factory EncryptedContent_ErrorMessages({
EncryptedContent_ErrorMessages_Type? type,
$core.String? relatedReceiptId,
}) {
final result = create();
if (type != null) result.type = type;
if (relatedReceiptId != null) result.relatedReceiptId = relatedReceiptId;
return result;
}
EncryptedContent_ErrorMessages._();
factory EncryptedContent_ErrorMessages.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory EncryptedContent_ErrorMessages.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'EncryptedContent.ErrorMessages',
createEmptyInstance: create)
..e<EncryptedContent_ErrorMessages_Type>(
1, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE,
defaultOrMaker: EncryptedContent_ErrorMessages_Type
.ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD,
valueOf: EncryptedContent_ErrorMessages_Type.valueOf,
enumValues: EncryptedContent_ErrorMessages_Type.values)
..aOS(2, _omitFieldNames ? '' : 'relatedReceiptId')
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
EncryptedContent_ErrorMessages clone() =>
EncryptedContent_ErrorMessages()..mergeFromMessage(this);
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
EncryptedContent_ErrorMessages copyWith(
void Function(EncryptedContent_ErrorMessages) updates) =>
super.copyWith(
(message) => updates(message as EncryptedContent_ErrorMessages))
as EncryptedContent_ErrorMessages;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static EncryptedContent_ErrorMessages create() =>
EncryptedContent_ErrorMessages._();
@$core.override
EncryptedContent_ErrorMessages createEmptyInstance() => create();
static $pb.PbList<EncryptedContent_ErrorMessages> createRepeated() =>
$pb.PbList<EncryptedContent_ErrorMessages>();
@$core.pragma('dart2js:noInline')
static EncryptedContent_ErrorMessages getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<EncryptedContent_ErrorMessages>(create);
static EncryptedContent_ErrorMessages? _defaultInstance;
@$pb.TagNumber(1)
EncryptedContent_ErrorMessages_Type get type => $_getN(0);
@$pb.TagNumber(1)
set type(EncryptedContent_ErrorMessages_Type value) => $_setField(1, value);
@$pb.TagNumber(1)
$core.bool hasType() => $_has(0);
@$pb.TagNumber(1)
void clearType() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get relatedReceiptId => $_getSZ(1);
@$pb.TagNumber(2)
set relatedReceiptId($core.String value) => $_setString(1, value);
@$pb.TagNumber(2)
$core.bool hasRelatedReceiptId() => $_has(1);
@$pb.TagNumber(2)
void clearRelatedReceiptId() => $_clearField(2);
}
class EncryptedContent_GroupCreate extends $pb.GeneratedMessage { class EncryptedContent_GroupCreate extends $pb.GeneratedMessage {
factory EncryptedContent_GroupCreate({ factory EncryptedContent_GroupCreate({
$core.List<$core.int>? stateKey, $core.List<$core.int>? stateKey,
@ -1519,6 +1595,7 @@ class EncryptedContent extends $pb.GeneratedMessage {
EncryptedContent_GroupJoin? groupJoin, EncryptedContent_GroupJoin? groupJoin,
EncryptedContent_GroupUpdate? groupUpdate, EncryptedContent_GroupUpdate? groupUpdate,
EncryptedContent_ResendGroupPublicKey? resendGroupPublicKey, EncryptedContent_ResendGroupPublicKey? resendGroupPublicKey,
EncryptedContent_ErrorMessages? errorMessages,
}) { }) {
final result = create(); final result = create();
if (groupId != null) result.groupId = groupId; if (groupId != null) result.groupId = groupId;
@ -1539,6 +1616,7 @@ class EncryptedContent extends $pb.GeneratedMessage {
if (groupUpdate != null) result.groupUpdate = groupUpdate; if (groupUpdate != null) result.groupUpdate = groupUpdate;
if (resendGroupPublicKey != null) if (resendGroupPublicKey != null)
result.resendGroupPublicKey = resendGroupPublicKey; result.resendGroupPublicKey = resendGroupPublicKey;
if (errorMessages != null) result.errorMessages = errorMessages;
return result; return result;
} }
@ -1599,6 +1677,9 @@ class EncryptedContent extends $pb.GeneratedMessage {
17, _omitFieldNames ? '' : 'resendGroupPublicKey', 17, _omitFieldNames ? '' : 'resendGroupPublicKey',
protoName: 'resendGroupPublicKey', protoName: 'resendGroupPublicKey',
subBuilder: EncryptedContent_ResendGroupPublicKey.create) subBuilder: EncryptedContent_ResendGroupPublicKey.create)
..aOM<EncryptedContent_ErrorMessages>(
18, _omitFieldNames ? '' : 'errorMessages',
subBuilder: EncryptedContent_ErrorMessages.create)
..hasRequiredFields = false; ..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@ -1797,6 +1878,18 @@ class EncryptedContent extends $pb.GeneratedMessage {
@$pb.TagNumber(17) @$pb.TagNumber(17)
EncryptedContent_ResendGroupPublicKey ensureResendGroupPublicKey() => EncryptedContent_ResendGroupPublicKey ensureResendGroupPublicKey() =>
$_ensure(15); $_ensure(15);
@$pb.TagNumber(18)
EncryptedContent_ErrorMessages get errorMessages => $_getN(16);
@$pb.TagNumber(18)
set errorMessages(EncryptedContent_ErrorMessages value) =>
$_setField(18, value);
@$pb.TagNumber(18)
$core.bool hasErrorMessages() => $_has(16);
@$pb.TagNumber(18)
void clearErrorMessages() => $_clearField(18);
@$pb.TagNumber(18)
EncryptedContent_ErrorMessages ensureErrorMessages() => $_ensure(16);
} }
const $core.bool _omitFieldNames = const $core.bool _omitFieldNames =

View file

@ -65,6 +65,32 @@ class PlaintextContent_DecryptionErrorMessage_Type extends $pb.ProtobufEnum {
const PlaintextContent_DecryptionErrorMessage_Type._(super.value, super.name); const PlaintextContent_DecryptionErrorMessage_Type._(super.value, super.name);
} }
class EncryptedContent_ErrorMessages_Type extends $pb.ProtobufEnum {
static const EncryptedContent_ErrorMessages_Type
ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD =
EncryptedContent_ErrorMessages_Type._(
0,
_omitEnumNames
? ''
: 'ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD');
static const EncryptedContent_ErrorMessages_Type UNKNOWN_MESSAGE_TYPE =
EncryptedContent_ErrorMessages_Type._(
2, _omitEnumNames ? '' : 'UNKNOWN_MESSAGE_TYPE');
static const $core.List<EncryptedContent_ErrorMessages_Type> values =
<EncryptedContent_ErrorMessages_Type>[
ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD,
UNKNOWN_MESSAGE_TYPE,
];
static final $core.Map<$core.int, EncryptedContent_ErrorMessages_Type>
_byValue = $pb.ProtobufEnum.initByValue(values);
static EncryptedContent_ErrorMessages_Type? valueOf($core.int value) =>
_byValue[value];
const EncryptedContent_ErrorMessages_Type._(super.value, super.name);
}
class EncryptedContent_MessageUpdate_Type extends $pb.ProtobufEnum { class EncryptedContent_MessageUpdate_Type extends $pb.ProtobufEnum {
static const EncryptedContent_MessageUpdate_Type DELETE = static const EncryptedContent_MessageUpdate_Type DELETE =
EncryptedContent_MessageUpdate_Type._(0, _omitEnumNames ? '' : 'DELETE'); EncryptedContent_MessageUpdate_Type._(0, _omitEnumNames ? '' : 'DELETE');

View file

@ -306,8 +306,19 @@ const EncryptedContent$json = {
'10': 'resendGroupPublicKey', '10': 'resendGroupPublicKey',
'17': true '17': true
}, },
{
'1': 'error_messages',
'3': 18,
'4': 1,
'5': 11,
'6': '.EncryptedContent.ErrorMessages',
'9': 16,
'10': 'errorMessages',
'17': true
},
], ],
'3': [ '3': [
EncryptedContent_ErrorMessages$json,
EncryptedContent_GroupCreate$json, EncryptedContent_GroupCreate$json,
EncryptedContent_GroupJoin$json, EncryptedContent_GroupJoin$json,
EncryptedContent_ResendGroupPublicKey$json, EncryptedContent_ResendGroupPublicKey$json,
@ -339,6 +350,39 @@ const EncryptedContent$json = {
{'1': '_groupJoin'}, {'1': '_groupJoin'},
{'1': '_groupUpdate'}, {'1': '_groupUpdate'},
{'1': '_resendGroupPublicKey'}, {'1': '_resendGroupPublicKey'},
{'1': '_error_messages'},
],
};
@$core.Deprecated('Use encryptedContentDescriptor instead')
const EncryptedContent_ErrorMessages$json = {
'1': 'ErrorMessages',
'2': [
{
'1': 'type',
'3': 1,
'4': 1,
'5': 14,
'6': '.EncryptedContent.ErrorMessages.Type',
'10': 'type'
},
{
'1': 'related_receipt_id',
'3': 2,
'4': 1,
'5': 9,
'10': 'relatedReceiptId'
},
],
'4': [EncryptedContent_ErrorMessages_Type$json],
};
@$core.Deprecated('Use encryptedContentDescriptor instead')
const EncryptedContent_ErrorMessages_Type$json = {
'1': 'Type',
'2': [
{'1': 'ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD', '2': 0},
{'1': 'UNKNOWN_MESSAGE_TYPE', '2': 2},
], ],
}; };
@ -772,57 +816,62 @@ final $typed_data.Uint8List encryptedContentDescriptor = $convert.base64Decode(
'AQESRAoLZ3JvdXBVcGRhdGUYECABKAsyHS5FbmNyeXB0ZWRDb250ZW50Lkdyb3VwVXBkYXRlSA' 'AQESRAoLZ3JvdXBVcGRhdGUYECABKAsyHS5FbmNyeXB0ZWRDb250ZW50Lkdyb3VwVXBkYXRlSA'
'5SC2dyb3VwVXBkYXRliAEBEl8KFHJlc2VuZEdyb3VwUHVibGljS2V5GBEgASgLMiYuRW5jcnlw' '5SC2dyb3VwVXBkYXRliAEBEl8KFHJlc2VuZEdyb3VwUHVibGljS2V5GBEgASgLMiYuRW5jcnlw'
'dGVkQ29udGVudC5SZXNlbmRHcm91cFB1YmxpY0tleUgPUhRyZXNlbmRHcm91cFB1YmxpY0tleY' 'dGVkQ29udGVudC5SZXNlbmRHcm91cFB1YmxpY0tleUgPUhRyZXNlbmRHcm91cFB1YmxpY0tleY'
'gBARpRCgtHcm91cENyZWF0ZRIaCghzdGF0ZUtleRgDIAEoDFIIc3RhdGVLZXkSJgoOZ3JvdXBQ' 'gBARJLCg5lcnJvcl9tZXNzYWdlcxgSIAEoCzIfLkVuY3J5cHRlZENvbnRlbnQuRXJyb3JNZXNz'
'dWJsaWNLZXkYBCABKAxSDmdyb3VwUHVibGljS2V5GjMKCUdyb3VwSm9pbhImCg5ncm91cFB1Ym' 'YWdlc0gQUg1lcnJvck1lc3NhZ2VziAEBGtcBCg1FcnJvck1lc3NhZ2VzEjgKBHR5cGUYASABKA'
'xpY0tleRgBIAEoDFIOZ3JvdXBQdWJsaWNLZXkaFgoUUmVzZW5kR3JvdXBQdWJsaWNLZXkatgIK' '4yJC5FbmNyeXB0ZWRDb250ZW50LkVycm9yTWVzc2FnZXMuVHlwZVIEdHlwZRIsChJyZWxhdGVk'
'C0dyb3VwVXBkYXRlEigKD2dyb3VwQWN0aW9uVHlwZRgBIAEoCVIPZ3JvdXBBY3Rpb25UeXBlEj' 'X3JlY2VpcHRfaWQYAiABKAlSEHJlbGF0ZWRSZWNlaXB0SWQiXgoEVHlwZRI8CjhFUlJPUl9QUk'
'EKEWFmZmVjdGVkQ29udGFjdElkGAIgASgDSABSEWFmZmVjdGVkQ29udGFjdElkiAEBEicKDG5l' '9DRVNTSU5HX01FU1NBR0VfQ1JFQVRFRF9BQ0NPVU5UX1JFUVVFU1RfSU5TVEVBRBAAEhgKFFVO'
'd0dyb3VwTmFtZRgDIAEoCUgBUgxuZXdHcm91cE5hbWWIAQESUwoibmV3RGVsZXRlTWVzc2FnZX' 'S05PV05fTUVTU0FHRV9UWVBFEAIaUQoLR3JvdXBDcmVhdGUSGgoIc3RhdGVLZXkYAyABKAxSCH'
'NBZnRlck1pbGxpc2Vjb25kcxgEIAEoA0gCUiJuZXdEZWxldGVNZXNzYWdlc0FmdGVyTWlsbGlz' 'N0YXRlS2V5EiYKDmdyb3VwUHVibGljS2V5GAQgASgMUg5ncm91cFB1YmxpY0tleRozCglHcm91'
'ZWNvbmRziAEBQhQKEl9hZmZlY3RlZENvbnRhY3RJZEIPCg1fbmV3R3JvdXBOYW1lQiUKI19uZX' 'cEpvaW4SJgoOZ3JvdXBQdWJsaWNLZXkYASABKAxSDmdyb3VwUHVibGljS2V5GhYKFFJlc2VuZE'
'dEZWxldGVNZXNzYWdlc0FmdGVyTWlsbGlzZWNvbmRzGqkBCgtUZXh0TWVzc2FnZRIoCg9zZW5k' 'dyb3VwUHVibGljS2V5GrYCCgtHcm91cFVwZGF0ZRIoCg9ncm91cEFjdGlvblR5cGUYASABKAlS'
'ZXJNZXNzYWdlSWQYASABKAlSD3NlbmRlck1lc3NhZ2VJZBISCgR0ZXh0GAIgASgJUgR0ZXh0Eh' 'D2dyb3VwQWN0aW9uVHlwZRIxChFhZmZlY3RlZENvbnRhY3RJZBgCIAEoA0gAUhFhZmZlY3RlZE'
'wKCXRpbWVzdGFtcBgDIAEoA1IJdGltZXN0YW1wEisKDnF1b3RlTWVzc2FnZUlkGAQgASgJSABS' 'NvbnRhY3RJZIgBARInCgxuZXdHcm91cE5hbWUYAyABKAlIAVIMbmV3R3JvdXBOYW1liAEBElMK'
'DnF1b3RlTWVzc2FnZUlkiAEBQhEKD19xdW90ZU1lc3NhZ2VJZBpiCghSZWFjdGlvbhIoCg90YX' 'Im5ld0RlbGV0ZU1lc3NhZ2VzQWZ0ZXJNaWxsaXNlY29uZHMYBCABKANIAlIibmV3RGVsZXRlTW'
'JnZXRNZXNzYWdlSWQYASABKAlSD3RhcmdldE1lc3NhZ2VJZBIUCgVlbW9qaRgCIAEoCVIFZW1v' 'Vzc2FnZXNBZnRlck1pbGxpc2Vjb25kc4gBAUIUChJfYWZmZWN0ZWRDb250YWN0SWRCDwoNX25l'
'amkSFgoGcmVtb3ZlGAMgASgIUgZyZW1vdmUatwIKDU1lc3NhZ2VVcGRhdGUSOAoEdHlwZRgBIA' 'd0dyb3VwTmFtZUIlCiNfbmV3RGVsZXRlTWVzc2FnZXNBZnRlck1pbGxpc2Vjb25kcxqpAQoLVG'
'EoDjIkLkVuY3J5cHRlZENvbnRlbnQuTWVzc2FnZVVwZGF0ZS5UeXBlUgR0eXBlEi0KD3NlbmRl' 'V4dE1lc3NhZ2USKAoPc2VuZGVyTWVzc2FnZUlkGAEgASgJUg9zZW5kZXJNZXNzYWdlSWQSEgoE'
'ck1lc3NhZ2VJZBgCIAEoCUgAUg9zZW5kZXJNZXNzYWdlSWSIAQESOgoYbXVsdGlwbGVUYXJnZX' 'dGV4dBgCIAEoCVIEdGV4dBIcCgl0aW1lc3RhbXAYAyABKANSCXRpbWVzdGFtcBIrCg5xdW90ZU'
'RNZXNzYWdlSWRzGAMgAygJUhhtdWx0aXBsZVRhcmdldE1lc3NhZ2VJZHMSFwoEdGV4dBgEIAEo' '1lc3NhZ2VJZBgEIAEoCUgAUg5xdW90ZU1lc3NhZ2VJZIgBAUIRCg9fcXVvdGVNZXNzYWdlSWQa'
'CUgBUgR0ZXh0iAEBEhwKCXRpbWVzdGFtcBgFIAEoA1IJdGltZXN0YW1wIi0KBFR5cGUSCgoGRE' 'YgoIUmVhY3Rpb24SKAoPdGFyZ2V0TWVzc2FnZUlkGAEgASgJUg90YXJnZXRNZXNzYWdlSWQSFA'
'VMRVRFEAASDQoJRURJVF9URVhUEAESCgoGT1BFTkVEEAJCEgoQX3NlbmRlck1lc3NhZ2VJZEIH' 'oFZW1vamkYAiABKAlSBWVtb2ppEhYKBnJlbW92ZRgDIAEoCFIGcmVtb3ZlGrcCCg1NZXNzYWdl'
'CgVfdGV4dBqXBQoFTWVkaWESKAoPc2VuZGVyTWVzc2FnZUlkGAEgASgJUg9zZW5kZXJNZXNzYW' 'VXBkYXRlEjgKBHR5cGUYASABKA4yJC5FbmNyeXB0ZWRDb250ZW50Lk1lc3NhZ2VVcGRhdGUuVH'
'dlSWQSMAoEdHlwZRgCIAEoDjIcLkVuY3J5cHRlZENvbnRlbnQuTWVkaWEuVHlwZVIEdHlwZRJD' 'lwZVIEdHlwZRItCg9zZW5kZXJNZXNzYWdlSWQYAiABKAlIAFIPc2VuZGVyTWVzc2FnZUlkiAEB'
'ChpkaXNwbGF5TGltaXRJbk1pbGxpc2Vjb25kcxgDIAEoA0gAUhpkaXNwbGF5TGltaXRJbk1pbG' 'EjoKGG11bHRpcGxlVGFyZ2V0TWVzc2FnZUlkcxgDIAMoCVIYbXVsdGlwbGVUYXJnZXRNZXNzYW'
'xpc2Vjb25kc4gBARI2ChZyZXF1aXJlc0F1dGhlbnRpY2F0aW9uGAQgASgIUhZyZXF1aXJlc0F1' 'dlSWRzEhcKBHRleHQYBCABKAlIAVIEdGV4dIgBARIcCgl0aW1lc3RhbXAYBSABKANSCXRpbWVz'
'dGhlbnRpY2F0aW9uEhwKCXRpbWVzdGFtcBgFIAEoA1IJdGltZXN0YW1wEisKDnF1b3RlTWVzc2' 'dGFtcCItCgRUeXBlEgoKBkRFTEVURRAAEg0KCUVESVRfVEVYVBABEgoKBk9QRU5FRBACQhIKEF'
'FnZUlkGAYgASgJSAFSDnF1b3RlTWVzc2FnZUlkiAEBEikKDWRvd25sb2FkVG9rZW4YByABKAxI' '9zZW5kZXJNZXNzYWdlSWRCBwoFX3RleHQalwUKBU1lZGlhEigKD3NlbmRlck1lc3NhZ2VJZBgB'
'AlINZG93bmxvYWRUb2tlbogBARIpCg1lbmNyeXB0aW9uS2V5GAggASgMSANSDWVuY3J5cHRpb2' 'IAEoCVIPc2VuZGVyTWVzc2FnZUlkEjAKBHR5cGUYAiABKA4yHC5FbmNyeXB0ZWRDb250ZW50Lk'
'5LZXmIAQESKQoNZW5jcnlwdGlvbk1hYxgJIAEoDEgEUg1lbmNyeXB0aW9uTWFjiAEBEi0KD2Vu' '1lZGlhLlR5cGVSBHR5cGUSQwoaZGlzcGxheUxpbWl0SW5NaWxsaXNlY29uZHMYAyABKANIAFIa'
'Y3J5cHRpb25Ob25jZRgKIAEoDEgFUg9lbmNyeXB0aW9uTm9uY2WIAQEiPgoEVHlwZRIMCghSRV' 'ZGlzcGxheUxpbWl0SW5NaWxsaXNlY29uZHOIAQESNgoWcmVxdWlyZXNBdXRoZW50aWNhdGlvbh'
'VQTE9BRBAAEgkKBUlNQUdFEAESCQoFVklERU8QAhIHCgNHSUYQAxIJCgVBVURJTxAEQh0KG19k' 'gEIAEoCFIWcmVxdWlyZXNBdXRoZW50aWNhdGlvbhIcCgl0aW1lc3RhbXAYBSABKANSCXRpbWVz'
'aXNwbGF5TGltaXRJbk1pbGxpc2Vjb25kc0IRCg9fcXVvdGVNZXNzYWdlSWRCEAoOX2Rvd25sb2' 'dGFtcBIrCg5xdW90ZU1lc3NhZ2VJZBgGIAEoCUgBUg5xdW90ZU1lc3NhZ2VJZIgBARIpCg1kb3'
'FkVG9rZW5CEAoOX2VuY3J5cHRpb25LZXlCEAoOX2VuY3J5cHRpb25NYWNCEgoQX2VuY3J5cHRp' 'dubG9hZFRva2VuGAcgASgMSAJSDWRvd25sb2FkVG9rZW6IAQESKQoNZW5jcnlwdGlvbktleRgI'
'b25Ob25jZRqnAQoLTWVkaWFVcGRhdGUSNgoEdHlwZRgBIAEoDjIiLkVuY3J5cHRlZENvbnRlbn' 'IAEoDEgDUg1lbmNyeXB0aW9uS2V5iAEBEikKDWVuY3J5cHRpb25NYWMYCSABKAxIBFINZW5jcn'
'QuTWVkaWFVcGRhdGUuVHlwZVIEdHlwZRIoCg90YXJnZXRNZXNzYWdlSWQYAiABKAlSD3Rhcmdl' 'lwdGlvbk1hY4gBARItCg9lbmNyeXB0aW9uTm9uY2UYCiABKAxIBVIPZW5jcnlwdGlvbk5vbmNl'
'dE1lc3NhZ2VJZCI2CgRUeXBlEgwKCFJFT1BFTkVEEAASCgoGU1RPUkVEEAESFAoQREVDUllQVE' 'iAEBIj4KBFR5cGUSDAoIUkVVUExPQUQQABIJCgVJTUFHRRABEgkKBVZJREVPEAISBwoDR0lGEA'
'lPTl9FUlJPUhACGngKDkNvbnRhY3RSZXF1ZXN0EjkKBHR5cGUYASABKA4yJS5FbmNyeXB0ZWRD' 'MSCQoFQVVESU8QBEIdChtfZGlzcGxheUxpbWl0SW5NaWxsaXNlY29uZHNCEQoPX3F1b3RlTWVz'
'b250ZW50LkNvbnRhY3RSZXF1ZXN0LlR5cGVSBHR5cGUiKwoEVHlwZRILCgdSRVFVRVNUEAASCg' 'c2FnZUlkQhAKDl9kb3dubG9hZFRva2VuQhAKDl9lbmNyeXB0aW9uS2V5QhAKDl9lbmNyeXB0aW'
'oGUkVKRUNUEAESCgoGQUNDRVBUEAIangIKDUNvbnRhY3RVcGRhdGUSOAoEdHlwZRgBIAEoDjIk' '9uTWFjQhIKEF9lbmNyeXB0aW9uTm9uY2UapwEKC01lZGlhVXBkYXRlEjYKBHR5cGUYASABKA4y'
'LkVuY3J5cHRlZENvbnRlbnQuQ29udGFjdFVwZGF0ZS5UeXBlUgR0eXBlEjUKE2F2YXRhclN2Z0' 'Ii5FbmNyeXB0ZWRDb250ZW50Lk1lZGlhVXBkYXRlLlR5cGVSBHR5cGUSKAoPdGFyZ2V0TWVzc2'
'NvbXByZXNzZWQYAiABKAxIAFITYXZhdGFyU3ZnQ29tcHJlc3NlZIgBARIfCgh1c2VybmFtZRgD' 'FnZUlkGAIgASgJUg90YXJnZXRNZXNzYWdlSWQiNgoEVHlwZRIMCghSRU9QRU5FRBAAEgoKBlNU'
'IAEoCUgBUgh1c2VybmFtZYgBARIlCgtkaXNwbGF5TmFtZRgEIAEoCUgCUgtkaXNwbGF5TmFtZY' 'T1JFRBABEhQKEERFQ1JZUFRJT05fRVJST1IQAhp4Cg5Db250YWN0UmVxdWVzdBI5CgR0eXBlGA'
'gBASIfCgRUeXBlEgsKB1JFUVVFU1QQABIKCgZVUERBVEUQAUIWChRfYXZhdGFyU3ZnQ29tcHJl' 'EgASgOMiUuRW5jcnlwdGVkQ29udGVudC5Db250YWN0UmVxdWVzdC5UeXBlUgR0eXBlIisKBFR5'
'c3NlZEILCglfdXNlcm5hbWVCDgoMX2Rpc3BsYXlOYW1lGtUBCghQdXNoS2V5cxIzCgR0eXBlGA' 'cGUSCwoHUkVRVUVTVBAAEgoKBlJFSkVDVBABEgoKBkFDQ0VQVBACGp4CCg1Db250YWN0VXBkYX'
'EgASgOMh8uRW5jcnlwdGVkQ29udGVudC5QdXNoS2V5cy5UeXBlUgR0eXBlEhkKBWtleUlkGAIg' 'RlEjgKBHR5cGUYASABKA4yJC5FbmNyeXB0ZWRDb250ZW50LkNvbnRhY3RVcGRhdGUuVHlwZVIE'
'ASgDSABSBWtleUlkiAEBEhUKA2tleRgDIAEoDEgBUgNrZXmIAQESIQoJY3JlYXRlZEF0GAQgAS' 'dHlwZRI1ChNhdmF0YXJTdmdDb21wcmVzc2VkGAIgASgMSABSE2F2YXRhclN2Z0NvbXByZXNzZW'
'gDSAJSCWNyZWF0ZWRBdIgBASIfCgRUeXBlEgsKB1JFUVVFU1QQABIKCgZVUERBVEUQAUIICgZf' 'SIAQESHwoIdXNlcm5hbWUYAyABKAlIAVIIdXNlcm5hbWWIAQESJQoLZGlzcGxheU5hbWUYBCAB'
'a2V5SWRCBgoEX2tleUIMCgpfY3JlYXRlZEF0GqkBCglGbGFtZVN5bmMSIgoMZmxhbWVDb3VudG' 'KAlIAlILZGlzcGxheU5hbWWIAQEiHwoEVHlwZRILCgdSRVFVRVNUEAASCgoGVVBEQVRFEAFCFg'
'VyGAEgASgDUgxmbGFtZUNvdW50ZXISNgoWbGFzdEZsYW1lQ291bnRlckNoYW5nZRgCIAEoA1IW' 'oUX2F2YXRhclN2Z0NvbXByZXNzZWRCCwoJX3VzZXJuYW1lQg4KDF9kaXNwbGF5TmFtZRrVAQoI'
'bGFzdEZsYW1lQ291bnRlckNoYW5nZRIeCgpiZXN0RnJpZW5kGAMgASgIUgpiZXN0RnJpZW5kEi' 'UHVzaEtleXMSMwoEdHlwZRgBIAEoDjIfLkVuY3J5cHRlZENvbnRlbnQuUHVzaEtleXMuVHlwZV'
'AKC2ZvcmNlVXBkYXRlGAQgASgIUgtmb3JjZVVwZGF0ZUIKCghfZ3JvdXBJZEIPCg1faXNEaXJl' 'IEdHlwZRIZCgVrZXlJZBgCIAEoA0gAUgVrZXlJZIgBARIVCgNrZXkYAyABKAxIAVIDa2V5iAEB'
'Y3RDaGF0QhcKFV9zZW5kZXJQcm9maWxlQ291bnRlckIQCg5fbWVzc2FnZVVwZGF0ZUIICgZfbW' 'EiEKCWNyZWF0ZWRBdBgEIAEoA0gCUgljcmVhdGVkQXSIAQEiHwoEVHlwZRILCgdSRVFVRVNUEA'
'VkaWFCDgoMX21lZGlhVXBkYXRlQhAKDl9jb250YWN0VXBkYXRlQhEKD19jb250YWN0UmVxdWVz' 'ASCgoGVVBEQVRFEAFCCAoGX2tleUlkQgYKBF9rZXlCDAoKX2NyZWF0ZWRBdBqpAQoJRmxhbWVT'
'dEIMCgpfZmxhbWVTeW5jQgsKCV9wdXNoS2V5c0ILCglfcmVhY3Rpb25CDgoMX3RleHRNZXNzYW' 'eW5jEiIKDGZsYW1lQ291bnRlchgBIAEoA1IMZmxhbWVDb3VudGVyEjYKFmxhc3RGbGFtZUNvdW'
'dlQg4KDF9ncm91cENyZWF0ZUIMCgpfZ3JvdXBKb2luQg4KDF9ncm91cFVwZGF0ZUIXChVfcmVz' '50ZXJDaGFuZ2UYAiABKANSFmxhc3RGbGFtZUNvdW50ZXJDaGFuZ2USHgoKYmVzdEZyaWVuZBgD'
'ZW5kR3JvdXBQdWJsaWNLZXk='); 'IAEoCFIKYmVzdEZyaWVuZBIgCgtmb3JjZVVwZGF0ZRgEIAEoCFILZm9yY2VVcGRhdGVCCgoIX2'
'dyb3VwSWRCDwoNX2lzRGlyZWN0Q2hhdEIXChVfc2VuZGVyUHJvZmlsZUNvdW50ZXJCEAoOX21l'
'c3NhZ2VVcGRhdGVCCAoGX21lZGlhQg4KDF9tZWRpYVVwZGF0ZUIQCg5fY29udGFjdFVwZGF0ZU'
'IRCg9fY29udGFjdFJlcXVlc3RCDAoKX2ZsYW1lU3luY0ILCglfcHVzaEtleXNCCwoJX3JlYWN0'
'aW9uQg4KDF90ZXh0TWVzc2FnZUIOCgxfZ3JvdXBDcmVhdGVCDAoKX2dyb3VwSm9pbkIOCgxfZ3'
'JvdXBVcGRhdGVCFwoVX3Jlc2VuZEdyb3VwUHVibGljS2V5QhEKD19lcnJvcl9tZXNzYWdlcw==');

View file

@ -51,6 +51,17 @@ message EncryptedContent {
optional GroupJoin groupJoin = 15; optional GroupJoin groupJoin = 15;
optional GroupUpdate groupUpdate = 16; optional GroupUpdate groupUpdate = 16;
optional ResendGroupPublicKey resendGroupPublicKey = 17; optional ResendGroupPublicKey resendGroupPublicKey = 17;
optional ErrorMessages error_messages = 18;
message ErrorMessages {
enum Type {
ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD = 0;
UNKNOWN_MESSAGE_TYPE = 2;
}
Type type = 1;
string related_receipt_id = 2;
}
message GroupCreate { message GroupCreate {

View file

@ -13,6 +13,43 @@ import 'package:twonly/src/utils/avatars.dart';
import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
Future<bool> handleNewContactRequest(int fromUserId) async {
final contact = await twonlyDB.contactsDao
.getContactByUserId(fromUserId)
.getSingleOrNull();
if (contact != null) {
if (contact.accepted) {
// contact was already accepted, so just accept the request in the background.
await sendCipherText(
contact.userId,
EncryptedContent(
contactRequest: EncryptedContent_ContactRequest(
type: EncryptedContent_ContactRequest_Type.ACCEPT,
),
),
);
return true;
}
}
// Request the username by the server so an attacker can not
// forge the displayed username in the contact request
final user = await apiService.getUserById(fromUserId);
if (user == null) {
return false;
}
await twonlyDB.contactsDao.insertOnConflictUpdate(
ContactsCompanion(
username: Value(utf8.decode(user.username)),
userId: Value(fromUserId),
requested: const Value(true),
deletedByUser: const Value(false),
),
);
await setupNotificationWithUsers();
return true;
}
Future<bool> handleContactRequest( Future<bool> handleContactRequest(
int fromUserId, int fromUserId,
EncryptedContent_ContactRequest contactRequest, EncryptedContent_ContactRequest contactRequest,
@ -20,38 +57,7 @@ Future<bool> handleContactRequest(
switch (contactRequest.type) { switch (contactRequest.type) {
case EncryptedContent_ContactRequest_Type.REQUEST: case EncryptedContent_ContactRequest_Type.REQUEST:
Log.info('Got a contact request from $fromUserId'); Log.info('Got a contact request from $fromUserId');
final contact = await twonlyDB.contactsDao return handleNewContactRequest(fromUserId);
.getContactByUserId(fromUserId)
.getSingleOrNull();
if (contact != null) {
if (contact.accepted) {
// contact was already accepted, so just accept the request in the background.
await sendCipherText(
contact.userId,
EncryptedContent(
contactRequest: EncryptedContent_ContactRequest(
type: EncryptedContent_ContactRequest_Type.ACCEPT,
),
),
);
return true;
}
}
// Request the username by the server so an attacker can not
// forge the displayed username in the contact request
final user = await apiService.getUserById(fromUserId);
if (user == null) {
return false;
}
await twonlyDB.contactsDao.insertOnConflictUpdate(
ContactsCompanion(
username: Value(utf8.decode(user.username)),
userId: Value(fromUserId),
requested: const Value(true),
deletedByUser: const Value(false),
),
);
await setupNotificationWithUsers();
case EncryptedContent_ContactRequest_Type.ACCEPT: case EncryptedContent_ContactRequest_Type.ACCEPT:
Log.info('Got a contact accept from $fromUserId'); Log.info('Got a contact accept from $fromUserId');
await twonlyDB.contactsDao.updateContact( await twonlyDB.contactsDao.updateContact(

View file

@ -0,0 +1,29 @@
import 'package:clock/clock.dart';
import 'package:drift/drift.dart' show Value;
import 'package:twonly/globals.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/model/protobuf/client/generated/messages.pbserver.dart';
Future<void> handleErrorMessage(
int fromUserId,
EncryptedContent_ErrorMessages error,
) async {
switch (error.type) {
case EncryptedContent_ErrorMessages_Type.UNKNOWN_MESSAGE_TYPE:
break;
case EncryptedContent_ErrorMessages_Type
.ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD:
await twonlyDB.receiptsDao.updateReceiptWidthUserId(
fromUserId,
error.relatedReceiptId,
ReceiptsCompanion(markForRetryAfterAccepted: Value(clock.now())),
);
await twonlyDB.contactsDao.updateContact(
fromUserId,
const ContactsCompanion(
accepted: Value(false),
requested: Value(true),
),
);
}
}

View file

@ -28,7 +28,29 @@ Future<void> tryTransmitMessages() async {
Log.info('Reuploading ${receipts.length} messages to the server.'); Log.info('Reuploading ${receipts.length} messages to the server.');
final contacts = <int, Contact>{};
for (final receipt in receipts) { for (final receipt in receipts) {
if (receipt.markForRetryAfterAccepted != null) {
if (!contacts.containsKey(receipt.contactId)) {
final contact = await twonlyDB.contactsDao
.getContactByUserId(receipt.contactId)
.getSingleOrNull();
if (contact == null) {
Log.error(
'Contact does not exists, but has a record in receipts, this should not be possible, because of the DELETE CASCADE relation.',
);
continue;
}
contacts[receipt.contactId] = contact;
}
if (!(contacts[receipt.contactId]?.accepted ?? true)) {
Log.warn(
'Could not send message as contact has still not yet accepted.',
);
continue;
}
}
await tryToSendCompleteMessage(receipt: receipt); await tryToSendCompleteMessage(receipt: receipt);
} }
}); });

View file

@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'package:clock/clock.dart'; import 'package:clock/clock.dart';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:hashlib/random.dart'; import 'package:hashlib/random.dart';
@ -15,6 +14,7 @@ import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart
import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pbserver.dart'; import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pbserver.dart';
import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart'; import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart';
import 'package:twonly/src/services/api/client2client/contact.c2c.dart'; import 'package:twonly/src/services/api/client2client/contact.c2c.dart';
import 'package:twonly/src/services/api/client2client/errors.c2c.dart';
import 'package:twonly/src/services/api/client2client/groups.c2c.dart'; import 'package:twonly/src/services/api/client2client/groups.c2c.dart';
import 'package:twonly/src/services/api/client2client/media.c2c.dart'; import 'package:twonly/src/services/api/client2client/media.c2c.dart';
import 'package:twonly/src/services/api/client2client/messages.c2c.dart'; import 'package:twonly/src/services/api/client2client/messages.c2c.dart';
@ -23,6 +23,7 @@ import 'package:twonly/src/services/api/client2client/pushkeys.c2c.dart';
import 'package:twonly/src/services/api/client2client/reaction.c2c.dart'; import 'package:twonly/src/services/api/client2client/reaction.c2c.dart';
import 'package:twonly/src/services/api/client2client/text_message.c2c.dart'; import 'package:twonly/src/services/api/client2client/text_message.c2c.dart';
import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/services/api/messages.dart';
import 'package:twonly/src/services/group.services.dart';
import 'package:twonly/src/services/signal/encryption.signal.dart'; import 'package:twonly/src/services/signal/encryption.signal.dart';
import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
@ -117,47 +118,60 @@ Future<void> handleClient2ClientMessage(NewMessage newMessage) async {
case Message_Type.CIPHERTEXT: case Message_Type.CIPHERTEXT:
case Message_Type.PREKEY_BUNDLE: case Message_Type.PREKEY_BUNDLE:
if (message.hasEncryptedContent()) { if (message.hasEncryptedContent()) {
Value<String>? receiptIdDB;
final encryptedContentRaw = final encryptedContentRaw =
Uint8List.fromList(message.encryptedContent); Uint8List.fromList(message.encryptedContent);
if (await twonlyDB.contactsDao Message? response;
.getContactByUserId(fromUserId)
.getSingleOrNull() ==
null) {
final user = await apiService.getUserById(fromUserId);
/// In case the user does not exists, just create a dummy user which was deleted by the user, so the message final user = await twonlyDB.contactsDao
/// can be inserted into the receipts database .getContactByUserId(fromUserId)
await twonlyDB.contactsDao.insertContact( .getSingleOrNull();
ContactsCompanion(
userId: Value(fromUserId), if (user == null) {
deletedByUser: const Value(true), if (!await addNewHiddenContact(fromUserId)) {
username: Value( // in case the user could not be added, send a retry error message as this error should only happen in case
user == null ? '[Unknown]' : utf8.decode(user.username), // it was not possible to load the user from the server
response = Message(
receiptId: receiptId,
type: Message_Type.PLAINTEXT_CONTENT,
plaintextContent: PlaintextContent(
retryControlError: PlaintextContent_RetryErrorMessage(),
), ),
), );
); }
} }
final responsePlaintextContent = await handleEncryptedMessage( if (response == null) {
fromUserId, final (encryptedContent, plainTextContent) =
encryptedContentRaw, await handleEncryptedMessage(
message.type, fromUserId,
); encryptedContentRaw,
Message response; message.type,
if (responsePlaintextContent != null) { receiptId,
response = Message() );
..receiptId = receiptId if (plainTextContent != null) {
..type = Message_Type.PLAINTEXT_CONTENT response = Message(
..plaintextContent = responsePlaintextContent; receiptId: receiptId,
} else { type: Message_Type.PLAINTEXT_CONTENT,
response = Message()..type = Message_Type.SENDER_DELIVERY_RECEIPT; plaintextContent: plainTextContent,
);
} else if (encryptedContent != null) {
response = Message(
type: Message_Type.CIPHERTEXT,
encryptedContent: encryptedContent.writeToBuffer(),
);
receiptIdDB = const Value.absent();
}
} }
response ??= Message(type: Message_Type.SENDER_DELIVERY_RECEIPT);
try { try {
await twonlyDB.receiptsDao.insertReceipt( await twonlyDB.receiptsDao.insertReceipt(
ReceiptsCompanion( ReceiptsCompanion(
receiptId: Value(receiptId), receiptId: receiptIdDB ?? Value(receiptId),
contactId: Value(fromUserId), contactId: Value(fromUserId),
message: Value(response.writeToBuffer()), message: Value(response.writeToBuffer()),
contactWillSendsReceipt: const Value(false), contactWillSendsReceipt: const Value(false),
@ -173,10 +187,11 @@ Future<void> handleClient2ClientMessage(NewMessage newMessage) async {
} }
} }
Future<PlaintextContent?> handleEncryptedMessage( Future<(EncryptedContent?, PlaintextContent?)> handleEncryptedMessage(
int fromUserId, int fromUserId,
Uint8List encryptedContentRaw, Uint8List encryptedContentRaw,
Message_Type messageType, Message_Type messageType,
String receiptId,
) async { ) async {
final (content, decryptionErrorType) = await signalDecryptMessage( final (content, decryptionErrorType) = await signalDecryptMessage(
fromUserId, fromUserId,
@ -185,9 +200,12 @@ Future<PlaintextContent?> handleEncryptedMessage(
); );
if (content == null) { if (content == null) {
return PlaintextContent() return (
..decryptionErrorMessage = (PlaintextContent_DecryptionErrorMessage() null,
..type = decryptionErrorType!); PlaintextContent()
..decryptionErrorMessage = (PlaintextContent_DecryptionErrorMessage()
..type = decryptionErrorType!)
);
} }
// We got a valid message fromUserId, so mark all messages which where // We got a valid message fromUserId, so mark all messages which where
@ -203,10 +221,21 @@ Future<PlaintextContent?> handleEncryptedMessage(
if (content.hasContactRequest()) { if (content.hasContactRequest()) {
if (!await handleContactRequest(fromUserId, content.contactRequest)) { if (!await handleContactRequest(fromUserId, content.contactRequest)) {
return PlaintextContent() return (
..retryControlError = PlaintextContent_RetryErrorMessage(); null,
PlaintextContent()
..retryControlError = PlaintextContent_RetryErrorMessage()
);
} }
return null; return (null, null);
}
if (content.hasErrorMessages()) {
await handleErrorMessage(
fromUserId,
content.errorMessages,
);
return (null, null);
} }
if (content.hasContactUpdate()) { if (content.hasContactUpdate()) {
@ -215,17 +244,17 @@ Future<PlaintextContent?> handleEncryptedMessage(
content.contactUpdate, content.contactUpdate,
senderProfileCounter, senderProfileCounter,
); );
return null; return (null, null);
} }
if (content.hasFlameSync()) { if (content.hasFlameSync()) {
await handleFlameSync(fromUserId, content.flameSync); await handleFlameSync(fromUserId, content.flameSync);
return null; return (null, null);
} }
if (content.hasPushKeys()) { if (content.hasPushKeys()) {
await handlePushKey(fromUserId, content.pushKeys); await handlePushKey(fromUserId, content.pushKeys);
return null; return (null, null);
} }
if (content.hasMessageUpdate()) { if (content.hasMessageUpdate()) {
@ -233,7 +262,7 @@ Future<PlaintextContent?> handleEncryptedMessage(
fromUserId, fromUserId,
content.messageUpdate, content.messageUpdate,
); );
return null; return (null, null);
} }
if (content.hasMediaUpdate()) { if (content.hasMediaUpdate()) {
@ -241,12 +270,12 @@ Future<PlaintextContent?> handleEncryptedMessage(
fromUserId, fromUserId,
content.mediaUpdate, content.mediaUpdate,
); );
return null; return (null, null);
} }
if (!content.hasGroupId()) { if (!content.hasGroupId()) {
Log.error('Messages should have a groupId $fromUserId.'); Log.error('Messages should have a groupId $fromUserId.');
return null; return (null, null);
} }
if (content.hasGroupCreate()) { if (content.hasGroupCreate()) {
@ -255,7 +284,7 @@ Future<PlaintextContent?> handleEncryptedMessage(
content.groupId, content.groupId,
content.groupCreate, content.groupCreate,
); );
return null; return (null, null);
} }
/// Verify that the user is (still) in that group... /// Verify that the user is (still) in that group...
@ -265,10 +294,20 @@ Future<PlaintextContent?> handleEncryptedMessage(
.getContactByUserId(fromUserId) .getContactByUserId(fromUserId)
.getSingleOrNull(); .getSingleOrNull();
if (contact == null || contact.deletedByUser) { if (contact == null || contact.deletedByUser) {
await handleNewContactRequest(fromUserId);
Log.error( Log.error(
'User tries to send message to direct chat while the user does not exists !', 'User tries to send message to direct chat while the user does not exists !',
); );
return null; return (
EncryptedContent(
errorMessages: EncryptedContent_ErrorMessages(
type: EncryptedContent_ErrorMessages_Type
.ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD,
relatedReceiptId: receiptId,
),
),
null
);
} }
Log.info( Log.info(
'Creating new DirectChat between two users', 'Creating new DirectChat between two users',
@ -285,12 +324,15 @@ Future<PlaintextContent?> handleEncryptedMessage(
'Got group join message, but group does not exists yet, retry later. As probably the GroupCreate was not yet received.', 'Got group join message, but group does not exists yet, retry later. As probably the GroupCreate was not yet received.',
); );
// In case the group join was received before the GroupCreate the sender should send it later again. // In case the group join was received before the GroupCreate the sender should send it later again.
return PlaintextContent() return (
..retryControlError = PlaintextContent_RetryErrorMessage(); null,
PlaintextContent()
..retryControlError = PlaintextContent_RetryErrorMessage()
);
} }
Log.error('User $fromUserId tried to access group ${content.groupId}.'); Log.error('User $fromUserId tried to access group ${content.groupId}.');
return null; return (null, null);
} }
} }
@ -300,7 +342,7 @@ Future<PlaintextContent?> handleEncryptedMessage(
content.groupId, content.groupId,
content.groupUpdate, content.groupUpdate,
); );
return null; return (null, null);
} }
if (content.hasGroupJoin()) { if (content.hasGroupJoin()) {
@ -309,10 +351,13 @@ Future<PlaintextContent?> handleEncryptedMessage(
content.groupId, content.groupId,
content.groupJoin, content.groupJoin,
)) { )) {
return PlaintextContent() return (
..retryControlError = PlaintextContent_RetryErrorMessage(); null,
PlaintextContent()
..retryControlError = PlaintextContent_RetryErrorMessage()
);
} }
return null; return (null, null);
} }
if (content.hasResendGroupPublicKey()) { if (content.hasResendGroupPublicKey()) {
@ -321,7 +366,7 @@ Future<PlaintextContent?> handleEncryptedMessage(
content.groupId, content.groupId,
content.groupJoin, content.groupJoin,
); );
return null; return (null, null);
} }
if (content.hasTextMessage()) { if (content.hasTextMessage()) {
@ -330,7 +375,7 @@ Future<PlaintextContent?> handleEncryptedMessage(
content.groupId, content.groupId,
content.textMessage, content.textMessage,
); );
return null; return (null, null);
} }
if (content.hasReaction()) { if (content.hasReaction()) {
@ -339,7 +384,7 @@ Future<PlaintextContent?> handleEncryptedMessage(
content.groupId, content.groupId,
content.reaction, content.reaction,
); );
return null; return (null, null);
} }
if (content.hasMedia()) { if (content.hasMedia()) {
@ -348,8 +393,8 @@ Future<PlaintextContent?> handleEncryptedMessage(
content.groupId, content.groupId,
content.media, content.media,
); );
return null; return (null, null);
} }
return null; return (null, null);
} }

View file

@ -83,13 +83,16 @@ class GroupContextMenu extends StatelessWidget {
); );
if (ok) { if (ok) {
await twonlyDB.messagesDao.deleteMessagesByGroupId(group.groupId); await twonlyDB.messagesDao.deleteMessagesByGroupId(group.groupId);
// await twonlyDB.groupsDao.deleteGroup(group.groupId); if (group.isDirectChat) {
await twonlyDB.groupsDao.updateGroup( await twonlyDB.groupsDao.deleteGroup(group.groupId);
group.groupId, } else {
const GroupsCompanion( await twonlyDB.groupsDao.updateGroup(
deletedContent: Value(true), group.groupId,
), const GroupsCompanion(
); deletedContent: Value(true),
),
);
}
} }
}, },
), ),

View file

@ -26,7 +26,48 @@ class ContactView extends StatefulWidget {
} }
class _ContactViewState extends State<ContactView> { class _ContactViewState extends State<ContactView> {
Contact? _contact;
bool _contactIsStillAGroupMember = true;
late StreamSubscription<Contact?> _contactSub;
late StreamSubscription<List<GroupMember>> _groupMemberSub;
@override
void initState() {
_contactSub =
twonlyDB.contactsDao.watchContact(widget.userId).listen((update) {
setState(() {
_contact = update;
});
});
_groupMemberSub = twonlyDB.groupsDao
.watchContactGroupMember(widget.userId)
.listen((update) {
setState(() {
_contactIsStillAGroupMember = update.isNotEmpty;
});
});
super.initState();
}
@override
void dispose() {
_contactSub.cancel();
_groupMemberSub.cancel();
super.dispose();
}
Future<void> handleUserRemoveRequest(Contact contact) async { Future<void> handleUserRemoveRequest(Contact contact) async {
if (_contactIsStillAGroupMember) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.lang.deleteUserErrorMessage),
duration: const Duration(seconds: 8),
),
);
return;
}
final remove = await showAlertDialog( final remove = await showAlertDialog(
context, context,
context.lang context.lang
@ -84,128 +125,117 @@ class _ContactViewState extends State<ContactView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final contact = twonlyDB.contactsDao if (_contact == null) return Container();
.getContactByUserId(widget.userId) final contact = _contact!;
.watchSingleOrNull();
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text(''), title: const Text(''),
), ),
body: StreamBuilder( body: ListView(
stream: contact, key: ValueKey(contact.userId),
builder: (context, snapshot) { children: [
if (!snapshot.hasData || snapshot.data == null) { Padding(
return Container(); padding: const EdgeInsets.all(10),
} child: AvatarIcon(contactId: contact.userId, fontSize: 30),
final contact = snapshot.data!; ),
return ListView( Row(
key: ValueKey(contact.userId), mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.only(right: 10),
child: AvatarIcon(contactId: contact.userId, fontSize: 30), child: VerifiedShield(
key: GlobalKey(),
contact: contact,
),
), ),
Row( Text(
mainAxisAlignment: MainAxisAlignment.center, getContactDisplayName(contact, maxLength: 20),
children: [ style: const TextStyle(fontSize: 20),
Padding(
padding: const EdgeInsets.only(right: 10),
child: VerifiedShield(
key: GlobalKey(),
contact: contact,
),
),
Text(
getContactDisplayName(contact, maxLength: 20),
style: const TextStyle(fontSize: 20),
),
FlameCounterWidget(
contactId: contact.userId,
prefix: true,
),
],
), ),
if (getContactDisplayName(contact) != contact.username) FlameCounterWidget(
Center(child: Text('(${contact.username})')), contactId: contact.userId,
const SizedBox(height: 50), prefix: true,
BetterListTile(
icon: FontAwesomeIcons.pencil,
text: context.lang.contactNickname,
onTap: () async {
final nickName =
await showNicknameChangeDialog(context, contact);
if (context.mounted && nickName != null && nickName != '') {
final update = ContactsCompanion(nickName: Value(nickName));
await twonlyDB.contactsDao
.updateContact(contact.userId, update);
}
},
), ),
const Divider(),
SelectChatDeletionTimeListTitle(
groupId: getUUIDforDirectChat(widget.userId, gUser.userId),
),
const Divider(),
MaxFlameListTitle(
contactId: widget.userId,
),
BetterListTile(
icon: FontAwesomeIcons.shieldHeart,
text: context.lang.contactVerifyNumberTitle,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const PublicProfileView();
},
),
);
setState(() {});
},
),
// BetterListTile(
// icon: FontAwesomeIcons.eraser,
// iconSize: 16,
// text: context.lang.deleteAllContactMessages,
// onTap: () async {
// final block = await showAlertDialog(
// context,
// context.lang.deleteAllContactMessages,
// context.lang.deleteAllContactMessagesBody(
// getContactDisplayName(contact),
// ),
// );
// if (block) {
// if (context.mounted) {
// await twonlyDB.messagesDao
// .deleteMessagesByContactId(contact.userId);
// }
// }
// },
// ),
BetterListTile(
icon: FontAwesomeIcons.flag,
text: context.lang.reportUser,
onTap: () => handleReportUser(contact),
),
BetterListTile(
icon: FontAwesomeIcons.ban,
text: context.lang.contactBlock,
onTap: () => handleUserBlockRequest(contact),
),
// BetterListTile(
// icon: FontAwesomeIcons.userMinus,
// iconSize: 16,
// color: Colors.red,
// text: context.lang.contactRemove,
// onTap: () => handleUserRemoveRequest(contact),
// ),
], ],
); ),
}, if (getContactDisplayName(contact) != contact.username)
Center(child: Text('(${contact.username})')),
const SizedBox(height: 50),
BetterListTile(
icon: FontAwesomeIcons.pencil,
text: context.lang.contactNickname,
onTap: () async {
final nickName = await showNicknameChangeDialog(context, contact);
if (context.mounted && nickName != null && nickName != '') {
final update = ContactsCompanion(nickName: Value(nickName));
await twonlyDB.contactsDao
.updateContact(contact.userId, update);
}
},
),
const Divider(),
SelectChatDeletionTimeListTitle(
groupId: getUUIDforDirectChat(widget.userId, gUser.userId),
),
const Divider(),
MaxFlameListTitle(
contactId: widget.userId,
),
BetterListTile(
icon: FontAwesomeIcons.shieldHeart,
text: context.lang.contactVerifyNumberTitle,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const PublicProfileView();
},
),
);
setState(() {});
},
),
// BetterListTile(
// icon: FontAwesomeIcons.eraser,
// iconSize: 16,
// text: context.lang.deleteAllContactMessages,
// onTap: () async {
// final block = await showAlertDialog(
// context,
// context.lang.deleteAllContactMessages,
// context.lang.deleteAllContactMessagesBody(
// getContactDisplayName(contact),
// ),
// );
// if (block) {
// if (context.mounted) {
// await twonlyDB.messagesDao
// .deleteMessagesByContactId(contact.userId);
// }
// }
// },
// ),
BetterListTile(
icon: FontAwesomeIcons.flag,
text: context.lang.reportUser,
onTap: () => handleReportUser(contact),
),
BetterListTile(
icon: FontAwesomeIcons.ban,
text: context.lang.contactBlock,
onTap: () => handleUserBlockRequest(contact),
),
BetterListTile(
icon: FontAwesomeIcons.userMinus,
iconSize: 16,
color: Colors.red,
text: context.lang.contactRemove,
onTap: () => handleUserRemoveRequest(contact),
),
],
), ),
); );
} }

View file

@ -8,6 +8,7 @@ import 'schema_v2.dart' as v2;
import 'schema_v3.dart' as v3; import 'schema_v3.dart' as v3;
import 'schema_v4.dart' as v4; import 'schema_v4.dart' as v4;
import 'schema_v5.dart' as v5; import 'schema_v5.dart' as v5;
import 'schema_v6.dart' as v6;
class GeneratedHelper implements SchemaInstantiationHelper { class GeneratedHelper implements SchemaInstantiationHelper {
@override @override
@ -23,10 +24,12 @@ class GeneratedHelper implements SchemaInstantiationHelper {
return v4.DatabaseAtV4(db); return v4.DatabaseAtV4(db);
case 5: case 5:
return v5.DatabaseAtV5(db); return v5.DatabaseAtV5(db);
case 6:
return v6.DatabaseAtV6(db);
default: default:
throw MissingSchemaException(version, versions); throw MissingSchemaException(version, versions);
} }
} }
static const versions = const [1, 2, 3, 4, 5]; static const versions = const [1, 2, 3, 4, 5, 6];
} }

File diff suppressed because it is too large Load diff