This commit is contained in:
otsmr 2025-06-01 16:39:14 +02:00
parent 86d87b84ac
commit 190b16ec9a
27 changed files with 4013 additions and 158 deletions

File diff suppressed because one or more lines are too long

View file

@ -34,8 +34,10 @@ void main() async {
apiService = ApiService(); apiService = ApiService();
twonlyDB = TwonlyDatabase(); twonlyDB = TwonlyDatabase();
await twonlyDB.messagesDao.resetPendingDownloadState(); await twonlyDB.messagesDao.resetPendingDownloadState();
await purgeReceivedMediaFiles();
await purgeSendMediaFiles(); // purge media files in the background
purgeReceivedMediaFiles();
purgeSendMediaFiles();
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);

View file

@ -123,12 +123,22 @@ class ContactsDao extends DatabaseAccessor<TwonlyDatabase>
// return (select(contacts)).watch(); // return (select(contacts)).watch();
} }
Stream<Contact> watchContact(int userid) { Stream<Contact?> watchContact(int userid) {
return (select(contacts)..where((t) => t.userId.equals(userid))) return (select(contacts)..where((t) => t.userId.equals(userid)))
.watchSingle(); .watchSingleOrNull();
} }
Stream<List<Contact>> watchContactsForShareView() { Stream<List<Contact>> watchContactsForShareView() {
return (select(contacts)
..where((t) =>
t.accepted.equals(true) &
t.blocked.equals(false) &
t.deleted.equals(false))
..orderBy([(t) => OrderingTerm.desc(t.lastMessageExchange)]))
.watch();
}
Stream<List<Contact>> watchContactsForStartNewChat() {
return (select(contacts) return (select(contacts)
..where((t) => t.accepted.equals(true) & t.blocked.equals(false)) ..where((t) => t.accepted.equals(true) & t.blocked.equals(false))
..orderBy([(t) => OrderingTerm.desc(t.lastMessageExchange)])) ..orderBy([(t) => OrderingTerm.desc(t.lastMessageExchange)]))
@ -190,13 +200,20 @@ class ContactsDao extends DatabaseAccessor<TwonlyDatabase>
} }
String getContactDisplayName(Contact user) { String getContactDisplayName(Contact user) {
if (user.nickName != null) { String name = user.username;
return user.nickName!; if (user.nickName != null && user.nickName != "") {
name = user.nickName!;
} else if (user.displayName != null) {
name = user.displayName!;
} }
if (user.displayName != null) { if (user.deleted) {
return user.displayName!; name = applyStrikethrough(name);
} }
return user.username; return name;
}
String applyStrikethrough(String text) {
return text.split('').map((char) => '$char\u0336').join('');
} }
int getFlameCounterFromContact(Contact contact) { int getFlameCounterFromContact(Contact contact) {

View file

@ -186,6 +186,10 @@ class MessagesDao extends DatabaseAccessor<TwonlyDatabase>
.go(); .go();
} }
Future deleteAllMessagesByContactId(int contactId) {
return (delete(messages)..where((t) => t.contactId.equals(contactId))).go();
}
Future<bool> containsOtherMessageId( Future<bool> containsOtherMessageId(
int fromUserId, int messageOtherId) async { int fromUserId, int messageOtherId) async {
final query = select(messages) final query = select(messages)

View file

@ -11,6 +11,15 @@ class SignalDao extends DatabaseAccessor<TwonlyDatabase> with _$SignalDaoMixin {
// of this object. // of this object.
SignalDao(super.db); SignalDao(super.db);
Future deleteAllByContactId(int contactId) async {
await (delete(signalContactPreKeys)
..where((t) => t.contactId.equals(contactId)))
.go();
await (delete(signalContactSignedPreKeys)
..where((t) => t.contactId.equals(contactId)))
.go();
}
// 1: Count the number of pre-keys by contact ID // 1: Count the number of pre-keys by contact ID
Future<int> countPreKeysByContactId(int contactId) { Future<int> countPreKeysByContactId(int contactId) {
return (select(signalContactPreKeys) return (select(signalContactPreKeys)

View file

@ -16,6 +16,8 @@ class Contacts extends Table {
BoolColumn get verified => boolean().withDefault(Constant(false))(); BoolColumn get verified => boolean().withDefault(Constant(false))();
BoolColumn get archived => boolean().withDefault(Constant(false))(); BoolColumn get archived => boolean().withDefault(Constant(false))();
BoolColumn get pinned => boolean().withDefault(Constant(false))(); BoolColumn get pinned => boolean().withDefault(Constant(false))();
BoolColumn get deleted => boolean().withDefault(Constant(false))();
BoolColumn get alsoBestFriend => boolean().withDefault(Constant(false))(); BoolColumn get alsoBestFriend => boolean().withDefault(Constant(false))();
IntColumn get deleteMessagesAfterXMinutes => IntColumn get deleteMessagesAfterXMinutes =>

View file

@ -63,6 +63,9 @@ class TwonlyDatabase extends _$TwonlyDatabase {
@override @override
MigrationStrategy get migration { MigrationStrategy get migration {
return MigrationStrategy( return MigrationStrategy(
beforeOpen: (details) async {
await customStatement('PRAGMA foreign_keys = ON');
},
onUpgrade: stepByStep( onUpgrade: stepByStep(
from1To2: (m, schema) async { from1To2: (m, schema) async {
m.addColumn(schema.messages, schema.messages.errorWhileSending); m.addColumn(schema.messages, schema.messages.errorWhileSending);
@ -109,6 +112,7 @@ class TwonlyDatabase extends _$TwonlyDatabase {
from9To10: (m, schema) async { from9To10: (m, schema) async {
m.createTable(signalContactPreKeys); m.createTable(signalContactPreKeys);
m.createTable(signalContactSignedPreKeys); m.createTable(signalContactSignedPreKeys);
m.addColumn(schema.contacts, schema.contacts.deleted);
}, },
), ),
); );

View file

@ -106,6 +106,16 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
defaultConstraints: defaultConstraints:
GeneratedColumn.constraintIsAlways('CHECK ("pinned" IN (0, 1))'), GeneratedColumn.constraintIsAlways('CHECK ("pinned" IN (0, 1))'),
defaultValue: Constant(false)); defaultValue: Constant(false));
static const VerificationMeta _deletedMeta =
const VerificationMeta('deleted');
@override
late final GeneratedColumn<bool> deleted = GeneratedColumn<bool>(
'deleted', aliasedName, false,
type: DriftSqlType.bool,
requiredDuringInsert: false,
defaultConstraints:
GeneratedColumn.constraintIsAlways('CHECK ("deleted" IN (0, 1))'),
defaultValue: Constant(false));
static const VerificationMeta _alsoBestFriendMeta = static const VerificationMeta _alsoBestFriendMeta =
const VerificationMeta('alsoBestFriend'); const VerificationMeta('alsoBestFriend');
@override @override
@ -195,6 +205,7 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
verified, verified,
archived, archived,
pinned, pinned,
deleted,
alsoBestFriend, alsoBestFriend,
deleteMessagesAfterXMinutes, deleteMessagesAfterXMinutes,
createdAt, createdAt,
@ -270,6 +281,10 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
context.handle(_pinnedMeta, context.handle(_pinnedMeta,
pinned.isAcceptableOrUnknown(data['pinned']!, _pinnedMeta)); pinned.isAcceptableOrUnknown(data['pinned']!, _pinnedMeta));
} }
if (data.containsKey('deleted')) {
context.handle(_deletedMeta,
deleted.isAcceptableOrUnknown(data['deleted']!, _deletedMeta));
}
if (data.containsKey('also_best_friend')) { if (data.containsKey('also_best_friend')) {
context.handle( context.handle(
_alsoBestFriendMeta, _alsoBestFriendMeta,
@ -362,6 +377,8 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
.read(DriftSqlType.bool, data['${effectivePrefix}archived'])!, .read(DriftSqlType.bool, data['${effectivePrefix}archived'])!,
pinned: attachedDatabase.typeMapping pinned: attachedDatabase.typeMapping
.read(DriftSqlType.bool, data['${effectivePrefix}pinned'])!, .read(DriftSqlType.bool, data['${effectivePrefix}pinned'])!,
deleted: attachedDatabase.typeMapping
.read(DriftSqlType.bool, data['${effectivePrefix}deleted'])!,
alsoBestFriend: attachedDatabase.typeMapping alsoBestFriend: attachedDatabase.typeMapping
.read(DriftSqlType.bool, data['${effectivePrefix}also_best_friend'])!, .read(DriftSqlType.bool, data['${effectivePrefix}also_best_friend'])!,
deleteMessagesAfterXMinutes: attachedDatabase.typeMapping.read( deleteMessagesAfterXMinutes: attachedDatabase.typeMapping.read(
@ -408,6 +425,7 @@ class Contact extends DataClass implements Insertable<Contact> {
final bool verified; final bool verified;
final bool archived; final bool archived;
final bool pinned; final bool pinned;
final bool deleted;
final bool alsoBestFriend; final bool alsoBestFriend;
final int deleteMessagesAfterXMinutes; final int deleteMessagesAfterXMinutes;
final DateTime createdAt; final DateTime createdAt;
@ -431,6 +449,7 @@ class Contact extends DataClass implements Insertable<Contact> {
required this.verified, required this.verified,
required this.archived, required this.archived,
required this.pinned, required this.pinned,
required this.deleted,
required this.alsoBestFriend, required this.alsoBestFriend,
required this.deleteMessagesAfterXMinutes, required this.deleteMessagesAfterXMinutes,
required this.createdAt, required this.createdAt,
@ -462,6 +481,7 @@ class Contact extends DataClass implements Insertable<Contact> {
map['verified'] = Variable<bool>(verified); map['verified'] = Variable<bool>(verified);
map['archived'] = Variable<bool>(archived); map['archived'] = Variable<bool>(archived);
map['pinned'] = Variable<bool>(pinned); map['pinned'] = Variable<bool>(pinned);
map['deleted'] = Variable<bool>(deleted);
map['also_best_friend'] = Variable<bool>(alsoBestFriend); map['also_best_friend'] = Variable<bool>(alsoBestFriend);
map['delete_messages_after_x_minutes'] = map['delete_messages_after_x_minutes'] =
Variable<int>(deleteMessagesAfterXMinutes); Variable<int>(deleteMessagesAfterXMinutes);
@ -505,6 +525,7 @@ class Contact extends DataClass implements Insertable<Contact> {
verified: Value(verified), verified: Value(verified),
archived: Value(archived), archived: Value(archived),
pinned: Value(pinned), pinned: Value(pinned),
deleted: Value(deleted),
alsoBestFriend: Value(alsoBestFriend), alsoBestFriend: Value(alsoBestFriend),
deleteMessagesAfterXMinutes: Value(deleteMessagesAfterXMinutes), deleteMessagesAfterXMinutes: Value(deleteMessagesAfterXMinutes),
createdAt: Value(createdAt), createdAt: Value(createdAt),
@ -542,6 +563,7 @@ class Contact extends DataClass implements Insertable<Contact> {
verified: serializer.fromJson<bool>(json['verified']), verified: serializer.fromJson<bool>(json['verified']),
archived: serializer.fromJson<bool>(json['archived']), archived: serializer.fromJson<bool>(json['archived']),
pinned: serializer.fromJson<bool>(json['pinned']), pinned: serializer.fromJson<bool>(json['pinned']),
deleted: serializer.fromJson<bool>(json['deleted']),
alsoBestFriend: serializer.fromJson<bool>(json['alsoBestFriend']), alsoBestFriend: serializer.fromJson<bool>(json['alsoBestFriend']),
deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes:
serializer.fromJson<int>(json['deleteMessagesAfterXMinutes']), serializer.fromJson<int>(json['deleteMessagesAfterXMinutes']),
@ -574,6 +596,7 @@ class Contact extends DataClass implements Insertable<Contact> {
'verified': serializer.toJson<bool>(verified), 'verified': serializer.toJson<bool>(verified),
'archived': serializer.toJson<bool>(archived), 'archived': serializer.toJson<bool>(archived),
'pinned': serializer.toJson<bool>(pinned), 'pinned': serializer.toJson<bool>(pinned),
'deleted': serializer.toJson<bool>(deleted),
'alsoBestFriend': serializer.toJson<bool>(alsoBestFriend), 'alsoBestFriend': serializer.toJson<bool>(alsoBestFriend),
'deleteMessagesAfterXMinutes': 'deleteMessagesAfterXMinutes':
serializer.toJson<int>(deleteMessagesAfterXMinutes), serializer.toJson<int>(deleteMessagesAfterXMinutes),
@ -602,6 +625,7 @@ class Contact extends DataClass implements Insertable<Contact> {
bool? verified, bool? verified,
bool? archived, bool? archived,
bool? pinned, bool? pinned,
bool? deleted,
bool? alsoBestFriend, bool? alsoBestFriend,
int? deleteMessagesAfterXMinutes, int? deleteMessagesAfterXMinutes,
DateTime? createdAt, DateTime? createdAt,
@ -625,6 +649,7 @@ class Contact extends DataClass implements Insertable<Contact> {
verified: verified ?? this.verified, verified: verified ?? this.verified,
archived: archived ?? this.archived, archived: archived ?? this.archived,
pinned: pinned ?? this.pinned, pinned: pinned ?? this.pinned,
deleted: deleted ?? this.deleted,
alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend,
deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes:
deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes, deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes,
@ -661,6 +686,7 @@ class Contact extends DataClass implements Insertable<Contact> {
verified: data.verified.present ? data.verified.value : this.verified, verified: data.verified.present ? data.verified.value : this.verified,
archived: data.archived.present ? data.archived.value : this.archived, archived: data.archived.present ? data.archived.value : this.archived,
pinned: data.pinned.present ? data.pinned.value : this.pinned, pinned: data.pinned.present ? data.pinned.value : this.pinned,
deleted: data.deleted.present ? data.deleted.value : this.deleted,
alsoBestFriend: data.alsoBestFriend.present alsoBestFriend: data.alsoBestFriend.present
? data.alsoBestFriend.value ? data.alsoBestFriend.value
: this.alsoBestFriend, : this.alsoBestFriend,
@ -707,6 +733,7 @@ class Contact extends DataClass implements Insertable<Contact> {
..write('verified: $verified, ') ..write('verified: $verified, ')
..write('archived: $archived, ') ..write('archived: $archived, ')
..write('pinned: $pinned, ') ..write('pinned: $pinned, ')
..write('deleted: $deleted, ')
..write('alsoBestFriend: $alsoBestFriend, ') ..write('alsoBestFriend: $alsoBestFriend, ')
..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ') ..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ')
..write('createdAt: $createdAt, ') ..write('createdAt: $createdAt, ')
@ -735,6 +762,7 @@ class Contact extends DataClass implements Insertable<Contact> {
verified, verified,
archived, archived,
pinned, pinned,
deleted,
alsoBestFriend, alsoBestFriend,
deleteMessagesAfterXMinutes, deleteMessagesAfterXMinutes,
createdAt, createdAt,
@ -762,6 +790,7 @@ class Contact extends DataClass implements Insertable<Contact> {
other.verified == this.verified && other.verified == this.verified &&
other.archived == this.archived && other.archived == this.archived &&
other.pinned == this.pinned && other.pinned == this.pinned &&
other.deleted == this.deleted &&
other.alsoBestFriend == this.alsoBestFriend && other.alsoBestFriend == this.alsoBestFriend &&
other.deleteMessagesAfterXMinutes == other.deleteMessagesAfterXMinutes ==
this.deleteMessagesAfterXMinutes && this.deleteMessagesAfterXMinutes &&
@ -788,6 +817,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
final Value<bool> verified; final Value<bool> verified;
final Value<bool> archived; final Value<bool> archived;
final Value<bool> pinned; final Value<bool> pinned;
final Value<bool> deleted;
final Value<bool> alsoBestFriend; final Value<bool> alsoBestFriend;
final Value<int> deleteMessagesAfterXMinutes; final Value<int> deleteMessagesAfterXMinutes;
final Value<DateTime> createdAt; final Value<DateTime> createdAt;
@ -811,6 +841,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
this.verified = const Value.absent(), this.verified = const Value.absent(),
this.archived = const Value.absent(), this.archived = const Value.absent(),
this.pinned = const Value.absent(), this.pinned = const Value.absent(),
this.deleted = const Value.absent(),
this.alsoBestFriend = const Value.absent(), this.alsoBestFriend = const Value.absent(),
this.deleteMessagesAfterXMinutes = const Value.absent(), this.deleteMessagesAfterXMinutes = const Value.absent(),
this.createdAt = const Value.absent(), this.createdAt = const Value.absent(),
@ -835,6 +866,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
this.verified = const Value.absent(), this.verified = const Value.absent(),
this.archived = const Value.absent(), this.archived = const Value.absent(),
this.pinned = const Value.absent(), this.pinned = const Value.absent(),
this.deleted = const Value.absent(),
this.alsoBestFriend = const Value.absent(), this.alsoBestFriend = const Value.absent(),
this.deleteMessagesAfterXMinutes = const Value.absent(), this.deleteMessagesAfterXMinutes = const Value.absent(),
this.createdAt = const Value.absent(), this.createdAt = const Value.absent(),
@ -859,6 +891,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
Expression<bool>? verified, Expression<bool>? verified,
Expression<bool>? archived, Expression<bool>? archived,
Expression<bool>? pinned, Expression<bool>? pinned,
Expression<bool>? deleted,
Expression<bool>? alsoBestFriend, Expression<bool>? alsoBestFriend,
Expression<int>? deleteMessagesAfterXMinutes, Expression<int>? deleteMessagesAfterXMinutes,
Expression<DateTime>? createdAt, Expression<DateTime>? createdAt,
@ -883,6 +916,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
if (verified != null) 'verified': verified, if (verified != null) 'verified': verified,
if (archived != null) 'archived': archived, if (archived != null) 'archived': archived,
if (pinned != null) 'pinned': pinned, if (pinned != null) 'pinned': pinned,
if (deleted != null) 'deleted': deleted,
if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend, if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend,
if (deleteMessagesAfterXMinutes != null) if (deleteMessagesAfterXMinutes != null)
'delete_messages_after_x_minutes': deleteMessagesAfterXMinutes, 'delete_messages_after_x_minutes': deleteMessagesAfterXMinutes,
@ -913,6 +947,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
Value<bool>? verified, Value<bool>? verified,
Value<bool>? archived, Value<bool>? archived,
Value<bool>? pinned, Value<bool>? pinned,
Value<bool>? deleted,
Value<bool>? alsoBestFriend, Value<bool>? alsoBestFriend,
Value<int>? deleteMessagesAfterXMinutes, Value<int>? deleteMessagesAfterXMinutes,
Value<DateTime>? createdAt, Value<DateTime>? createdAt,
@ -936,6 +971,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
verified: verified ?? this.verified, verified: verified ?? this.verified,
archived: archived ?? this.archived, archived: archived ?? this.archived,
pinned: pinned ?? this.pinned, pinned: pinned ?? this.pinned,
deleted: deleted ?? this.deleted,
alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend,
deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes:
deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes, deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes,
@ -990,6 +1026,9 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
if (pinned.present) { if (pinned.present) {
map['pinned'] = Variable<bool>(pinned.value); map['pinned'] = Variable<bool>(pinned.value);
} }
if (deleted.present) {
map['deleted'] = Variable<bool>(deleted.value);
}
if (alsoBestFriend.present) { if (alsoBestFriend.present) {
map['also_best_friend'] = Variable<bool>(alsoBestFriend.value); map['also_best_friend'] = Variable<bool>(alsoBestFriend.value);
} }
@ -1042,6 +1081,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
..write('verified: $verified, ') ..write('verified: $verified, ')
..write('archived: $archived, ') ..write('archived: $archived, ')
..write('pinned: $pinned, ') ..write('pinned: $pinned, ')
..write('deleted: $deleted, ')
..write('alsoBestFriend: $alsoBestFriend, ') ..write('alsoBestFriend: $alsoBestFriend, ')
..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ') ..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ')
..write('createdAt: $createdAt, ') ..write('createdAt: $createdAt, ')
@ -4196,6 +4236,7 @@ typedef $$ContactsTableCreateCompanionBuilder = ContactsCompanion Function({
Value<bool> verified, Value<bool> verified,
Value<bool> archived, Value<bool> archived,
Value<bool> pinned, Value<bool> pinned,
Value<bool> deleted,
Value<bool> alsoBestFriend, Value<bool> alsoBestFriend,
Value<int> deleteMessagesAfterXMinutes, Value<int> deleteMessagesAfterXMinutes,
Value<DateTime> createdAt, Value<DateTime> createdAt,
@ -4220,6 +4261,7 @@ typedef $$ContactsTableUpdateCompanionBuilder = ContactsCompanion Function({
Value<bool> verified, Value<bool> verified,
Value<bool> archived, Value<bool> archived,
Value<bool> pinned, Value<bool> pinned,
Value<bool> deleted,
Value<bool> alsoBestFriend, Value<bool> alsoBestFriend,
Value<int> deleteMessagesAfterXMinutes, Value<int> deleteMessagesAfterXMinutes,
Value<DateTime> createdAt, Value<DateTime> createdAt,
@ -4298,6 +4340,9 @@ class $$ContactsTableFilterComposer
ColumnFilters<bool> get pinned => $composableBuilder( ColumnFilters<bool> get pinned => $composableBuilder(
column: $table.pinned, builder: (column) => ColumnFilters(column)); column: $table.pinned, builder: (column) => ColumnFilters(column));
ColumnFilters<bool> get deleted => $composableBuilder(
column: $table.deleted, builder: (column) => ColumnFilters(column));
ColumnFilters<bool> get alsoBestFriend => $composableBuilder( ColumnFilters<bool> get alsoBestFriend => $composableBuilder(
column: $table.alsoBestFriend, column: $table.alsoBestFriend,
builder: (column) => ColumnFilters(column)); builder: (column) => ColumnFilters(column));
@ -4403,6 +4448,9 @@ class $$ContactsTableOrderingComposer
ColumnOrderings<bool> get pinned => $composableBuilder( ColumnOrderings<bool> get pinned => $composableBuilder(
column: $table.pinned, builder: (column) => ColumnOrderings(column)); column: $table.pinned, builder: (column) => ColumnOrderings(column));
ColumnOrderings<bool> get deleted => $composableBuilder(
column: $table.deleted, builder: (column) => ColumnOrderings(column));
ColumnOrderings<bool> get alsoBestFriend => $composableBuilder( ColumnOrderings<bool> get alsoBestFriend => $composableBuilder(
column: $table.alsoBestFriend, column: $table.alsoBestFriend,
builder: (column) => ColumnOrderings(column)); builder: (column) => ColumnOrderings(column));
@ -4488,6 +4536,9 @@ class $$ContactsTableAnnotationComposer
GeneratedColumn<bool> get pinned => GeneratedColumn<bool> get pinned =>
$composableBuilder(column: $table.pinned, builder: (column) => column); $composableBuilder(column: $table.pinned, builder: (column) => column);
GeneratedColumn<bool> get deleted =>
$composableBuilder(column: $table.deleted, builder: (column) => column);
GeneratedColumn<bool> get alsoBestFriend => $composableBuilder( GeneratedColumn<bool> get alsoBestFriend => $composableBuilder(
column: $table.alsoBestFriend, builder: (column) => column); column: $table.alsoBestFriend, builder: (column) => column);
@ -4575,6 +4626,7 @@ class $$ContactsTableTableManager extends RootTableManager<
Value<bool> verified = const Value.absent(), Value<bool> verified = const Value.absent(),
Value<bool> archived = const Value.absent(), Value<bool> archived = const Value.absent(),
Value<bool> pinned = const Value.absent(), Value<bool> pinned = const Value.absent(),
Value<bool> deleted = const Value.absent(),
Value<bool> alsoBestFriend = const Value.absent(), Value<bool> alsoBestFriend = const Value.absent(),
Value<int> deleteMessagesAfterXMinutes = const Value.absent(), Value<int> deleteMessagesAfterXMinutes = const Value.absent(),
Value<DateTime> createdAt = const Value.absent(), Value<DateTime> createdAt = const Value.absent(),
@ -4599,6 +4651,7 @@ class $$ContactsTableTableManager extends RootTableManager<
verified: verified, verified: verified,
archived: archived, archived: archived,
pinned: pinned, pinned: pinned,
deleted: deleted,
alsoBestFriend: alsoBestFriend, alsoBestFriend: alsoBestFriend,
deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes, deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes,
createdAt: createdAt, createdAt: createdAt,
@ -4623,6 +4676,7 @@ class $$ContactsTableTableManager extends RootTableManager<
Value<bool> verified = const Value.absent(), Value<bool> verified = const Value.absent(),
Value<bool> archived = const Value.absent(), Value<bool> archived = const Value.absent(),
Value<bool> pinned = const Value.absent(), Value<bool> pinned = const Value.absent(),
Value<bool> deleted = const Value.absent(),
Value<bool> alsoBestFriend = const Value.absent(), Value<bool> alsoBestFriend = const Value.absent(),
Value<int> deleteMessagesAfterXMinutes = const Value.absent(), Value<int> deleteMessagesAfterXMinutes = const Value.absent(),
Value<DateTime> createdAt = const Value.absent(), Value<DateTime> createdAt = const Value.absent(),
@ -4647,6 +4701,7 @@ class $$ContactsTableTableManager extends RootTableManager<
verified: verified, verified: verified,
archived: archived, archived: archived,
pinned: pinned, pinned: pinned,
deleted: deleted,
alsoBestFriend: alsoBestFriend, alsoBestFriend: alsoBestFriend,
deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes, deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes,
createdAt: createdAt, createdAt: createdAt,

View file

@ -1895,7 +1895,7 @@ final class Schema10 extends i0.VersionedSchema {
signalContactPreKeys, signalContactPreKeys,
signalContactSignedPreKeys, signalContactSignedPreKeys,
]; ];
late final Shape12 contacts = Shape12( late final Shape13 contacts = Shape13(
source: i0.VersionedTable( source: i0.VersionedTable(
entityName: 'contacts', entityName: 'contacts',
withoutRowId: false, withoutRowId: false,
@ -1916,6 +1916,7 @@ final class Schema10 extends i0.VersionedSchema {
_column_9, _column_9,
_column_39, _column_39,
_column_53, _column_53,
_column_57,
_column_54, _column_54,
_column_40, _column_40,
_column_10, _column_10,
@ -2054,7 +2055,7 @@ final class Schema10 extends i0.VersionedSchema {
attachedDatabase: database, attachedDatabase: database,
), ),
alias: null); alias: null);
late final Shape13 signalContactPreKeys = Shape13( late final Shape14 signalContactPreKeys = Shape14(
source: i0.VersionedTable( source: i0.VersionedTable(
entityName: 'signal_contact_pre_keys', entityName: 'signal_contact_pre_keys',
withoutRowId: false, withoutRowId: false,
@ -2063,7 +2064,7 @@ final class Schema10 extends i0.VersionedSchema {
'PRIMARY KEY(contact_id, pre_key_id)', 'PRIMARY KEY(contact_id, pre_key_id)',
], ],
columns: [ columns: [
_column_57, _column_58,
_column_34, _column_34,
_column_35, _column_35,
_column_10, _column_10,
@ -2071,19 +2072,19 @@ final class Schema10 extends i0.VersionedSchema {
attachedDatabase: database, attachedDatabase: database,
), ),
alias: null); alias: null);
late final Shape14 signalContactSignedPreKeys = Shape14( late final Shape15 signalContactSignedPreKeys = Shape15(
source: i0.VersionedTable( source: i0.VersionedTable(
entityName: 'signal_contact_signed_pre_keys', entityName: 'signal_contact_signed_pre_keys',
withoutRowId: false, withoutRowId: false,
isStrict: false, isStrict: false,
tableConstraints: [ tableConstraints: [
'PRIMARY KEY(contact_id, signed_pre_key_id)', 'PRIMARY KEY(contact_id)',
], ],
columns: [ columns: [
_column_57,
_column_58, _column_58,
_column_59, _column_59,
_column_60, _column_60,
_column_61,
_column_10, _column_10,
], ],
attachedDatabase: database, attachedDatabase: database,
@ -2093,6 +2094,65 @@ final class Schema10 extends i0.VersionedSchema {
class Shape13 extends i0.VersionedTable { class Shape13 extends i0.VersionedTable {
Shape13({required super.source, required super.alias}) : super.aliased(); Shape13({required super.source, required super.alias}) : super.aliased();
i1.GeneratedColumn<int> get userId =>
columnsByName['user_id']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<String> get username =>
columnsByName['username']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get displayName =>
columnsByName['display_name']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get nickName =>
columnsByName['nick_name']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get avatarSvg =>
columnsByName['avatar_svg']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<int> get myAvatarCounter =>
columnsByName['my_avatar_counter']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<bool> get accepted =>
columnsByName['accepted']! as i1.GeneratedColumn<bool>;
i1.GeneratedColumn<bool> get requested =>
columnsByName['requested']! as i1.GeneratedColumn<bool>;
i1.GeneratedColumn<bool> get blocked =>
columnsByName['blocked']! as i1.GeneratedColumn<bool>;
i1.GeneratedColumn<bool> get verified =>
columnsByName['verified']! as i1.GeneratedColumn<bool>;
i1.GeneratedColumn<bool> get archived =>
columnsByName['archived']! as i1.GeneratedColumn<bool>;
i1.GeneratedColumn<bool> get pinned =>
columnsByName['pinned']! as i1.GeneratedColumn<bool>;
i1.GeneratedColumn<bool> get deleted =>
columnsByName['deleted']! as i1.GeneratedColumn<bool>;
i1.GeneratedColumn<bool> get alsoBestFriend =>
columnsByName['also_best_friend']! as i1.GeneratedColumn<bool>;
i1.GeneratedColumn<int> get deleteMessagesAfterXMinutes =>
columnsByName['delete_messages_after_x_minutes']!
as i1.GeneratedColumn<int>;
i1.GeneratedColumn<DateTime> get createdAt =>
columnsByName['created_at']! as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<int> get totalMediaCounter =>
columnsByName['total_media_counter']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<DateTime> get lastMessageSend =>
columnsByName['last_message_send']! as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<DateTime> get lastMessageReceived =>
columnsByName['last_message_received']! as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<DateTime> get lastFlameCounterChange =>
columnsByName['last_flame_counter_change']!
as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<DateTime> get lastFlameSync =>
columnsByName['last_flame_sync']! as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<DateTime> get lastMessageExchange =>
columnsByName['last_message_exchange']! as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<int> get flameCounter =>
columnsByName['flame_counter']! as i1.GeneratedColumn<int>;
}
i1.GeneratedColumn<bool> _column_57(String aliasedName) =>
i1.GeneratedColumn<bool>('deleted', aliasedName, false,
type: i1.DriftSqlType.bool,
defaultConstraints: i1.GeneratedColumn.constraintIsAlways(
'CHECK ("deleted" IN (0, 1))'),
defaultValue: const CustomExpression('0'));
class Shape14 extends i0.VersionedTable {
Shape14({required super.source, required super.alias}) : super.aliased();
i1.GeneratedColumn<int> get contactId => i1.GeneratedColumn<int> get contactId =>
columnsByName['contact_id']! as i1.GeneratedColumn<int>; columnsByName['contact_id']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<int> get preKeyId => i1.GeneratedColumn<int> get preKeyId =>
@ -2103,12 +2163,12 @@ class Shape13 extends i0.VersionedTable {
columnsByName['created_at']! as i1.GeneratedColumn<DateTime>; columnsByName['created_at']! as i1.GeneratedColumn<DateTime>;
} }
i1.GeneratedColumn<int> _column_57(String aliasedName) => i1.GeneratedColumn<int> _column_58(String aliasedName) =>
i1.GeneratedColumn<int>('contact_id', aliasedName, false, i1.GeneratedColumn<int>('contact_id', aliasedName, false,
type: i1.DriftSqlType.int); type: i1.DriftSqlType.int);
class Shape14 extends i0.VersionedTable { class Shape15 extends i0.VersionedTable {
Shape14({required super.source, required super.alias}) : super.aliased(); Shape15({required super.source, required super.alias}) : super.aliased();
i1.GeneratedColumn<int> get contactId => i1.GeneratedColumn<int> get contactId =>
columnsByName['contact_id']! as i1.GeneratedColumn<int>; columnsByName['contact_id']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<int> get signedPreKeyId => i1.GeneratedColumn<int> get signedPreKeyId =>
@ -2122,13 +2182,13 @@ class Shape14 extends i0.VersionedTable {
columnsByName['created_at']! as i1.GeneratedColumn<DateTime>; columnsByName['created_at']! as i1.GeneratedColumn<DateTime>;
} }
i1.GeneratedColumn<int> _column_58(String aliasedName) => i1.GeneratedColumn<int> _column_59(String aliasedName) =>
i1.GeneratedColumn<int>('signed_pre_key_id', aliasedName, false, i1.GeneratedColumn<int>('signed_pre_key_id', aliasedName, false,
type: i1.DriftSqlType.int); type: i1.DriftSqlType.int);
i1.GeneratedColumn<i2.Uint8List> _column_59(String aliasedName) => i1.GeneratedColumn<i2.Uint8List> _column_60(String aliasedName) =>
i1.GeneratedColumn<i2.Uint8List>('signed_pre_key', aliasedName, false, i1.GeneratedColumn<i2.Uint8List>('signed_pre_key', aliasedName, false,
type: i1.DriftSqlType.blob); type: i1.DriftSqlType.blob);
i1.GeneratedColumn<i2.Uint8List> _column_60(String aliasedName) => i1.GeneratedColumn<i2.Uint8List> _column_61(String aliasedName) =>
i1.GeneratedColumn<i2.Uint8List>( i1.GeneratedColumn<i2.Uint8List>(
'signed_pre_key_signature', aliasedName, false, 'signed_pre_key_signature', aliasedName, false,
type: i1.DriftSqlType.blob); type: i1.DriftSqlType.blob);

View file

@ -64,6 +64,7 @@
"chatListViewSearchUserNameBtn": "Füge deinen ersten twonly-Kontakt hinzu!", "chatListViewSearchUserNameBtn": "Füge deinen ersten twonly-Kontakt hinzu!",
"chatListViewSendFirstTwonly": "Sende dein erstes twonly!", "chatListViewSendFirstTwonly": "Sende dein erstes twonly!",
"chatListDetailInput": "Nachricht eingeben", "chatListDetailInput": "Nachricht eingeben",
"userDeletedAccount": "Der Nutzer hat sein Konto gelöscht.",
"contextMenuVerifyUser": "Verifizieren", "contextMenuVerifyUser": "Verifizieren",
"@contextMenuVerifyUser": {}, "@contextMenuVerifyUser": {},
"contextMenuArchiveUser": "Archivieren", "contextMenuArchiveUser": "Archivieren",
@ -141,7 +142,10 @@
"contactNickname": "Spitzname", "contactNickname": "Spitzname",
"contactNicknameNew": "Neuer Spitzname", "contactNicknameNew": "Neuer Spitzname",
"contactBlock": "Blockieren", "contactBlock": "Blockieren",
"deleteAllContactMessages": "Alle Nachrichten löschen", "contactRemove": "Benutzer löschen",
"contactRemoveTitle": "{username} löschen?",
"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.",
"deleteAllContactMessages": "Textnachrichten löschen",
"deleteAllContactMessagesBody": "Dadurch werden alle Nachrichten, ausgenommen gespeicherte Mediendateien, in deinem Chat mit {username} gelöscht. Dies löscht NICHT die auf dem Gerät von {username} gespeicherten Nachrichten!", "deleteAllContactMessagesBody": "Dadurch werden alle Nachrichten, ausgenommen gespeicherte Mediendateien, in deinem Chat mit {username} gelöscht. Dies löscht NICHT die auf dem Gerät von {username} gespeicherten Nachrichten!",
"contactBlockTitle": "Blockiere {username}", "contactBlockTitle": "Blockiere {username}",
"contactBlockBody": "Ein blockierter Benutzer kann dir keine Nachrichten mehr senden, und sein Profil ist nicht mehr sichtbar. Um die Blockierung eines Benutzers aufzuheben, navigiere einfach zu Einstellungen > Datenschutz > Blockierte Benutzer.", "contactBlockBody": "Ein blockierter Benutzer kann dir keine Nachrichten mehr senden, und sein Profil ist nicht mehr sichtbar. Um die Blockierung eines Benutzers aufzuheben, navigiere einfach zu Einstellungen > Datenschutz > Blockierte Benutzer.",

View file

@ -115,6 +115,7 @@
"@chatListViewSendFirstTwonly": {}, "@chatListViewSendFirstTwonly": {},
"chatListDetailInput": "Type a message", "chatListDetailInput": "Type a message",
"@chatListDetailInput": {}, "@chatListDetailInput": {},
"userDeletedAccount": "The user has deleted its account.",
"contextMenuVerifyUser": "Verify", "contextMenuVerifyUser": "Verify",
"@contextMenuVerifyUser": {}, "@contextMenuVerifyUser": {},
"contextMenuArchiveUser": "Archive", "contextMenuArchiveUser": "Archive",
@ -250,7 +251,7 @@
"@contactNickname": {}, "@contactNickname": {},
"contactNicknameNew": "New nickname", "contactNicknameNew": "New nickname",
"@contactNicknameNew": {}, "@contactNicknameNew": {},
"deleteAllContactMessages": "Delete all messages", "deleteAllContactMessages": "Delete all text-messages",
"@deleteAllContactMessages": {}, "@deleteAllContactMessages": {},
"deleteAllContactMessagesBody": "This will remove all messages, except stored media files, in your chat with {username}. This will NOT delete the messages stored at {username}s device!", "deleteAllContactMessagesBody": "This will remove all messages, except stored media files, in your chat with {username}. This will NOT delete the messages stored at {username}s device!",
"@deleteAllContactMessagesBody": { "@deleteAllContactMessagesBody": {
@ -268,6 +269,9 @@
}, },
"contactBlockBody": "A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users.", "contactBlockBody": "A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users.",
"@contactBlockBody": {}, "@contactBlockBody": {},
"contactRemove": "Remove user",
"contactRemoveTitle": "Remove {username}",
"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.",
"undo": "Undo", "undo": "Undo",
"@undo": {}, "@undo": {},
"redo": "Redo", "redo": "Redo",

View file

@ -446,6 +446,12 @@ abstract class AppLocalizations {
/// **'Type a message'** /// **'Type a message'**
String get chatListDetailInput; String get chatListDetailInput;
/// No description provided for @userDeletedAccount.
///
/// In en, this message translates to:
/// **'The user has deleted its account.'**
String get userDeletedAccount;
/// No description provided for @contextMenuVerifyUser. /// No description provided for @contextMenuVerifyUser.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
@ -845,7 +851,7 @@ abstract class AppLocalizations {
/// No description provided for @deleteAllContactMessages. /// No description provided for @deleteAllContactMessages.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
/// **'Delete all messages'** /// **'Delete all text-messages'**
String get deleteAllContactMessages; String get deleteAllContactMessages;
/// No description provided for @deleteAllContactMessagesBody. /// No description provided for @deleteAllContactMessagesBody.
@ -872,6 +878,24 @@ abstract class AppLocalizations {
/// **'A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users.'** /// **'A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users.'**
String get contactBlockBody; String get contactBlockBody;
/// No description provided for @contactRemove.
///
/// In en, this message translates to:
/// **'Remove user'**
String get contactRemove;
/// No description provided for @contactRemoveTitle.
///
/// In en, this message translates to:
/// **'Remove {username}'**
String contactRemoveTitle(Object username);
/// No description provided for @contactRemoveBody.
///
/// 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.'**
String get contactRemoveBody;
/// No description provided for @undo. /// No description provided for @undo.
/// ///
/// In en, this message translates to: /// In en, this message translates to:

View file

@ -203,6 +203,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override @override
String get chatListDetailInput => 'Nachricht eingeben'; String get chatListDetailInput => 'Nachricht eingeben';
@override
String get userDeletedAccount => 'Der Nutzer hat sein Konto gelöscht.';
@override @override
String get contextMenuVerifyUser => 'Verifizieren'; String get contextMenuVerifyUser => 'Verifizieren';
@ -419,7 +422,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get contactNicknameNew => 'Neuer Spitzname'; String get contactNicknameNew => 'Neuer Spitzname';
@override @override
String get deleteAllContactMessages => 'Alle Nachrichten löschen'; String get deleteAllContactMessages => 'Textnachrichten löschen';
@override @override
String deleteAllContactMessagesBody(Object username) { String deleteAllContactMessagesBody(Object username) {
@ -438,6 +441,18 @@ class AppLocalizationsDe extends AppLocalizations {
String get contactBlockBody => String get contactBlockBody =>
'Ein blockierter Benutzer kann dir keine Nachrichten mehr senden, und sein Profil ist nicht mehr sichtbar. Um die Blockierung eines Benutzers aufzuheben, navigiere einfach zu Einstellungen > Datenschutz > Blockierte Benutzer.'; 'Ein blockierter Benutzer kann dir keine Nachrichten mehr senden, und sein Profil ist nicht mehr sichtbar. Um die Blockierung eines Benutzers aufzuheben, navigiere einfach zu Einstellungen > Datenschutz > Blockierte Benutzer.';
@override
String get contactRemove => 'Benutzer löschen';
@override
String contactRemoveTitle(Object username) {
return '$username löschen?';
}
@override
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.';
@override @override
String get undo => 'Rückgängig'; String get undo => 'Rückgängig';

View file

@ -201,6 +201,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get chatListDetailInput => 'Type a message'; String get chatListDetailInput => 'Type a message';
@override
String get userDeletedAccount => 'The user has deleted its account.';
@override @override
String get contextMenuVerifyUser => 'Verify'; String get contextMenuVerifyUser => 'Verify';
@ -414,7 +417,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get contactNicknameNew => 'New nickname'; String get contactNicknameNew => 'New nickname';
@override @override
String get deleteAllContactMessages => 'Delete all messages'; String get deleteAllContactMessages => 'Delete all text-messages';
@override @override
String deleteAllContactMessagesBody(Object username) { String deleteAllContactMessagesBody(Object username) {
@ -433,6 +436,18 @@ class AppLocalizationsEn extends AppLocalizations {
String get contactBlockBody => String get contactBlockBody =>
'A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users.'; 'A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users.';
@override
String get contactRemove => 'Remove user';
@override
String contactRemoveTitle(Object username) {
return 'Remove $username';
}
@override
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.';
@override @override
String get undo => 'Undo'; String get undo => 'Undo';

View file

@ -3,6 +3,7 @@ import 'dart:collection';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:drift/drift.dart';
import 'package:fixnum/fixnum.dart'; import 'package:fixnum/fixnum.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
@ -10,6 +11,7 @@ import 'package:mutex/mutex.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/app.dart'; import 'package:twonly/app.dart';
import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/model/json/userdata.dart'; import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/model/protobuf/api/client_to_server.pbserver.dart'; import 'package:twonly/src/model/protobuf/api/client_to_server.pbserver.dart';
import 'package:twonly/src/model/protobuf/api/error.pb.dart'; import 'package:twonly/src/model/protobuf/api/error.pb.dart';
@ -221,8 +223,12 @@ class ApiService {
box.put("rawbytes-to-retransmit", retransmit); box.put("rawbytes-to-retransmit", retransmit);
} }
Future<Result> sendRequestSync(ClientToServer request, Future<Result> sendRequestSync(
{bool authenticated = true, bool ensureRetransmission = false}) async { ClientToServer request, {
bool authenticated = true,
bool ensureRetransmission = false,
int? contactId,
}) async {
var seq = Int64(Random().nextInt(4294967296)); var seq = Int64(Random().nextInt(4294967296));
while (messagesV0.containsKey(seq)) { while (messagesV0.containsKey(seq)) {
seq = Int64(Random().nextInt(4294967296)); seq = Int64(Random().nextInt(4294967296));
@ -263,6 +269,11 @@ class ApiService {
} }
} }
} }
if (res.error == ErrorCode.UserIdNotFound && contactId != null) {
Log.error("Contact deleted their account $contactId.");
await twonlyDB.contactsDao
.updateContact(contactId, ContactsCompanion(deleted: Value(true)));
}
} }
return res; return res;
} }
@ -393,7 +404,7 @@ class ApiService {
var get = ApplicationData_GetUserById()..userId = Int64(userId); var get = ApplicationData_GetUserById()..userId = Int64(userId);
var appData = ApplicationData()..getuserbyid = get; var appData = ApplicationData()..getuserbyid = get;
var req = createClientToServerFromApplicationData(appData); var req = createClientToServerFromApplicationData(appData);
return await sendRequestSync(req); return await sendRequestSync(req, contactId: userId);
} }
Future<Result> getUploadToken(int recipientsCount) async { Future<Result> getUploadToken(int recipientsCount) async {
@ -504,7 +515,7 @@ class ApiService {
var get = ApplicationData_RemoveAdditionalUser()..userId = userId; var get = ApplicationData_RemoveAdditionalUser()..userId = userId;
var appData = ApplicationData()..removeadditionaluser = get; var appData = ApplicationData()..removeadditionaluser = get;
var req = createClientToServerFromApplicationData(appData); var req = createClientToServerFromApplicationData(appData);
return await sendRequestSync(req); return await sendRequestSync(req, contactId: userId.toInt());
} }
Future<Result> buyVoucher(int valueInCents) async { Future<Result> buyVoucher(int valueInCents) async {
@ -571,7 +582,7 @@ class ApiService {
var get = ApplicationData_GetSignedPreKeyByUserId()..userId = Int64(userId); var get = ApplicationData_GetSignedPreKeyByUserId()..userId = Int64(userId);
var appData = ApplicationData()..getsignedprekeybyuserid = get; var appData = ApplicationData()..getsignedprekeybyuserid = get;
var req = createClientToServerFromApplicationData(appData); var req = createClientToServerFromApplicationData(appData);
Result res = await sendRequestSync(req); Result res = await sendRequestSync(req, contactId: userId);
if (res.isSuccess) { if (res.isSuccess) {
server.Response_Ok ok = res.value; server.Response_Ok ok = res.value;
if (ok.hasSignedprekey()) { if (ok.hasSignedprekey()) {
@ -585,7 +596,7 @@ class ApiService {
var get = ApplicationData_GetPrekeysByUserId()..userId = Int64(userId); var get = ApplicationData_GetPrekeysByUserId()..userId = Int64(userId);
var appData = ApplicationData()..getprekeysbyuserid = get; var appData = ApplicationData()..getprekeysbyuserid = get;
var req = createClientToServerFromApplicationData(appData); var req = createClientToServerFromApplicationData(appData);
Result res = await sendRequestSync(req); Result res = await sendRequestSync(req, contactId: userId);
if (res.isSuccess) { if (res.isSuccess) {
server.Response_Ok ok = res.value; server.Response_Ok ok = res.value;
if (ok.hasUserdata()) { if (ok.hasUserdata()) {
@ -617,7 +628,6 @@ class ApiService {
var appData = ApplicationData()..textmessage = testMessage; var appData = ApplicationData()..textmessage = testMessage;
var req = createClientToServerFromApplicationData(appData); var req = createClientToServerFromApplicationData(appData);
return await sendRequestSync(req, contactId: target);
return await sendRequestSync(req);
} }
} }

View file

@ -8,6 +8,7 @@ import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/model/json/message.dart'; import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/model/json/userdata.dart'; import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/model/protobuf/api/error.pb.dart';
import 'package:twonly/src/services/api/utils.dart'; import 'package:twonly/src/services/api/utils.dart';
import 'package:twonly/src/services/signal/encryption.signal.dart'; import 'package:twonly/src/services/signal/encryption.signal.dart';
import 'package:twonly/src/utils/hive.dart'; import 'package:twonly/src/utils/hive.dart';
@ -114,19 +115,37 @@ Future<Result> sendRetransmitMessage(
Result resp = Result resp =
await apiService.sendTextMessage(msg.userId, msg.bytes, msg.pushData); await apiService.sendTextMessage(msg.userId, msg.bytes, msg.pushData);
bool retry = true;
if (resp.isError) {
if (resp.error == ErrorCode.UserIdNotFound) {
retry = false;
if (msg.messageId != null) {
await twonlyDB.messagesDao.updateMessageByMessageId(
msg.messageId!,
MessagesCompanion(errorWhileSending: Value(true)),
);
}
}
}
if (resp.isSuccess) { if (resp.isSuccess) {
if (msg.messageId != null) {
retry = false;
await twonlyDB.messagesDao.updateMessageByMessageId(
msg.messageId!,
MessagesCompanion(acknowledgeByServer: Value(true)),
);
}
}
if (!retry) {
{ {
var retransmit = await getAllMessagesForRetransmitting(); var retransmit = await getAllMessagesForRetransmitting();
retransmit.remove(stateId); retransmit.remove(stateId);
Box box = await getMediaStorage(); Box box = await getMediaStorage();
box.put("messages-to-retransmit", jsonEncode(retransmit)); box.put("messages-to-retransmit", jsonEncode(retransmit));
} }
if (msg.messageId != null) {
await twonlyDB.messagesDao.updateMessageByMessageId(
msg.messageId!,
MessagesCompanion(acknowledgeByServer: Value(true)),
);
}
} }
return resp; return resp;
} }

View file

@ -107,7 +107,7 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
break; break;
case MessageKind.rejectRequest: case MessageKind.rejectRequest:
await twonlyDB.contactsDao.deleteContactByUserId(fromUserId); await deleteContact(fromUserId);
break; break;
case MessageKind.acceptRequest: case MessageKind.acceptRequest:

View file

@ -1,10 +1,15 @@
import 'package:fixnum/fixnum.dart'; import 'package:fixnum/fixnum.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/model/protobuf/api/client_to_server.pb.dart' import 'package:twonly/src/model/protobuf/api/client_to_server.pb.dart'
as client; as client;
import 'package:twonly/src/model/protobuf/api/client_to_server.pbserver.dart'; import 'package:twonly/src/model/protobuf/api/client_to_server.pbserver.dart';
import 'package:twonly/src/model/protobuf/api/error.pb.dart'; import 'package:twonly/src/model/protobuf/api/error.pb.dart';
import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart' import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart'
as server; as server;
import 'package:twonly/src/services/api/messages.dart';
import 'package:twonly/src/services/signal/session.signal.dart';
class Result<T, E> { class Result<T, E> {
final T? value; final T? value;
@ -42,3 +47,22 @@ ClientToServer createClientToServerFromApplicationData(
..applicationdata = applicationData; ..applicationdata = applicationData;
return ClientToServer()..v0 = v0; return ClientToServer()..v0 = v0;
} }
Future deleteContact(int contactId) async {
await twonlyDB.messagesDao.deleteAllMessagesByContactId(contactId);
await twonlyDB.signalDao.deleteAllByContactId(contactId);
await deleteSessionWithTarget(contactId);
await twonlyDB.contactsDao.deleteContactByUserId(contactId);
}
Future rejectUser(int contactId) async {
await encryptAndSendMessageAsync(
null,
contactId,
MessageJson(
kind: MessageKind.rejectRequest,
timestamp: DateTime.now(),
content: MessageContent(),
),
);
}

View file

@ -77,6 +77,13 @@ Future<bool> createNewSignalSession(Response_UserData userData) async {
} }
} }
Future deleteSessionWithTarget(int target) async {
ConnectSignalProtocolStore? signalStore = await getSignalStore();
if (signalStore == null) return;
final address = SignalProtocolAddress(target.toString(), defaultDeviceId);
await signalStore.sessionStore.deleteSession(address);
}
Future<Fingerprint?> generateSessionFingerPrint(int target) async { Future<Fingerprint?> generateSessionFingerPrint(int target) async {
ConnectSignalProtocolStore? signalStore = await getSignalStore(); ConnectSignalProtocolStore? signalStore = await getSignalStore();
UserData? user = await getUser(); UserData? user = await getUser();

View file

@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:twonly/src/providers/connection.provider.dart'; import 'package:twonly/src/providers/connection.provider.dart';
import 'package:twonly/src/services/api/utils.dart';
import 'package:twonly/src/services/signal/session.signal.dart'; import 'package:twonly/src/services/signal/session.signal.dart';
import 'package:twonly/src/views/components/alert_dialog.dart'; import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
@ -262,16 +263,8 @@ class _ContactsListViewState extends State<ContactsListView> {
child: IconButton( child: IconButton(
icon: Icon(Icons.close, color: Colors.red), icon: Icon(Icons.close, color: Colors.red),
onPressed: () async { onPressed: () async {
await twonlyDB.contactsDao.deleteContactByUserId(contact.userId); rejectUser(contact.userId);
await encryptAndSendMessageAsync( await deleteContact(contact.userId);
null,
contact.userId,
MessageJson(
kind: MessageKind.rejectRequest,
timestamp: DateTime.now(),
content: MessageContent(),
),
);
}, },
), ),
), ),

View file

@ -363,7 +363,9 @@ class _UserListItem extends State<UserListItem> {
title: Text( title: Text(
getContactDisplayName(widget.user), getContactDisplayName(widget.user),
), ),
subtitle: (currentMessage == null) subtitle: (widget.user.deleted)
? Text(context.lang.userDeletedAccount)
: (currentMessage == null)
? Text(context.lang.chatsTapToSend) ? Text(context.lang.chatsTapToSend)
: Row( : Row(
children: [ children: [
@ -383,7 +385,9 @@ class _UserListItem extends State<UserListItem> {
], ],
), ),
leading: ContactAvatar(contact: widget.user), leading: ContactAvatar(contact: widget.user),
trailing: IconButton( trailing: (widget.user.deleted)
? null
: IconButton(
onPressed: () { onPressed: () {
Navigator.push(context, MaterialPageRoute( Navigator.push(context, MaterialPageRoute(
builder: (context) { builder: (context) {

View file

@ -42,7 +42,7 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
HashSet<int> alreadyReportedOpened = HashSet<int>(); HashSet<int> alreadyReportedOpened = HashSet<int>();
late Contact user; late Contact user;
String currentInputText = ""; String currentInputText = "";
late StreamSubscription<Contact> userSub; late StreamSubscription<Contact?> userSub;
late StreamSubscription<List<Message>> messageSub; late StreamSubscription<List<Message>> messageSub;
List<Message> messages = []; List<Message> messages = [];
List<MemoryItem> galleryItems = []; List<MemoryItem> galleryItems = [];
@ -75,9 +75,10 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
Future initStreams() async { Future initStreams() async {
await twonlyDB.messagesDao.removeOldMessages(); await twonlyDB.messagesDao.removeOldMessages();
Stream<Contact> contact = Stream<Contact?> contact =
twonlyDB.contactsDao.watchContact(widget.contact.userId); twonlyDB.contactsDao.watchContact(widget.contact.userId);
userSub = contact.listen((contact) { userSub = contact.listen((contact) {
if (contact == null) return;
setState(() { setState(() {
user = contact; user = contact;
}); });
@ -336,7 +337,7 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
}, },
), ),
), ),
if (responseToMessage != null) if (responseToMessage != null && !user.deleted)
Container( Container(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
bottom: 00, bottom: 00,
@ -369,7 +370,9 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
top: 10, top: 10,
), ),
child: Row( child: Row(
children: [ children: (user.deleted)
? []
: [
Expanded( Expanded(
child: TextField( child: TextField(
controller: newMessageController, controller: newMessageController,

View file

@ -30,7 +30,7 @@ class _StartNewChatView extends State<StartNewChatView> {
super.initState(); super.initState();
Stream<List<Contact>> stream = Stream<List<Contact>> stream =
twonlyDB.contactsDao.watchContactsForShareView(); twonlyDB.contactsDao.watchContactsForStartNewChat();
contactSub = stream.listen((update) { contactSub = stream.listen((update) {
update.sort((a, b) => update.sort((a, b) =>

View file

@ -1,6 +1,7 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/services/api/utils.dart';
import 'package:twonly/src/views/components/alert_dialog.dart'; import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/views/components/better_list_title.dart'; import 'package:twonly/src/views/components/better_list_title.dart';
import 'package:twonly/src/views/components/flame.dart'; import 'package:twonly/src/views/components/flame.dart';
@ -22,6 +23,39 @@ class ContactView extends StatefulWidget {
} }
class _ContactViewState extends State<ContactView> { class _ContactViewState extends State<ContactView> {
Future handleUserRemoveRequest(Contact contact) async {
bool remove = await showAlertDialog(
context,
context.lang.contactRemoveTitle(getContactDisplayName(contact)),
context.lang.contactRemoveBody,
);
if (remove) {
// trigger deletion for the other user...
rejectUser(contact.userId);
await deleteContact(contact.userId);
if (mounted) {
Navigator.popUntil(context, (route) => route.isFirst);
}
}
}
Future handleUserBlockRequest(Contact contact) async {
bool block = await showAlertDialog(
context,
context.lang.contactBlockTitle(getContactDisplayName(contact)),
context.lang.contactBlockBody,
);
if (block) {
final update = ContactsCompanion(blocked: Value(true));
if (context.mounted) {
await twonlyDB.contactsDao.updateContact(contact.userId, update);
}
if (context.mounted) {
Navigator.popUntil(context, (route) => route.isFirst);
}
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Stream<Contact?> contact = twonlyDB.contactsDao Stream<Contact?> contact = twonlyDB.contactsDao
@ -93,7 +127,8 @@ class _ContactViewState extends State<ContactView> {
}, },
), ),
BetterListTile( BetterListTile(
icon: FontAwesomeIcons.trashCan, icon: FontAwesomeIcons.eraser,
iconSize: 16,
text: context.lang.deleteAllContactMessages, text: context.lang.deleteAllContactMessages,
onTap: () async { onTap: () async {
bool block = await showAlertDialog( bool block = await showAlertDialog(
@ -114,24 +149,14 @@ class _ContactViewState extends State<ContactView> {
icon: FontAwesomeIcons.ban, icon: FontAwesomeIcons.ban,
color: Colors.red, color: Colors.red,
text: context.lang.contactBlock, text: context.lang.contactBlock,
onTap: () async { onTap: () => handleUserBlockRequest(contact),
bool block = await showAlertDialog( ),
context, BetterListTile(
context.lang icon: FontAwesomeIcons.userMinus,
.contactBlockTitle(getContactDisplayName(contact)), iconSize: 16,
context.lang.contactBlockBody, color: Colors.red,
); text: context.lang.contactRemove,
if (block) { onTap: () => handleUserRemoveRequest(contact),
final update = ContactsCompanion(blocked: Value(true));
if (context.mounted) {
await twonlyDB.contactsDao
.updateContact(contact.userId, update);
}
if (context.mounted) {
Navigator.popUntil(context, (route) => route.isFirst);
}
}
},
), ),
], ],
); );

View file

@ -95,6 +95,15 @@ class _AccountViewState extends State<AccountView> {
.settingsAccountDeleteAccountWithBallance( .settingsAccountDeleteAccountWithBallance(
formattedBallance!)) formattedBallance!))
: Text(context.lang.settingsAccountDeleteAccountNoBallance), : Text(context.lang.settingsAccountDeleteAccountNoBallance),
onLongPress: (kDebugMode)
? () async {
await deleteLocalUserData();
Restart.restartApp(
notificationTitle: 'Account successfully deleted',
notificationBody: 'Click here to open the app again',
);
}
: null,
onTap: (formattedBallance == null) onTap: (formattedBallance == null)
? null ? null
: () async { : () async {

View file

@ -72,6 +72,13 @@ class Contacts extends Table with TableInfo<Contacts, ContactsData> {
defaultConstraints: defaultConstraints:
GeneratedColumn.constraintIsAlways('CHECK ("pinned" IN (0, 1))'), GeneratedColumn.constraintIsAlways('CHECK ("pinned" IN (0, 1))'),
defaultValue: const CustomExpression('0')); defaultValue: const CustomExpression('0'));
late final GeneratedColumn<bool> deleted = GeneratedColumn<bool>(
'deleted', aliasedName, false,
type: DriftSqlType.bool,
requiredDuringInsert: false,
defaultConstraints:
GeneratedColumn.constraintIsAlways('CHECK ("deleted" IN (0, 1))'),
defaultValue: const CustomExpression('0'));
late final GeneratedColumn<bool> alsoBestFriend = GeneratedColumn<bool>( late final GeneratedColumn<bool> alsoBestFriend = GeneratedColumn<bool>(
'also_best_friend', aliasedName, false, 'also_best_friend', aliasedName, false,
type: DriftSqlType.bool, type: DriftSqlType.bool,
@ -133,6 +140,7 @@ class Contacts extends Table with TableInfo<Contacts, ContactsData> {
verified, verified,
archived, archived,
pinned, pinned,
deleted,
alsoBestFriend, alsoBestFriend,
deleteMessagesAfterXMinutes, deleteMessagesAfterXMinutes,
createdAt, createdAt,
@ -179,6 +187,8 @@ class Contacts extends Table with TableInfo<Contacts, ContactsData> {
.read(DriftSqlType.bool, data['${effectivePrefix}archived'])!, .read(DriftSqlType.bool, data['${effectivePrefix}archived'])!,
pinned: attachedDatabase.typeMapping pinned: attachedDatabase.typeMapping
.read(DriftSqlType.bool, data['${effectivePrefix}pinned'])!, .read(DriftSqlType.bool, data['${effectivePrefix}pinned'])!,
deleted: attachedDatabase.typeMapping
.read(DriftSqlType.bool, data['${effectivePrefix}deleted'])!,
alsoBestFriend: attachedDatabase.typeMapping alsoBestFriend: attachedDatabase.typeMapping
.read(DriftSqlType.bool, data['${effectivePrefix}also_best_friend'])!, .read(DriftSqlType.bool, data['${effectivePrefix}also_best_friend'])!,
deleteMessagesAfterXMinutes: attachedDatabase.typeMapping.read( deleteMessagesAfterXMinutes: attachedDatabase.typeMapping.read(
@ -225,6 +235,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
final bool verified; final bool verified;
final bool archived; final bool archived;
final bool pinned; final bool pinned;
final bool deleted;
final bool alsoBestFriend; final bool alsoBestFriend;
final int deleteMessagesAfterXMinutes; final int deleteMessagesAfterXMinutes;
final DateTime createdAt; final DateTime createdAt;
@ -248,6 +259,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
required this.verified, required this.verified,
required this.archived, required this.archived,
required this.pinned, required this.pinned,
required this.deleted,
required this.alsoBestFriend, required this.alsoBestFriend,
required this.deleteMessagesAfterXMinutes, required this.deleteMessagesAfterXMinutes,
required this.createdAt, required this.createdAt,
@ -279,6 +291,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
map['verified'] = Variable<bool>(verified); map['verified'] = Variable<bool>(verified);
map['archived'] = Variable<bool>(archived); map['archived'] = Variable<bool>(archived);
map['pinned'] = Variable<bool>(pinned); map['pinned'] = Variable<bool>(pinned);
map['deleted'] = Variable<bool>(deleted);
map['also_best_friend'] = Variable<bool>(alsoBestFriend); map['also_best_friend'] = Variable<bool>(alsoBestFriend);
map['delete_messages_after_x_minutes'] = map['delete_messages_after_x_minutes'] =
Variable<int>(deleteMessagesAfterXMinutes); Variable<int>(deleteMessagesAfterXMinutes);
@ -322,6 +335,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
verified: Value(verified), verified: Value(verified),
archived: Value(archived), archived: Value(archived),
pinned: Value(pinned), pinned: Value(pinned),
deleted: Value(deleted),
alsoBestFriend: Value(alsoBestFriend), alsoBestFriend: Value(alsoBestFriend),
deleteMessagesAfterXMinutes: Value(deleteMessagesAfterXMinutes), deleteMessagesAfterXMinutes: Value(deleteMessagesAfterXMinutes),
createdAt: Value(createdAt), createdAt: Value(createdAt),
@ -359,6 +373,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
verified: serializer.fromJson<bool>(json['verified']), verified: serializer.fromJson<bool>(json['verified']),
archived: serializer.fromJson<bool>(json['archived']), archived: serializer.fromJson<bool>(json['archived']),
pinned: serializer.fromJson<bool>(json['pinned']), pinned: serializer.fromJson<bool>(json['pinned']),
deleted: serializer.fromJson<bool>(json['deleted']),
alsoBestFriend: serializer.fromJson<bool>(json['alsoBestFriend']), alsoBestFriend: serializer.fromJson<bool>(json['alsoBestFriend']),
deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes:
serializer.fromJson<int>(json['deleteMessagesAfterXMinutes']), serializer.fromJson<int>(json['deleteMessagesAfterXMinutes']),
@ -391,6 +406,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
'verified': serializer.toJson<bool>(verified), 'verified': serializer.toJson<bool>(verified),
'archived': serializer.toJson<bool>(archived), 'archived': serializer.toJson<bool>(archived),
'pinned': serializer.toJson<bool>(pinned), 'pinned': serializer.toJson<bool>(pinned),
'deleted': serializer.toJson<bool>(deleted),
'alsoBestFriend': serializer.toJson<bool>(alsoBestFriend), 'alsoBestFriend': serializer.toJson<bool>(alsoBestFriend),
'deleteMessagesAfterXMinutes': 'deleteMessagesAfterXMinutes':
serializer.toJson<int>(deleteMessagesAfterXMinutes), serializer.toJson<int>(deleteMessagesAfterXMinutes),
@ -419,6 +435,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
bool? verified, bool? verified,
bool? archived, bool? archived,
bool? pinned, bool? pinned,
bool? deleted,
bool? alsoBestFriend, bool? alsoBestFriend,
int? deleteMessagesAfterXMinutes, int? deleteMessagesAfterXMinutes,
DateTime? createdAt, DateTime? createdAt,
@ -442,6 +459,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
verified: verified ?? this.verified, verified: verified ?? this.verified,
archived: archived ?? this.archived, archived: archived ?? this.archived,
pinned: pinned ?? this.pinned, pinned: pinned ?? this.pinned,
deleted: deleted ?? this.deleted,
alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend,
deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes:
deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes, deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes,
@ -478,6 +496,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
verified: data.verified.present ? data.verified.value : this.verified, verified: data.verified.present ? data.verified.value : this.verified,
archived: data.archived.present ? data.archived.value : this.archived, archived: data.archived.present ? data.archived.value : this.archived,
pinned: data.pinned.present ? data.pinned.value : this.pinned, pinned: data.pinned.present ? data.pinned.value : this.pinned,
deleted: data.deleted.present ? data.deleted.value : this.deleted,
alsoBestFriend: data.alsoBestFriend.present alsoBestFriend: data.alsoBestFriend.present
? data.alsoBestFriend.value ? data.alsoBestFriend.value
: this.alsoBestFriend, : this.alsoBestFriend,
@ -524,6 +543,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
..write('verified: $verified, ') ..write('verified: $verified, ')
..write('archived: $archived, ') ..write('archived: $archived, ')
..write('pinned: $pinned, ') ..write('pinned: $pinned, ')
..write('deleted: $deleted, ')
..write('alsoBestFriend: $alsoBestFriend, ') ..write('alsoBestFriend: $alsoBestFriend, ')
..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ') ..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ')
..write('createdAt: $createdAt, ') ..write('createdAt: $createdAt, ')
@ -552,6 +572,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
verified, verified,
archived, archived,
pinned, pinned,
deleted,
alsoBestFriend, alsoBestFriend,
deleteMessagesAfterXMinutes, deleteMessagesAfterXMinutes,
createdAt, createdAt,
@ -579,6 +600,7 @@ class ContactsData extends DataClass implements Insertable<ContactsData> {
other.verified == this.verified && other.verified == this.verified &&
other.archived == this.archived && other.archived == this.archived &&
other.pinned == this.pinned && other.pinned == this.pinned &&
other.deleted == this.deleted &&
other.alsoBestFriend == this.alsoBestFriend && other.alsoBestFriend == this.alsoBestFriend &&
other.deleteMessagesAfterXMinutes == other.deleteMessagesAfterXMinutes ==
this.deleteMessagesAfterXMinutes && this.deleteMessagesAfterXMinutes &&
@ -605,6 +627,7 @@ class ContactsCompanion extends UpdateCompanion<ContactsData> {
final Value<bool> verified; final Value<bool> verified;
final Value<bool> archived; final Value<bool> archived;
final Value<bool> pinned; final Value<bool> pinned;
final Value<bool> deleted;
final Value<bool> alsoBestFriend; final Value<bool> alsoBestFriend;
final Value<int> deleteMessagesAfterXMinutes; final Value<int> deleteMessagesAfterXMinutes;
final Value<DateTime> createdAt; final Value<DateTime> createdAt;
@ -628,6 +651,7 @@ class ContactsCompanion extends UpdateCompanion<ContactsData> {
this.verified = const Value.absent(), this.verified = const Value.absent(),
this.archived = const Value.absent(), this.archived = const Value.absent(),
this.pinned = const Value.absent(), this.pinned = const Value.absent(),
this.deleted = const Value.absent(),
this.alsoBestFriend = const Value.absent(), this.alsoBestFriend = const Value.absent(),
this.deleteMessagesAfterXMinutes = const Value.absent(), this.deleteMessagesAfterXMinutes = const Value.absent(),
this.createdAt = const Value.absent(), this.createdAt = const Value.absent(),
@ -652,6 +676,7 @@ class ContactsCompanion extends UpdateCompanion<ContactsData> {
this.verified = const Value.absent(), this.verified = const Value.absent(),
this.archived = const Value.absent(), this.archived = const Value.absent(),
this.pinned = const Value.absent(), this.pinned = const Value.absent(),
this.deleted = const Value.absent(),
this.alsoBestFriend = const Value.absent(), this.alsoBestFriend = const Value.absent(),
this.deleteMessagesAfterXMinutes = const Value.absent(), this.deleteMessagesAfterXMinutes = const Value.absent(),
this.createdAt = const Value.absent(), this.createdAt = const Value.absent(),
@ -676,6 +701,7 @@ class ContactsCompanion extends UpdateCompanion<ContactsData> {
Expression<bool>? verified, Expression<bool>? verified,
Expression<bool>? archived, Expression<bool>? archived,
Expression<bool>? pinned, Expression<bool>? pinned,
Expression<bool>? deleted,
Expression<bool>? alsoBestFriend, Expression<bool>? alsoBestFriend,
Expression<int>? deleteMessagesAfterXMinutes, Expression<int>? deleteMessagesAfterXMinutes,
Expression<DateTime>? createdAt, Expression<DateTime>? createdAt,
@ -700,6 +726,7 @@ class ContactsCompanion extends UpdateCompanion<ContactsData> {
if (verified != null) 'verified': verified, if (verified != null) 'verified': verified,
if (archived != null) 'archived': archived, if (archived != null) 'archived': archived,
if (pinned != null) 'pinned': pinned, if (pinned != null) 'pinned': pinned,
if (deleted != null) 'deleted': deleted,
if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend, if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend,
if (deleteMessagesAfterXMinutes != null) if (deleteMessagesAfterXMinutes != null)
'delete_messages_after_x_minutes': deleteMessagesAfterXMinutes, 'delete_messages_after_x_minutes': deleteMessagesAfterXMinutes,
@ -730,6 +757,7 @@ class ContactsCompanion extends UpdateCompanion<ContactsData> {
Value<bool>? verified, Value<bool>? verified,
Value<bool>? archived, Value<bool>? archived,
Value<bool>? pinned, Value<bool>? pinned,
Value<bool>? deleted,
Value<bool>? alsoBestFriend, Value<bool>? alsoBestFriend,
Value<int>? deleteMessagesAfterXMinutes, Value<int>? deleteMessagesAfterXMinutes,
Value<DateTime>? createdAt, Value<DateTime>? createdAt,
@ -753,6 +781,7 @@ class ContactsCompanion extends UpdateCompanion<ContactsData> {
verified: verified ?? this.verified, verified: verified ?? this.verified,
archived: archived ?? this.archived, archived: archived ?? this.archived,
pinned: pinned ?? this.pinned, pinned: pinned ?? this.pinned,
deleted: deleted ?? this.deleted,
alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend,
deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes:
deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes, deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes,
@ -807,6 +836,9 @@ class ContactsCompanion extends UpdateCompanion<ContactsData> {
if (pinned.present) { if (pinned.present) {
map['pinned'] = Variable<bool>(pinned.value); map['pinned'] = Variable<bool>(pinned.value);
} }
if (deleted.present) {
map['deleted'] = Variable<bool>(deleted.value);
}
if (alsoBestFriend.present) { if (alsoBestFriend.present) {
map['also_best_friend'] = Variable<bool>(alsoBestFriend.value); map['also_best_friend'] = Variable<bool>(alsoBestFriend.value);
} }
@ -859,6 +891,7 @@ class ContactsCompanion extends UpdateCompanion<ContactsData> {
..write('verified: $verified, ') ..write('verified: $verified, ')
..write('archived: $archived, ') ..write('archived: $archived, ')
..write('pinned: $pinned, ') ..write('pinned: $pinned, ')
..write('deleted: $deleted, ')
..write('alsoBestFriend: $alsoBestFriend, ') ..write('alsoBestFriend: $alsoBestFriend, ')
..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ') ..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ')
..write('createdAt: $createdAt, ') ..write('createdAt: $createdAt, ')
@ -3176,7 +3209,7 @@ class SignalContactSignedPreKeys extends Table
SignalContactSignedPreKeys(this.attachedDatabase, [this._alias]); SignalContactSignedPreKeys(this.attachedDatabase, [this._alias]);
late final GeneratedColumn<int> contactId = GeneratedColumn<int>( late final GeneratedColumn<int> contactId = GeneratedColumn<int>(
'contact_id', aliasedName, false, 'contact_id', aliasedName, false,
type: DriftSqlType.int, requiredDuringInsert: true); type: DriftSqlType.int, requiredDuringInsert: false);
late final GeneratedColumn<int> signedPreKeyId = GeneratedColumn<int>( late final GeneratedColumn<int> signedPreKeyId = GeneratedColumn<int>(
'signed_pre_key_id', aliasedName, false, 'signed_pre_key_id', aliasedName, false,
type: DriftSqlType.int, requiredDuringInsert: true); type: DriftSqlType.int, requiredDuringInsert: true);
@ -3206,7 +3239,7 @@ class SignalContactSignedPreKeys extends Table
String get actualTableName => $name; String get actualTableName => $name;
static const String $name = 'signal_contact_signed_pre_keys'; static const String $name = 'signal_contact_signed_pre_keys';
@override @override
Set<GeneratedColumn> get $primaryKey => {contactId, signedPreKeyId}; Set<GeneratedColumn> get $primaryKey => {contactId};
@override @override
SignalContactSignedPreKeysData map(Map<String, dynamic> data, SignalContactSignedPreKeysData map(Map<String, dynamic> data,
{String? tablePrefix}) { {String? tablePrefix}) {
@ -3361,24 +3394,20 @@ class SignalContactSignedPreKeysCompanion
final Value<Uint8List> signedPreKey; final Value<Uint8List> signedPreKey;
final Value<Uint8List> signedPreKeySignature; final Value<Uint8List> signedPreKeySignature;
final Value<DateTime> createdAt; final Value<DateTime> createdAt;
final Value<int> rowid;
const SignalContactSignedPreKeysCompanion({ const SignalContactSignedPreKeysCompanion({
this.contactId = const Value.absent(), this.contactId = const Value.absent(),
this.signedPreKeyId = const Value.absent(), this.signedPreKeyId = const Value.absent(),
this.signedPreKey = const Value.absent(), this.signedPreKey = const Value.absent(),
this.signedPreKeySignature = const Value.absent(), this.signedPreKeySignature = const Value.absent(),
this.createdAt = const Value.absent(), this.createdAt = const Value.absent(),
this.rowid = const Value.absent(),
}); });
SignalContactSignedPreKeysCompanion.insert({ SignalContactSignedPreKeysCompanion.insert({
required int contactId, this.contactId = const Value.absent(),
required int signedPreKeyId, required int signedPreKeyId,
required Uint8List signedPreKey, required Uint8List signedPreKey,
required Uint8List signedPreKeySignature, required Uint8List signedPreKeySignature,
this.createdAt = const Value.absent(), this.createdAt = const Value.absent(),
this.rowid = const Value.absent(), }) : signedPreKeyId = Value(signedPreKeyId),
}) : contactId = Value(contactId),
signedPreKeyId = Value(signedPreKeyId),
signedPreKey = Value(signedPreKey), signedPreKey = Value(signedPreKey),
signedPreKeySignature = Value(signedPreKeySignature); signedPreKeySignature = Value(signedPreKeySignature);
static Insertable<SignalContactSignedPreKeysData> custom({ static Insertable<SignalContactSignedPreKeysData> custom({
@ -3387,7 +3416,6 @@ class SignalContactSignedPreKeysCompanion
Expression<Uint8List>? signedPreKey, Expression<Uint8List>? signedPreKey,
Expression<Uint8List>? signedPreKeySignature, Expression<Uint8List>? signedPreKeySignature,
Expression<DateTime>? createdAt, Expression<DateTime>? createdAt,
Expression<int>? rowid,
}) { }) {
return RawValuesInsertable({ return RawValuesInsertable({
if (contactId != null) 'contact_id': contactId, if (contactId != null) 'contact_id': contactId,
@ -3396,7 +3424,6 @@ class SignalContactSignedPreKeysCompanion
if (signedPreKeySignature != null) if (signedPreKeySignature != null)
'signed_pre_key_signature': signedPreKeySignature, 'signed_pre_key_signature': signedPreKeySignature,
if (createdAt != null) 'created_at': createdAt, if (createdAt != null) 'created_at': createdAt,
if (rowid != null) 'rowid': rowid,
}); });
} }
@ -3405,8 +3432,7 @@ class SignalContactSignedPreKeysCompanion
Value<int>? signedPreKeyId, Value<int>? signedPreKeyId,
Value<Uint8List>? signedPreKey, Value<Uint8List>? signedPreKey,
Value<Uint8List>? signedPreKeySignature, Value<Uint8List>? signedPreKeySignature,
Value<DateTime>? createdAt, Value<DateTime>? createdAt}) {
Value<int>? rowid}) {
return SignalContactSignedPreKeysCompanion( return SignalContactSignedPreKeysCompanion(
contactId: contactId ?? this.contactId, contactId: contactId ?? this.contactId,
signedPreKeyId: signedPreKeyId ?? this.signedPreKeyId, signedPreKeyId: signedPreKeyId ?? this.signedPreKeyId,
@ -3414,7 +3440,6 @@ class SignalContactSignedPreKeysCompanion
signedPreKeySignature: signedPreKeySignature:
signedPreKeySignature ?? this.signedPreKeySignature, signedPreKeySignature ?? this.signedPreKeySignature,
createdAt: createdAt ?? this.createdAt, createdAt: createdAt ?? this.createdAt,
rowid: rowid ?? this.rowid,
); );
} }
@ -3437,9 +3462,6 @@ class SignalContactSignedPreKeysCompanion
if (createdAt.present) { if (createdAt.present) {
map['created_at'] = Variable<DateTime>(createdAt.value); map['created_at'] = Variable<DateTime>(createdAt.value);
} }
if (rowid.present) {
map['rowid'] = Variable<int>(rowid.value);
}
return map; return map;
} }
@ -3450,8 +3472,7 @@ class SignalContactSignedPreKeysCompanion
..write('signedPreKeyId: $signedPreKeyId, ') ..write('signedPreKeyId: $signedPreKeyId, ')
..write('signedPreKey: $signedPreKey, ') ..write('signedPreKey: $signedPreKey, ')
..write('signedPreKeySignature: $signedPreKeySignature, ') ..write('signedPreKeySignature: $signedPreKeySignature, ')
..write('createdAt: $createdAt, ') ..write('createdAt: $createdAt')
..write('rowid: $rowid')
..write(')')) ..write(')'))
.toString(); .toString();
} }

File diff suppressed because it is too large Load diff