This commit is contained in:
otsmr 2025-05-11 20:37:22 +02:00
parent 5309f0a738
commit eedf6e0646
21 changed files with 3511 additions and 69 deletions

File diff suppressed because one or more lines are too long

View file

@ -19,6 +19,7 @@ import 'dart:async';
// this callback is called by the apiProvider
Function(bool) globalCallbackConnectionState = (a) {};
bool globalIsAppInBackground = true;
int globalBestFriendUserId = -1;
// these two callbacks are called on updated to the corresponding database
@ -50,7 +51,18 @@ class _AppState extends State<App> with WidgetsBindingObserver {
Future setUserPlan() async {
final user = await getUser();
globalBestFriendUserId = -1;
if (user != null && context.mounted) {
if (user.myBestFriendContactId != null) {
final contact = await twonlyDatabase.contactsDao
.getContactByUserId(user.myBestFriendContactId!)
.getSingleOrNull();
if (contact != null) {
if (contact.alsoBestFriend) {
globalBestFriendUserId = user.myBestFriendContactId ?? 0;
}
}
}
context.read<CustomChangeProvider>().updatePlan(user.subscriptionPlan);
}
}

View file

@ -16,6 +16,7 @@ class Contacts extends Table {
BoolColumn get verified => boolean().withDefault(Constant(false))();
BoolColumn get archived => boolean().withDefault(Constant(false))();
BoolColumn get pinned => boolean().withDefault(Constant(false))();
BoolColumn get alsoBestFriend => boolean().withDefault(Constant(false))();
IntColumn get deleteMessagesAfterXMinutes =>
integer().withDefault(Constant(60 * 24))();
@ -27,6 +28,7 @@ class Contacts extends Table {
DateTimeColumn get lastMessageSend => dateTime().nullable()();
DateTimeColumn get lastMessageReceived => dateTime().nullable()();
DateTimeColumn get lastFlameCounterChange => dateTime().nullable()();
DateTimeColumn get lastFlameSync => dateTime().nullable()();
DateTimeColumn get lastMessageExchange =>
dateTime().withDefault(currentDateAndTime)();

View file

@ -10,6 +10,7 @@ enum MessageKind {
profileChange,
rejectRequest,
acceptRequest,
flameSync,
opened,
ack,
pushKey

View file

@ -43,7 +43,7 @@ class TwonlyDatabase extends _$TwonlyDatabase {
TwonlyDatabase.forTesting(DatabaseConnection super.connection);
@override
int get schemaVersion => 7;
int get schemaVersion => 8;
static QueryExecutor _openConnection() {
return driftDatabase(
@ -80,6 +80,10 @@ class TwonlyDatabase extends _$TwonlyDatabase {
from6To7: (m, schema) async {
m.addColumn(schema.contacts, schema.contacts.pinned);
},
from7To8: (m, schema) async {
m.addColumn(schema.contacts, schema.contacts.alsoBestFriend);
m.addColumn(schema.contacts, schema.contacts.lastFlameSync);
},
),
);
}

View file

@ -106,6 +106,16 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
defaultConstraints:
GeneratedColumn.constraintIsAlways('CHECK ("pinned" IN (0, 1))'),
defaultValue: Constant(false));
static const VerificationMeta _alsoBestFriendMeta =
const VerificationMeta('alsoBestFriend');
@override
late final GeneratedColumn<bool> alsoBestFriend = GeneratedColumn<bool>(
'also_best_friend', aliasedName, false,
type: DriftSqlType.bool,
requiredDuringInsert: false,
defaultConstraints: GeneratedColumn.constraintIsAlways(
'CHECK ("also_best_friend" IN (0, 1))'),
defaultValue: Constant(false));
static const VerificationMeta _deleteMessagesAfterXMinutesMeta =
const VerificationMeta('deleteMessagesAfterXMinutes');
@override
@ -149,6 +159,12 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
late final GeneratedColumn<DateTime> lastFlameCounterChange =
GeneratedColumn<DateTime>('last_flame_counter_change', aliasedName, true,
type: DriftSqlType.dateTime, requiredDuringInsert: false);
static const VerificationMeta _lastFlameSyncMeta =
const VerificationMeta('lastFlameSync');
@override
late final GeneratedColumn<DateTime> lastFlameSync =
GeneratedColumn<DateTime>('last_flame_sync', aliasedName, true,
type: DriftSqlType.dateTime, requiredDuringInsert: false);
static const VerificationMeta _lastMessageExchangeMeta =
const VerificationMeta('lastMessageExchange');
@override
@ -179,12 +195,14 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
verified,
archived,
pinned,
alsoBestFriend,
deleteMessagesAfterXMinutes,
createdAt,
totalMediaCounter,
lastMessageSend,
lastMessageReceived,
lastFlameCounterChange,
lastFlameSync,
lastMessageExchange,
flameCounter
];
@ -252,6 +270,12 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
context.handle(_pinnedMeta,
pinned.isAcceptableOrUnknown(data['pinned']!, _pinnedMeta));
}
if (data.containsKey('also_best_friend')) {
context.handle(
_alsoBestFriendMeta,
alsoBestFriend.isAcceptableOrUnknown(
data['also_best_friend']!, _alsoBestFriendMeta));
}
if (data.containsKey('delete_messages_after_x_minutes')) {
context.handle(
_deleteMessagesAfterXMinutesMeta,
@ -287,6 +311,12 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
lastFlameCounterChange.isAcceptableOrUnknown(
data['last_flame_counter_change']!, _lastFlameCounterChangeMeta));
}
if (data.containsKey('last_flame_sync')) {
context.handle(
_lastFlameSyncMeta,
lastFlameSync.isAcceptableOrUnknown(
data['last_flame_sync']!, _lastFlameSyncMeta));
}
if (data.containsKey('last_message_exchange')) {
context.handle(
_lastMessageExchangeMeta,
@ -332,6 +362,8 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
.read(DriftSqlType.bool, data['${effectivePrefix}archived'])!,
pinned: attachedDatabase.typeMapping
.read(DriftSqlType.bool, data['${effectivePrefix}pinned'])!,
alsoBestFriend: attachedDatabase.typeMapping
.read(DriftSqlType.bool, data['${effectivePrefix}also_best_friend'])!,
deleteMessagesAfterXMinutes: attachedDatabase.typeMapping.read(
DriftSqlType.int,
data['${effectivePrefix}delete_messages_after_x_minutes'])!,
@ -347,6 +379,8 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
lastFlameCounterChange: attachedDatabase.typeMapping.read(
DriftSqlType.dateTime,
data['${effectivePrefix}last_flame_counter_change']),
lastFlameSync: attachedDatabase.typeMapping.read(
DriftSqlType.dateTime, data['${effectivePrefix}last_flame_sync']),
lastMessageExchange: attachedDatabase.typeMapping.read(
DriftSqlType.dateTime,
data['${effectivePrefix}last_message_exchange'])!,
@ -374,12 +408,14 @@ class Contact extends DataClass implements Insertable<Contact> {
final bool verified;
final bool archived;
final bool pinned;
final bool alsoBestFriend;
final int deleteMessagesAfterXMinutes;
final DateTime createdAt;
final int totalMediaCounter;
final DateTime? lastMessageSend;
final DateTime? lastMessageReceived;
final DateTime? lastFlameCounterChange;
final DateTime? lastFlameSync;
final DateTime lastMessageExchange;
final int flameCounter;
const Contact(
@ -395,12 +431,14 @@ class Contact extends DataClass implements Insertable<Contact> {
required this.verified,
required this.archived,
required this.pinned,
required this.alsoBestFriend,
required this.deleteMessagesAfterXMinutes,
required this.createdAt,
required this.totalMediaCounter,
this.lastMessageSend,
this.lastMessageReceived,
this.lastFlameCounterChange,
this.lastFlameSync,
required this.lastMessageExchange,
required this.flameCounter});
@override
@ -424,6 +462,7 @@ class Contact extends DataClass implements Insertable<Contact> {
map['verified'] = Variable<bool>(verified);
map['archived'] = Variable<bool>(archived);
map['pinned'] = Variable<bool>(pinned);
map['also_best_friend'] = Variable<bool>(alsoBestFriend);
map['delete_messages_after_x_minutes'] =
Variable<int>(deleteMessagesAfterXMinutes);
map['created_at'] = Variable<DateTime>(createdAt);
@ -438,6 +477,9 @@ class Contact extends DataClass implements Insertable<Contact> {
map['last_flame_counter_change'] =
Variable<DateTime>(lastFlameCounterChange);
}
if (!nullToAbsent || lastFlameSync != null) {
map['last_flame_sync'] = Variable<DateTime>(lastFlameSync);
}
map['last_message_exchange'] = Variable<DateTime>(lastMessageExchange);
map['flame_counter'] = Variable<int>(flameCounter);
return map;
@ -463,6 +505,7 @@ class Contact extends DataClass implements Insertable<Contact> {
verified: Value(verified),
archived: Value(archived),
pinned: Value(pinned),
alsoBestFriend: Value(alsoBestFriend),
deleteMessagesAfterXMinutes: Value(deleteMessagesAfterXMinutes),
createdAt: Value(createdAt),
totalMediaCounter: Value(totalMediaCounter),
@ -475,6 +518,9 @@ class Contact extends DataClass implements Insertable<Contact> {
lastFlameCounterChange: lastFlameCounterChange == null && nullToAbsent
? const Value.absent()
: Value(lastFlameCounterChange),
lastFlameSync: lastFlameSync == null && nullToAbsent
? const Value.absent()
: Value(lastFlameSync),
lastMessageExchange: Value(lastMessageExchange),
flameCounter: Value(flameCounter),
);
@ -496,6 +542,7 @@ class Contact extends DataClass implements Insertable<Contact> {
verified: serializer.fromJson<bool>(json['verified']),
archived: serializer.fromJson<bool>(json['archived']),
pinned: serializer.fromJson<bool>(json['pinned']),
alsoBestFriend: serializer.fromJson<bool>(json['alsoBestFriend']),
deleteMessagesAfterXMinutes:
serializer.fromJson<int>(json['deleteMessagesAfterXMinutes']),
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
@ -505,6 +552,7 @@ class Contact extends DataClass implements Insertable<Contact> {
serializer.fromJson<DateTime?>(json['lastMessageReceived']),
lastFlameCounterChange:
serializer.fromJson<DateTime?>(json['lastFlameCounterChange']),
lastFlameSync: serializer.fromJson<DateTime?>(json['lastFlameSync']),
lastMessageExchange:
serializer.fromJson<DateTime>(json['lastMessageExchange']),
flameCounter: serializer.fromJson<int>(json['flameCounter']),
@ -526,6 +574,7 @@ class Contact extends DataClass implements Insertable<Contact> {
'verified': serializer.toJson<bool>(verified),
'archived': serializer.toJson<bool>(archived),
'pinned': serializer.toJson<bool>(pinned),
'alsoBestFriend': serializer.toJson<bool>(alsoBestFriend),
'deleteMessagesAfterXMinutes':
serializer.toJson<int>(deleteMessagesAfterXMinutes),
'createdAt': serializer.toJson<DateTime>(createdAt),
@ -534,6 +583,7 @@ class Contact extends DataClass implements Insertable<Contact> {
'lastMessageReceived': serializer.toJson<DateTime?>(lastMessageReceived),
'lastFlameCounterChange':
serializer.toJson<DateTime?>(lastFlameCounterChange),
'lastFlameSync': serializer.toJson<DateTime?>(lastFlameSync),
'lastMessageExchange': serializer.toJson<DateTime>(lastMessageExchange),
'flameCounter': serializer.toJson<int>(flameCounter),
};
@ -552,12 +602,14 @@ class Contact extends DataClass implements Insertable<Contact> {
bool? verified,
bool? archived,
bool? pinned,
bool? alsoBestFriend,
int? deleteMessagesAfterXMinutes,
DateTime? createdAt,
int? totalMediaCounter,
Value<DateTime?> lastMessageSend = const Value.absent(),
Value<DateTime?> lastMessageReceived = const Value.absent(),
Value<DateTime?> lastFlameCounterChange = const Value.absent(),
Value<DateTime?> lastFlameSync = const Value.absent(),
DateTime? lastMessageExchange,
int? flameCounter}) =>
Contact(
@ -573,6 +625,7 @@ class Contact extends DataClass implements Insertable<Contact> {
verified: verified ?? this.verified,
archived: archived ?? this.archived,
pinned: pinned ?? this.pinned,
alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend,
deleteMessagesAfterXMinutes:
deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes,
createdAt: createdAt ?? this.createdAt,
@ -586,6 +639,8 @@ class Contact extends DataClass implements Insertable<Contact> {
lastFlameCounterChange: lastFlameCounterChange.present
? lastFlameCounterChange.value
: this.lastFlameCounterChange,
lastFlameSync:
lastFlameSync.present ? lastFlameSync.value : this.lastFlameSync,
lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange,
flameCounter: flameCounter ?? this.flameCounter,
);
@ -606,6 +661,9 @@ class Contact extends DataClass implements Insertable<Contact> {
verified: data.verified.present ? data.verified.value : this.verified,
archived: data.archived.present ? data.archived.value : this.archived,
pinned: data.pinned.present ? data.pinned.value : this.pinned,
alsoBestFriend: data.alsoBestFriend.present
? data.alsoBestFriend.value
: this.alsoBestFriend,
deleteMessagesAfterXMinutes: data.deleteMessagesAfterXMinutes.present
? data.deleteMessagesAfterXMinutes.value
: this.deleteMessagesAfterXMinutes,
@ -622,6 +680,9 @@ class Contact extends DataClass implements Insertable<Contact> {
lastFlameCounterChange: data.lastFlameCounterChange.present
? data.lastFlameCounterChange.value
: this.lastFlameCounterChange,
lastFlameSync: data.lastFlameSync.present
? data.lastFlameSync.value
: this.lastFlameSync,
lastMessageExchange: data.lastMessageExchange.present
? data.lastMessageExchange.value
: this.lastMessageExchange,
@ -646,12 +707,14 @@ class Contact extends DataClass implements Insertable<Contact> {
..write('verified: $verified, ')
..write('archived: $archived, ')
..write('pinned: $pinned, ')
..write('alsoBestFriend: $alsoBestFriend, ')
..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ')
..write('createdAt: $createdAt, ')
..write('totalMediaCounter: $totalMediaCounter, ')
..write('lastMessageSend: $lastMessageSend, ')
..write('lastMessageReceived: $lastMessageReceived, ')
..write('lastFlameCounterChange: $lastFlameCounterChange, ')
..write('lastFlameSync: $lastFlameSync, ')
..write('lastMessageExchange: $lastMessageExchange, ')
..write('flameCounter: $flameCounter')
..write(')'))
@ -659,27 +722,30 @@ class Contact extends DataClass implements Insertable<Contact> {
}
@override
int get hashCode => Object.hash(
userId,
username,
displayName,
nickName,
avatarSvg,
myAvatarCounter,
accepted,
requested,
blocked,
verified,
archived,
pinned,
deleteMessagesAfterXMinutes,
createdAt,
totalMediaCounter,
lastMessageSend,
lastMessageReceived,
lastFlameCounterChange,
lastMessageExchange,
flameCounter);
int get hashCode => Object.hashAll([
userId,
username,
displayName,
nickName,
avatarSvg,
myAvatarCounter,
accepted,
requested,
blocked,
verified,
archived,
pinned,
alsoBestFriend,
deleteMessagesAfterXMinutes,
createdAt,
totalMediaCounter,
lastMessageSend,
lastMessageReceived,
lastFlameCounterChange,
lastFlameSync,
lastMessageExchange,
flameCounter
]);
@override
bool operator ==(Object other) =>
identical(this, other) ||
@ -696,6 +762,7 @@ class Contact extends DataClass implements Insertable<Contact> {
other.verified == this.verified &&
other.archived == this.archived &&
other.pinned == this.pinned &&
other.alsoBestFriend == this.alsoBestFriend &&
other.deleteMessagesAfterXMinutes ==
this.deleteMessagesAfterXMinutes &&
other.createdAt == this.createdAt &&
@ -703,6 +770,7 @@ class Contact extends DataClass implements Insertable<Contact> {
other.lastMessageSend == this.lastMessageSend &&
other.lastMessageReceived == this.lastMessageReceived &&
other.lastFlameCounterChange == this.lastFlameCounterChange &&
other.lastFlameSync == this.lastFlameSync &&
other.lastMessageExchange == this.lastMessageExchange &&
other.flameCounter == this.flameCounter);
}
@ -720,12 +788,14 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
final Value<bool> verified;
final Value<bool> archived;
final Value<bool> pinned;
final Value<bool> alsoBestFriend;
final Value<int> deleteMessagesAfterXMinutes;
final Value<DateTime> createdAt;
final Value<int> totalMediaCounter;
final Value<DateTime?> lastMessageSend;
final Value<DateTime?> lastMessageReceived;
final Value<DateTime?> lastFlameCounterChange;
final Value<DateTime?> lastFlameSync;
final Value<DateTime> lastMessageExchange;
final Value<int> flameCounter;
const ContactsCompanion({
@ -741,12 +811,14 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
this.verified = const Value.absent(),
this.archived = const Value.absent(),
this.pinned = const Value.absent(),
this.alsoBestFriend = const Value.absent(),
this.deleteMessagesAfterXMinutes = const Value.absent(),
this.createdAt = const Value.absent(),
this.totalMediaCounter = const Value.absent(),
this.lastMessageSend = const Value.absent(),
this.lastMessageReceived = const Value.absent(),
this.lastFlameCounterChange = const Value.absent(),
this.lastFlameSync = const Value.absent(),
this.lastMessageExchange = const Value.absent(),
this.flameCounter = const Value.absent(),
});
@ -763,12 +835,14 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
this.verified = const Value.absent(),
this.archived = const Value.absent(),
this.pinned = const Value.absent(),
this.alsoBestFriend = const Value.absent(),
this.deleteMessagesAfterXMinutes = const Value.absent(),
this.createdAt = const Value.absent(),
this.totalMediaCounter = const Value.absent(),
this.lastMessageSend = const Value.absent(),
this.lastMessageReceived = const Value.absent(),
this.lastFlameCounterChange = const Value.absent(),
this.lastFlameSync = const Value.absent(),
this.lastMessageExchange = const Value.absent(),
this.flameCounter = const Value.absent(),
}) : username = Value(username);
@ -785,12 +859,14 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
Expression<bool>? verified,
Expression<bool>? archived,
Expression<bool>? pinned,
Expression<bool>? alsoBestFriend,
Expression<int>? deleteMessagesAfterXMinutes,
Expression<DateTime>? createdAt,
Expression<int>? totalMediaCounter,
Expression<DateTime>? lastMessageSend,
Expression<DateTime>? lastMessageReceived,
Expression<DateTime>? lastFlameCounterChange,
Expression<DateTime>? lastFlameSync,
Expression<DateTime>? lastMessageExchange,
Expression<int>? flameCounter,
}) {
@ -807,6 +883,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
if (verified != null) 'verified': verified,
if (archived != null) 'archived': archived,
if (pinned != null) 'pinned': pinned,
if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend,
if (deleteMessagesAfterXMinutes != null)
'delete_messages_after_x_minutes': deleteMessagesAfterXMinutes,
if (createdAt != null) 'created_at': createdAt,
@ -816,6 +893,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
'last_message_received': lastMessageReceived,
if (lastFlameCounterChange != null)
'last_flame_counter_change': lastFlameCounterChange,
if (lastFlameSync != null) 'last_flame_sync': lastFlameSync,
if (lastMessageExchange != null)
'last_message_exchange': lastMessageExchange,
if (flameCounter != null) 'flame_counter': flameCounter,
@ -835,12 +913,14 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
Value<bool>? verified,
Value<bool>? archived,
Value<bool>? pinned,
Value<bool>? alsoBestFriend,
Value<int>? deleteMessagesAfterXMinutes,
Value<DateTime>? createdAt,
Value<int>? totalMediaCounter,
Value<DateTime?>? lastMessageSend,
Value<DateTime?>? lastMessageReceived,
Value<DateTime?>? lastFlameCounterChange,
Value<DateTime?>? lastFlameSync,
Value<DateTime>? lastMessageExchange,
Value<int>? flameCounter}) {
return ContactsCompanion(
@ -856,6 +936,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
verified: verified ?? this.verified,
archived: archived ?? this.archived,
pinned: pinned ?? this.pinned,
alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend,
deleteMessagesAfterXMinutes:
deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes,
createdAt: createdAt ?? this.createdAt,
@ -864,6 +945,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
lastMessageReceived: lastMessageReceived ?? this.lastMessageReceived,
lastFlameCounterChange:
lastFlameCounterChange ?? this.lastFlameCounterChange,
lastFlameSync: lastFlameSync ?? this.lastFlameSync,
lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange,
flameCounter: flameCounter ?? this.flameCounter,
);
@ -908,6 +990,9 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
if (pinned.present) {
map['pinned'] = Variable<bool>(pinned.value);
}
if (alsoBestFriend.present) {
map['also_best_friend'] = Variable<bool>(alsoBestFriend.value);
}
if (deleteMessagesAfterXMinutes.present) {
map['delete_messages_after_x_minutes'] =
Variable<int>(deleteMessagesAfterXMinutes.value);
@ -929,6 +1014,9 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
map['last_flame_counter_change'] =
Variable<DateTime>(lastFlameCounterChange.value);
}
if (lastFlameSync.present) {
map['last_flame_sync'] = Variable<DateTime>(lastFlameSync.value);
}
if (lastMessageExchange.present) {
map['last_message_exchange'] =
Variable<DateTime>(lastMessageExchange.value);
@ -954,12 +1042,14 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
..write('verified: $verified, ')
..write('archived: $archived, ')
..write('pinned: $pinned, ')
..write('alsoBestFriend: $alsoBestFriend, ')
..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ')
..write('createdAt: $createdAt, ')
..write('totalMediaCounter: $totalMediaCounter, ')
..write('lastMessageSend: $lastMessageSend, ')
..write('lastMessageReceived: $lastMessageReceived, ')
..write('lastFlameCounterChange: $lastFlameCounterChange, ')
..write('lastFlameSync: $lastFlameSync, ')
..write('lastMessageExchange: $lastMessageExchange, ')
..write('flameCounter: $flameCounter')
..write(')'))
@ -3485,12 +3575,14 @@ typedef $$ContactsTableCreateCompanionBuilder = ContactsCompanion Function({
Value<bool> verified,
Value<bool> archived,
Value<bool> pinned,
Value<bool> alsoBestFriend,
Value<int> deleteMessagesAfterXMinutes,
Value<DateTime> createdAt,
Value<int> totalMediaCounter,
Value<DateTime?> lastMessageSend,
Value<DateTime?> lastMessageReceived,
Value<DateTime?> lastFlameCounterChange,
Value<DateTime?> lastFlameSync,
Value<DateTime> lastMessageExchange,
Value<int> flameCounter,
});
@ -3507,12 +3599,14 @@ typedef $$ContactsTableUpdateCompanionBuilder = ContactsCompanion Function({
Value<bool> verified,
Value<bool> archived,
Value<bool> pinned,
Value<bool> alsoBestFriend,
Value<int> deleteMessagesAfterXMinutes,
Value<DateTime> createdAt,
Value<int> totalMediaCounter,
Value<DateTime?> lastMessageSend,
Value<DateTime?> lastMessageReceived,
Value<DateTime?> lastFlameCounterChange,
Value<DateTime?> lastFlameSync,
Value<DateTime> lastMessageExchange,
Value<int> flameCounter,
});
@ -3583,6 +3677,10 @@ class $$ContactsTableFilterComposer
ColumnFilters<bool> get pinned => $composableBuilder(
column: $table.pinned, builder: (column) => ColumnFilters(column));
ColumnFilters<bool> get alsoBestFriend => $composableBuilder(
column: $table.alsoBestFriend,
builder: (column) => ColumnFilters(column));
ColumnFilters<int> get deleteMessagesAfterXMinutes => $composableBuilder(
column: $table.deleteMessagesAfterXMinutes,
builder: (column) => ColumnFilters(column));
@ -3606,6 +3704,9 @@ class $$ContactsTableFilterComposer
column: $table.lastFlameCounterChange,
builder: (column) => ColumnFilters(column));
ColumnFilters<DateTime> get lastFlameSync => $composableBuilder(
column: $table.lastFlameSync, builder: (column) => ColumnFilters(column));
ColumnFilters<DateTime> get lastMessageExchange => $composableBuilder(
column: $table.lastMessageExchange,
builder: (column) => ColumnFilters(column));
@ -3681,6 +3782,10 @@ class $$ContactsTableOrderingComposer
ColumnOrderings<bool> get pinned => $composableBuilder(
column: $table.pinned, builder: (column) => ColumnOrderings(column));
ColumnOrderings<bool> get alsoBestFriend => $composableBuilder(
column: $table.alsoBestFriend,
builder: (column) => ColumnOrderings(column));
ColumnOrderings<int> get deleteMessagesAfterXMinutes => $composableBuilder(
column: $table.deleteMessagesAfterXMinutes,
builder: (column) => ColumnOrderings(column));
@ -3704,6 +3809,10 @@ class $$ContactsTableOrderingComposer
column: $table.lastFlameCounterChange,
builder: (column) => ColumnOrderings(column));
ColumnOrderings<DateTime> get lastFlameSync => $composableBuilder(
column: $table.lastFlameSync,
builder: (column) => ColumnOrderings(column));
ColumnOrderings<DateTime> get lastMessageExchange => $composableBuilder(
column: $table.lastMessageExchange,
builder: (column) => ColumnOrderings(column));
@ -3758,6 +3867,9 @@ class $$ContactsTableAnnotationComposer
GeneratedColumn<bool> get pinned =>
$composableBuilder(column: $table.pinned, builder: (column) => column);
GeneratedColumn<bool> get alsoBestFriend => $composableBuilder(
column: $table.alsoBestFriend, builder: (column) => column);
GeneratedColumn<int> get deleteMessagesAfterXMinutes => $composableBuilder(
column: $table.deleteMessagesAfterXMinutes, builder: (column) => column);
@ -3776,6 +3888,9 @@ class $$ContactsTableAnnotationComposer
GeneratedColumn<DateTime> get lastFlameCounterChange => $composableBuilder(
column: $table.lastFlameCounterChange, builder: (column) => column);
GeneratedColumn<DateTime> get lastFlameSync => $composableBuilder(
column: $table.lastFlameSync, builder: (column) => column);
GeneratedColumn<DateTime> get lastMessageExchange => $composableBuilder(
column: $table.lastMessageExchange, builder: (column) => column);
@ -3839,12 +3954,14 @@ class $$ContactsTableTableManager extends RootTableManager<
Value<bool> verified = const Value.absent(),
Value<bool> archived = const Value.absent(),
Value<bool> pinned = const Value.absent(),
Value<bool> alsoBestFriend = const Value.absent(),
Value<int> deleteMessagesAfterXMinutes = const Value.absent(),
Value<DateTime> createdAt = const Value.absent(),
Value<int> totalMediaCounter = const Value.absent(),
Value<DateTime?> lastMessageSend = const Value.absent(),
Value<DateTime?> lastMessageReceived = const Value.absent(),
Value<DateTime?> lastFlameCounterChange = const Value.absent(),
Value<DateTime?> lastFlameSync = const Value.absent(),
Value<DateTime> lastMessageExchange = const Value.absent(),
Value<int> flameCounter = const Value.absent(),
}) =>
@ -3861,12 +3978,14 @@ class $$ContactsTableTableManager extends RootTableManager<
verified: verified,
archived: archived,
pinned: pinned,
alsoBestFriend: alsoBestFriend,
deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes,
createdAt: createdAt,
totalMediaCounter: totalMediaCounter,
lastMessageSend: lastMessageSend,
lastMessageReceived: lastMessageReceived,
lastFlameCounterChange: lastFlameCounterChange,
lastFlameSync: lastFlameSync,
lastMessageExchange: lastMessageExchange,
flameCounter: flameCounter,
),
@ -3883,12 +4002,14 @@ class $$ContactsTableTableManager extends RootTableManager<
Value<bool> verified = const Value.absent(),
Value<bool> archived = const Value.absent(),
Value<bool> pinned = const Value.absent(),
Value<bool> alsoBestFriend = const Value.absent(),
Value<int> deleteMessagesAfterXMinutes = const Value.absent(),
Value<DateTime> createdAt = const Value.absent(),
Value<int> totalMediaCounter = const Value.absent(),
Value<DateTime?> lastMessageSend = const Value.absent(),
Value<DateTime?> lastMessageReceived = const Value.absent(),
Value<DateTime?> lastFlameCounterChange = const Value.absent(),
Value<DateTime?> lastFlameSync = const Value.absent(),
Value<DateTime> lastMessageExchange = const Value.absent(),
Value<int> flameCounter = const Value.absent(),
}) =>
@ -3905,12 +4026,14 @@ class $$ContactsTableTableManager extends RootTableManager<
verified: verified,
archived: archived,
pinned: pinned,
alsoBestFriend: alsoBestFriend,
deleteMessagesAfterXMinutes: deleteMessagesAfterXMinutes,
createdAt: createdAt,
totalMediaCounter: totalMediaCounter,
lastMessageSend: lastMessageSend,
lastMessageReceived: lastMessageReceived,
lastFlameCounterChange: lastFlameCounterChange,
lastFlameSync: lastFlameSync,
lastMessageExchange: lastMessageExchange,
flameCounter: flameCounter,
),

View file

@ -1467,6 +1467,240 @@ i1.GeneratedColumn<bool> _column_53(String aliasedName) =>
defaultConstraints:
i1.GeneratedColumn.constraintIsAlways('CHECK ("pinned" IN (0, 1))'),
defaultValue: const CustomExpression('0'));
final class Schema8 extends i0.VersionedSchema {
Schema8({required super.database}) : super(version: 8);
@override
late final List<i1.DatabaseSchemaEntity> entities = [
contacts,
messages,
mediaUploads,
mediaDownloads,
signalIdentityKeyStores,
signalPreKeyStores,
signalSenderKeyStores,
signalSessionStores,
];
late final Shape12 contacts = Shape12(
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_39,
_column_53,
_column_54,
_column_40,
_column_10,
_column_11,
_column_12,
_column_13,
_column_14,
_column_55,
_column_15,
_column_16,
],
attachedDatabase: database,
),
alias: null);
late final Shape10 messages = Shape10(
source: i0.VersionedTable(
entityName: 'messages',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_17,
_column_18,
_column_19,
_column_48,
_column_49,
_column_20,
_column_21,
_column_22,
_column_52,
_column_23,
_column_24,
_column_25,
_column_26,
_column_27,
_column_28,
_column_29,
_column_30,
],
attachedDatabase: database,
),
alias: null);
late final Shape7 mediaUploads = Shape7(
source: i0.VersionedTable(
entityName: 'media_uploads',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_41,
_column_42,
_column_43,
_column_44,
_column_45,
_column_46,
_column_47,
],
attachedDatabase: database,
),
alias: null);
late final Shape9 mediaDownloads = Shape9(
source: i0.VersionedTable(
entityName: 'media_downloads',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_50,
_column_51,
],
attachedDatabase: database,
),
alias: null);
late final Shape2 signalIdentityKeyStores = Shape2(
source: i0.VersionedTable(
entityName: 'signal_identity_key_stores',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(device_id, name)',
],
columns: [
_column_31,
_column_32,
_column_33,
_column_10,
],
attachedDatabase: database,
),
alias: null);
late final Shape3 signalPreKeyStores = Shape3(
source: i0.VersionedTable(
entityName: 'signal_pre_key_stores',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(pre_key_id)',
],
columns: [
_column_34,
_column_35,
_column_10,
],
attachedDatabase: database,
),
alias: null);
late final Shape4 signalSenderKeyStores = Shape4(
source: i0.VersionedTable(
entityName: 'signal_sender_key_stores',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(sender_key_name)',
],
columns: [
_column_36,
_column_37,
],
attachedDatabase: database,
),
alias: null);
late final Shape5 signalSessionStores = Shape5(
source: i0.VersionedTable(
entityName: 'signal_session_stores',
withoutRowId: false,
isStrict: false,
tableConstraints: [
'PRIMARY KEY(device_id, name)',
],
columns: [
_column_31,
_column_32,
_column_38,
_column_10,
],
attachedDatabase: database,
),
alias: null);
}
class Shape12 extends i0.VersionedTable {
Shape12({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 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_54(String aliasedName) =>
i1.GeneratedColumn<bool>('also_best_friend', aliasedName, false,
type: i1.DriftSqlType.bool,
defaultConstraints: i1.GeneratedColumn.constraintIsAlways(
'CHECK ("also_best_friend" IN (0, 1))'),
defaultValue: const CustomExpression('0'));
i1.GeneratedColumn<DateTime> _column_55(String aliasedName) =>
i1.GeneratedColumn<DateTime>('last_flame_sync', aliasedName, true,
type: i1.DriftSqlType.dateTime);
i0.MigrationStepWithVersion migrationSteps({
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
@ -1474,6 +1708,7 @@ i0.MigrationStepWithVersion migrationSteps({
required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5,
required Future<void> Function(i1.Migrator m, Schema6 schema) from5To6,
required Future<void> Function(i1.Migrator m, Schema7 schema) from6To7,
required Future<void> Function(i1.Migrator m, Schema8 schema) from7To8,
}) {
return (currentVersion, database) async {
switch (currentVersion) {
@ -1507,6 +1742,11 @@ i0.MigrationStepWithVersion migrationSteps({
final migrator = i1.Migrator(database, schema);
await from6To7(migrator, schema);
return 7;
case 7:
final schema = Schema8(database: database);
final migrator = i1.Migrator(database, schema);
await from7To8(migrator, schema);
return 8;
default:
throw ArgumentError.value('Unknown migration from $currentVersion');
}
@ -1520,6 +1760,7 @@ i1.OnUpgrade stepByStep({
required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5,
required Future<void> Function(i1.Migrator m, Schema6 schema) from5To6,
required Future<void> Function(i1.Migrator m, Schema7 schema) from6To7,
required Future<void> Function(i1.Migrator m, Schema8 schema) from7To8,
}) =>
i0.VersionedSchema.stepByStepHelper(
step: migrationSteps(
@ -1529,4 +1770,5 @@ i1.OnUpgrade stepByStep({
from4To5: from4To5,
from5To6: from5To6,
from6To7: from6To7,
from7To8: from7To8,
));

View file

@ -87,6 +87,8 @@ class MessageContent {
return PushKeyContent.fromJson(json);
case MessageKind.reopenedMedia:
return ReopenedMediaFileContent.fromJson(json);
case MessageKind.flameSync:
return FlameSyncContent.fromJson(json);
default:
return null;
}
@ -242,3 +244,33 @@ class PushKeyContent extends MessageContent {
};
}
}
class FlameSyncContent extends MessageContent {
int flameCounter;
DateTime lastFlameCounterChange;
bool bestFriend;
FlameSyncContent(
{required this.flameCounter,
required this.bestFriend,
required this.lastFlameCounterChange});
static FlameSyncContent fromJson(Map json) {
return FlameSyncContent(
flameCounter: json['flameCounter'],
bestFriend: json['bestFriend'],
lastFlameCounterChange:
DateTime.fromMillisecondsSinceEpoch(json['lastFlameCounterChange']),
);
}
@override
Map toJson() {
return {
'flameCounter': flameCounter,
'bestFriend': bestFriend,
'lastFlameCounterChange':
lastFlameCounterChange.toUtc().millisecondsSinceEpoch,
};
}
}

View file

@ -34,6 +34,8 @@ class UserData {
DateTime? lastImageSend;
int? todaysImageCounter;
int? myBestFriendContactId;
final int userId;
factory UserData.fromJson(Map<String, dynamic> json) =>

View file

@ -35,7 +35,9 @@ UserData _$UserDataFromJson(Map<String, dynamic> json) => UserData(
..lastImageSend = json['lastImageSend'] == null
? null
: DateTime.parse(json['lastImageSend'] as String)
..todaysImageCounter = (json['todaysImageCounter'] as num?)?.toInt();
..todaysImageCounter = (json['todaysImageCounter'] as num?)?.toInt()
..myBestFriendContactId =
(json['myBestFriendContactId'] as num?)?.toInt();
Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
'username': instance.username,
@ -55,6 +57,7 @@ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
'additionalUserInvites': instance.additionalUserInvites,
'lastImageSend': instance.lastImageSend?.toIso8601String(),
'todaysImageCounter': instance.todaysImageCounter,
'myBestFriendContactId': instance.myBestFriendContactId,
'userId': instance.userId,
};

View file

@ -18,6 +18,7 @@ import 'package:twonly/src/providers/api/api.dart';
import 'package:twonly/src/providers/api/api_utils.dart';
import 'package:twonly/src/providers/api/media_received.dart';
import 'package:twonly/src/services/notification_service.dart';
import 'package:twonly/src/utils/misc.dart';
// ignore: library_prefixes
import 'package:twonly/src/utils/signal.dart' as SignalHelper;
@ -67,6 +68,29 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
case MessageKind.contactRequest:
return handleContactRequest(fromUserId, message);
case MessageKind.flameSync:
Contact? contact = await twonlyDatabase.contactsDao
.getContactByUserId(fromUserId)
.getSingleOrNull();
if (contact != null && contact.lastFlameCounterChange != null) {
final content = message.content;
if (content is FlameSyncContent) {
var updates = ContactsCompanion(
alsoBestFriend: Value(content.bestFriend),
);
if (isToday(contact.lastFlameCounterChange!) &&
isToday(content.lastFlameCounterChange)) {
if (content.flameCounter > contact.flameCounter) {
updates = ContactsCompanion(
alsoBestFriend: Value(content.bestFriend),
flameCounter: Value(content.flameCounter),
);
}
}
await twonlyDatabase.contactsDao.updateContact(fromUserId, updates);
}
}
case MessageKind.opened:
final update = MessagesCompanion(openedAt: Value(message.timestamp));
await twonlyDatabase.messagesDao.updateMessageByOtherUser(

View file

@ -23,6 +23,7 @@ import 'package:twonly/src/providers/api/media_received.dart';
import 'package:twonly/src/providers/api/media_send.dart';
import 'package:twonly/src/providers/api/server_messages.dart';
import 'package:twonly/src/services/fcm_service.dart';
import 'package:twonly/src/services/flame_service.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
// ignore: library_prefixes
@ -77,10 +78,6 @@ class ApiProvider {
Future onAuthenticated() async {
isAuthenticated = true;
initFCMAfterAuthenticated();
}
Future onConnected() async {
await authenticate();
globalCallbackConnectionState(true);
if (!globalIsAppInBackground) {
@ -89,9 +86,15 @@ class ApiProvider {
tryDownloadAllMediaFiles();
notifyContactsAboutProfileChange();
twonlyDatabase.markUpdated();
syncFlameCounters();
}
}
Future onConnected() async {
await authenticate();
globalCallbackConnectionState(true);
}
Future onClosed() async {
_channel = null;
isAuthenticated = false;

View file

@ -0,0 +1,60 @@
import 'package:collection/collection.dart';
import 'package:drift/drift.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/providers/api/api.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/model/json/message.dart' as my;
Future syncFlameCounters() async {
var user = await getUser();
if (user == null) return;
List<Contact> contacts =
await twonlyDatabase.contactsDao.getAllNotBlockedContacts();
if (contacts.isEmpty) return;
int maxMessageCounter = contacts.map((x) => x.totalMediaCounter).max;
Contact bestFriend =
contacts.firstWhere((x) => x.totalMediaCounter == maxMessageCounter);
if (user.myBestFriendContactId != bestFriend.userId) {
user.myBestFriendContactId = bestFriend.userId;
await updateUser(user);
}
for (Contact contact in contacts) {
if (contact.lastFlameCounterChange == null) continue;
if (contact.lastFlameSync != null) {
if (isToday(contact.lastFlameSync!)) continue;
}
int flameCounter = getFlameCounterFromContact(contact) - 1;
// only sync when flame counter is higher than three days
if (flameCounter < 1 && bestFriend.userId != contact.userId) continue;
encryptAndSendMessage(
null,
contact.userId,
my.MessageJson(
kind: MessageKind.flameSync,
content: my.FlameSyncContent(
flameCounter: flameCounter,
lastFlameCounterChange: contact.lastFlameCounterChange!,
bestFriend: contact.userId == bestFriend.userId,
),
timestamp: DateTime.now(),
),
);
await twonlyDatabase.contactsDao.updateContact(
contact.userId,
ContactsCompanion(
lastFlameSync: Value(DateTime.now()),
),
);
}
}

View file

@ -13,14 +13,12 @@ class BestFriendsSelector extends StatelessWidget {
final List<Contact> users;
final Function(int, bool) updateStatus;
final HashSet<int> selectedUserIds;
final int maxTotalMediaCounter;
final bool isRealTwonly;
final String title;
const BestFriendsSelector(
{super.key,
required this.users,
required this.maxTotalMediaCounter,
required this.isRealTwonly,
required this.updateStatus,
required this.selectedUserIds,
@ -81,18 +79,17 @@ class BestFriendsSelector extends StatelessWidget {
user: users[firstUserIndex],
onChanged: updateStatus,
isRealTwonly: isRealTwonly,
maxTotalMediaCounter: maxTotalMediaCounter,
),
),
(secondUserIndex < users.length)
? Expanded(
child: UserCheckbox(
isChecked: selectedUserIds
.contains(users[secondUserIndex].userId),
user: users[secondUserIndex],
onChanged: updateStatus,
isRealTwonly: isRealTwonly,
maxTotalMediaCounter: maxTotalMediaCounter),
isChecked: selectedUserIds
.contains(users[secondUserIndex].userId),
user: users[secondUserIndex],
onChanged: updateStatus,
isRealTwonly: isRealTwonly,
),
)
: Expanded(
child: Container(),
@ -112,12 +109,10 @@ class UserCheckbox extends StatelessWidget {
final Function(int, bool) onChanged;
final bool isChecked;
final bool isRealTwonly;
final int maxTotalMediaCounter;
const UserCheckbox({
super.key,
required this.user,
required this.maxTotalMediaCounter,
required this.onChanged,
required this.isRealTwonly,
required this.isChecked,
@ -181,8 +176,7 @@ class UserCheckbox extends StatelessWidget {
if (!snapshot.hasData || snapshot.data! == 0) {
return Container();
}
return FlameCounterWidget(
user, snapshot.data!, maxTotalMediaCounter);
return FlameCounterWidget(user, snapshot.data!);
},
)
],

View file

@ -44,7 +44,6 @@ class _ShareImageView extends State<ShareImageView> {
List<Contact> _otherUsers = [];
List<Contact> _bestFriends = [];
List<Contact> _pinnedContacs = [];
int maxTotalMediaCounter = 0;
Uint8List? imageBytes;
bool sendingImage = false;
bool hideArchivedUsers = true;
@ -100,12 +99,6 @@ class _ShareImageView extends State<ShareImageView> {
a.totalMediaCounter); // Sort by totalMediaCounter in descending order
});
maxTotalMediaCounter = 0;
if (users.isNotEmpty) {
maxTotalMediaCounter =
users.map((x) => x.totalMediaCounter).reduce((a, b) => a > b ? a : b);
}
// Separate best friends and other users
List<Contact> bestFriends = [];
List<Contact> otherUsers = [];
@ -201,7 +194,6 @@ class _ShareImageView extends State<ShareImageView> {
BestFriendsSelector(
users: _pinnedContacs,
selectedUserIds: _selectedUserIds,
maxTotalMediaCounter: maxTotalMediaCounter,
isRealTwonly: widget.isRealTwonly,
updateStatus: updateStatus,
title: context.lang.shareImagePinnedContacts,
@ -210,7 +202,6 @@ class _ShareImageView extends State<ShareImageView> {
BestFriendsSelector(
users: _bestFriends,
selectedUserIds: _selectedUserIds,
maxTotalMediaCounter: maxTotalMediaCounter,
isRealTwonly: widget.isRealTwonly,
updateStatus: updateStatus,
title: context.lang.shareImageBestFriends,
@ -259,7 +250,6 @@ class _ShareImageView extends State<ShareImageView> {
Expanded(
child: UserList(
List.from(_otherUsers),
maxTotalMediaCounter,
selectedUserIds: _selectedUserIds,
isRealTwonly: widget.isRealTwonly,
updateStatus: updateStatus,
@ -351,8 +341,7 @@ class _ShareImageView extends State<ShareImageView> {
class UserList extends StatelessWidget {
const UserList(
this.users,
this.maxTotalMediaCounter, {
this.users, {
super.key,
required this.selectedUserIds,
required this.updateStatus,
@ -360,7 +349,6 @@ class UserList extends StatelessWidget {
});
final Function(int, bool) updateStatus;
final List<Contact> users;
final int maxTotalMediaCounter;
final bool isRealTwonly;
final HashSet<int> selectedUserIds;
@ -391,7 +379,6 @@ class UserList extends StatelessWidget {
FlameCounterWidget(
user,
flameCounter,
maxTotalMediaCounter,
prefix: true,
),
],

View file

@ -334,7 +334,6 @@ class _UserListItem extends State<UserListItem> {
FlameCounterWidget(
widget.user,
flameCounter,
widget.maxTotalMediaCounter,
prefix: true,
),
],

View file

@ -24,7 +24,6 @@ class _StartNewChat extends State<StartNewChat> {
List<Contact> allContacts = [];
final TextEditingController searchUserName = TextEditingController();
late StreamSubscription<List<Contact>> contactSub;
int maxTotalMediaCounter = 1000;
@override
void initState() {
@ -96,7 +95,6 @@ class _StartNewChat extends State<StartNewChat> {
Expanded(
child: UserList(
contacts,
maxTotalMediaCounter,
),
)
],
@ -110,12 +108,10 @@ class _StartNewChat extends State<StartNewChat> {
class UserList extends StatelessWidget {
const UserList(
this.users,
this.maxTotalMediaCounter, {
this.users, {
super.key,
});
final List<Contact> users;
final int maxTotalMediaCounter;
@override
Widget build(BuildContext context) {
@ -161,7 +157,6 @@ class UserList extends StatelessWidget {
FlameCounterWidget(
user,
flameCounter,
maxTotalMediaCounter,
prefix: true,
),
Spacer(),

View file

@ -1,17 +1,16 @@
import 'package:flutter/material.dart';
import 'package:twonly/app.dart';
import 'package:twonly/src/views/components/animate_icon.dart';
import 'package:twonly/src/database/twonly_database.dart';
class FlameCounterWidget extends StatelessWidget {
final Contact user;
final int maxTotalMediaCounter;
final int flameCounter;
final bool prefix;
const FlameCounterWidget(
this.user,
this.flameCounter,
this.maxTotalMediaCounter, {
this.flameCounter, {
this.prefix = false,
super.key,
});
@ -30,9 +29,7 @@ class FlameCounterWidget extends StatelessWidget {
SizedBox(
height: 15,
child: EmojiAnimation(
emoji: (maxTotalMediaCounter == user.totalMediaCounter)
? "❤️‍🔥"
: "🔥"),
emoji: (globalBestFriendUserId == user.userId) ? "❤️‍🔥" : "🔥"),
),
],
);

View file

@ -60,7 +60,6 @@ class _ContactViewState extends State<ContactView> {
FlameCounterWidget(
contact,
flameCounter,
110000000,
prefix: true,
),
],

View file

@ -10,6 +10,7 @@ import 'schema_v4.dart' as v4;
import 'schema_v5.dart' as v5;
import 'schema_v6.dart' as v6;
import 'schema_v7.dart' as v7;
import 'schema_v8.dart' as v8;
class GeneratedHelper implements SchemaInstantiationHelper {
@override
@ -29,10 +30,12 @@ class GeneratedHelper implements SchemaInstantiationHelper {
return v6.DatabaseAtV6(db);
case 7:
return v7.DatabaseAtV7(db);
case 8:
return v8.DatabaseAtV8(db);
default:
throw MissingSchemaException(version, versions);
}
}
static const versions = const [1, 2, 3, 4, 5, 6, 7];
static const versions = const [1, 2, 3, 4, 5, 6, 7, 8];
}

File diff suppressed because it is too large Load diff