mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 09:28:41 +00:00
fix flame problem
This commit is contained in:
parent
aa000afaf4
commit
8cdcc74683
13 changed files with 168 additions and 123 deletions
|
|
@ -4,7 +4,6 @@ Don't be lonely, get twonly! Send pictures to a friend in real time and be sure
|
|||
|
||||
|
||||
## TODOS bevor first beta
|
||||
- Flammen Problem fixen
|
||||
- Add no_screenshot plugin: https://pub.dev/packages/no_screenshot
|
||||
- Bei mehreren neu Empfangen Nachrichten fixen
|
||||
- Settings
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import 'dart:collection';
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:twonly/src/providers/messages_change_provider.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/components/flame.dart';
|
||||
import 'package:twonly/src/components/headline.dart';
|
||||
|
|
@ -87,6 +89,11 @@ class UserCheckbox extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int? flameCounter = context
|
||||
.watch<MessagesChangeProvider>()
|
||||
.flamesCounter[user.userId.toInt()];
|
||||
flameCounter ??= 0;
|
||||
|
||||
return Container(
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 3), // Padding inside the container
|
||||
|
|
@ -116,8 +123,8 @@ class UserCheckbox extends StatelessWidget {
|
|||
: user.displayName,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
if (user.flameCounter > 0)
|
||||
FlameCounterWidget(user, maxTotalMediaCounter),
|
||||
if (flameCounter > 0)
|
||||
FlameCounterWidget(user, flameCounter, maxTotalMediaCounter),
|
||||
Expanded(child: Container()),
|
||||
Checkbox(
|
||||
value: isChecked,
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ import 'package:twonly/src/model/contacts_model.dart';
|
|||
class FlameCounterWidget extends StatelessWidget {
|
||||
final Contact user;
|
||||
final int maxTotalMediaCounter;
|
||||
final int flameCounter;
|
||||
|
||||
const FlameCounterWidget(
|
||||
this.user,
|
||||
this.flameCounter,
|
||||
this.maxTotalMediaCounter, {
|
||||
super.key,
|
||||
});
|
||||
|
|
@ -19,7 +21,7 @@ class FlameCounterWidget extends StatelessWidget {
|
|||
Text("•"),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
user.flameCounter.toString(),
|
||||
flameCounter.toString(),
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
Text(
|
||||
|
|
|
|||
|
|
@ -10,17 +10,13 @@ class Contact {
|
|||
{required this.userId,
|
||||
required this.displayName,
|
||||
required this.accepted,
|
||||
required this.flameCounter,
|
||||
required this.totalMediaCounter,
|
||||
required this.lastUpdateOfFlameCounter,
|
||||
required this.requested});
|
||||
final Int64 userId;
|
||||
final String displayName;
|
||||
final bool accepted;
|
||||
final bool requested;
|
||||
final int flameCounter;
|
||||
final int totalMediaCounter;
|
||||
final DateTime lastUpdateOfFlameCounter;
|
||||
}
|
||||
|
||||
class DbContacts extends CvModelBase {
|
||||
|
|
@ -41,16 +37,9 @@ class DbContacts extends CvModelBase {
|
|||
static const columnBlocked = "blocked";
|
||||
final blocked = CvField<int>(columnBlocked);
|
||||
|
||||
static const columnFlameCounter = "flame_counter";
|
||||
final flameCounter = CvField<int>(columnFlameCounter);
|
||||
|
||||
static const columnTotalMediaCounter = "total_media_counter";
|
||||
final totalMediaCounter = CvField<int>(columnTotalMediaCounter);
|
||||
|
||||
static const columnLastUpdateOfFlameCounter = "last_update_flame_counter";
|
||||
final lastUpdateOfFlameCounter =
|
||||
CvField<DateTime>(columnLastUpdateOfFlameCounter);
|
||||
|
||||
static const columnCreatedAt = "created_at";
|
||||
final createdAt = CvField<DateTime>(columnCreatedAt);
|
||||
|
||||
|
|
@ -65,8 +54,6 @@ class DbContacts extends CvModelBase {
|
|||
$columnRequested INT NOT NULL DEFAULT 0,
|
||||
$columnBlocked INT NOT NULL DEFAULT 0,
|
||||
$columnTotalMediaCounter INT NOT NULL DEFAULT 0,
|
||||
$columnFlameCounter INT NOT NULL DEFAULT 0,
|
||||
$columnLastUpdateOfFlameCounter DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
$columnCreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""";
|
||||
|
|
@ -85,46 +72,22 @@ class DbContacts extends CvModelBase {
|
|||
|
||||
List<Map<String, dynamic>> result = await dbProvider.db!.query(
|
||||
tableName,
|
||||
columns: [
|
||||
columnLastUpdateOfFlameCounter,
|
||||
columnFlameCounter,
|
||||
columnTotalMediaCounter
|
||||
],
|
||||
columns: [columnTotalMediaCounter],
|
||||
where: '$columnUserId = ?',
|
||||
whereArgs: [userId],
|
||||
);
|
||||
|
||||
if (result.isNotEmpty) {
|
||||
String lastUpdateString = result.first[columnLastUpdateOfFlameCounter];
|
||||
DateTime lastUpdate = DateTime.tryParse(lastUpdateString)!;
|
||||
|
||||
if (timestamp.isAfter(lastUpdate)) {
|
||||
int currentCount = result.first.cast()[columnFlameCounter];
|
||||
int totalMediaCounter = result.first.cast()[columnTotalMediaCounter];
|
||||
if (lastUpdate.isAfter(DateTime.now()
|
||||
.subtract(Duration(seconds: nextFlameCounterInSeconds)))) {
|
||||
_updateFlameCounter(userId, currentCount,
|
||||
totalMediaCounter: totalMediaCounter + 1,
|
||||
timestamp: timestamp); // just update the time
|
||||
} else {
|
||||
_updateFlameCounter(userId, (currentCount + 1),
|
||||
totalMediaCounter: totalMediaCounter + 1, timestamp: timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
_updateFlameCounter(userId, totalMediaCounter + 1);
|
||||
globalCallBackOnContactChange();
|
||||
}
|
||||
|
||||
static Future _updateFlameCounter(int userId, int newCount,
|
||||
{DateTime? timestamp, int? totalMediaCounter}) async {
|
||||
timestamp ??= DateTime.now();
|
||||
Map<String, dynamic> valuesToUpdate = {
|
||||
columnFlameCounter: newCount,
|
||||
columnLastUpdateOfFlameCounter: timestamp.toIso8601String()
|
||||
};
|
||||
if (totalMediaCounter != null) {
|
||||
valuesToUpdate[columnTotalMediaCounter] = totalMediaCounter;
|
||||
}
|
||||
|
||||
static Future _updateFlameCounter(int userId, int totalMediaCounter) async {
|
||||
Map<String, dynamic> valuesToUpdate = {
|
||||
columnTotalMediaCounter: totalMediaCounter
|
||||
};
|
||||
await dbProvider.db!.update(
|
||||
tableName,
|
||||
valuesToUpdate,
|
||||
|
|
@ -141,9 +104,7 @@ class DbContacts extends CvModelBase {
|
|||
columnDisplayName,
|
||||
columnAccepted,
|
||||
columnRequested,
|
||||
columnFlameCounter,
|
||||
columnTotalMediaCounter,
|
||||
columnLastUpdateOfFlameCounter,
|
||||
columnCreatedAt
|
||||
],
|
||||
where: "$columnBlocked = 0");
|
||||
|
|
@ -151,27 +112,13 @@ class DbContacts extends CvModelBase {
|
|||
|
||||
List<Contact> parsedUsers = [];
|
||||
for (int i = 0; i < users.length; i++) {
|
||||
DateTime lastUpdate =
|
||||
DateTime.tryParse(users.cast()[i][columnLastUpdateOfFlameCounter])!;
|
||||
|
||||
int userId = users.cast()[i][columnUserId];
|
||||
|
||||
int flameCounter = users.cast()[i][columnFlameCounter];
|
||||
|
||||
// if (lastUpdate.isBefore(DateTime.now()
|
||||
// .subtract(Duration(seconds: nextFlameCounterInSeconds * 2)))) {
|
||||
// _updateFlameCounter(userId, 0);
|
||||
// flameCounter = 0;
|
||||
// }
|
||||
|
||||
parsedUsers.add(
|
||||
Contact(
|
||||
userId: Int64(userId),
|
||||
totalMediaCounter: users.cast()[i][columnTotalMediaCounter],
|
||||
displayName: users.cast()[i][columnDisplayName],
|
||||
accepted: users[i][columnAccepted] == 1,
|
||||
flameCounter: flameCounter,
|
||||
lastUpdateOfFlameCounter: lastUpdate,
|
||||
requested: users[i][columnRequested] == 1,
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class DbMessage {
|
|||
required this.messageAcknowledgeByUser,
|
||||
required this.isDownloaded,
|
||||
required this.messageAcknowledgeByServer,
|
||||
required this.sendOrReceivedAt,
|
||||
required this.sendAt,
|
||||
});
|
||||
|
||||
int messageId;
|
||||
|
|
@ -32,7 +32,7 @@ class DbMessage {
|
|||
bool messageAcknowledgeByUser;
|
||||
bool isDownloaded;
|
||||
bool messageAcknowledgeByServer;
|
||||
DateTime sendOrReceivedAt;
|
||||
DateTime sendAt;
|
||||
|
||||
bool containsOtherMedia() {
|
||||
if (messageOtherId == null) return false;
|
||||
|
|
@ -99,8 +99,8 @@ class DbMessages extends CvModelBase {
|
|||
final messageAcknowledgeByServer =
|
||||
CvField<int>(columnMessageAcknowledgeByServer);
|
||||
|
||||
static const columnSendOrReceivedAt = "message_send_or_received_at";
|
||||
final sendOrReceivedAt = CvField<DateTime>(columnSendOrReceivedAt);
|
||||
static const columnSendAt = "message_send_or_received_at";
|
||||
final sendAt = CvField<DateTime>(columnSendAt);
|
||||
|
||||
static const columnUpdatedAt = "updated_at";
|
||||
final updatedAt = CvField<DateTime>(columnUpdatedAt);
|
||||
|
|
@ -116,12 +116,33 @@ class DbMessages extends CvModelBase {
|
|||
$columnMessageAcknowledgeByServer INTEGER NOT NULL DEFAULT 0,
|
||||
$columnMessageContentJson TEXT NOT NULL,
|
||||
$columnMessageOpenedAt DATETIME DEFAULT NULL,
|
||||
$columnSendOrReceivedAt DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
$columnSendAt DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
$columnUpdatedAt DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""";
|
||||
}
|
||||
|
||||
static Future<List<(DateTime, int?)>> getMessageDates(int otherUserId) async {
|
||||
final List<Map<String, dynamic>> maps = await dbProvider.db!.rawQuery('''
|
||||
SELECT $columnSendAt, $columnMessageOtherId
|
||||
FROM $tableName
|
||||
WHERE $columnOtherUserId = ?
|
||||
ORDER BY $columnSendAt DESC;
|
||||
''', [otherUserId]);
|
||||
|
||||
try {
|
||||
return List.generate(maps.length, (i) {
|
||||
return (
|
||||
DateTime.tryParse(maps[i][columnSendAt])!,
|
||||
maps[i][columnMessageOtherId]
|
||||
);
|
||||
});
|
||||
} catch (e) {
|
||||
Logger("error parsing datetime: $e");
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
static Future deleteMessageById(int messageId) async {
|
||||
await dbProvider.db!.delete(
|
||||
tableName,
|
||||
|
|
@ -147,14 +168,14 @@ class DbMessages extends CvModelBase {
|
|||
return null;
|
||||
}
|
||||
|
||||
static Future<int?> insertMyMessage(
|
||||
int userIdFrom, MessageKind kind, MessageContent content) async {
|
||||
static Future<int?> insertMyMessage(int userIdFrom, MessageKind kind,
|
||||
MessageContent content, DateTime messageSendAt) async {
|
||||
try {
|
||||
int messageId = await dbProvider.db!.insert(tableName, {
|
||||
columnMessageKind: kind.index,
|
||||
columnMessageContentJson: jsonEncode(content.toJson()),
|
||||
columnOtherUserId: userIdFrom,
|
||||
columnSendOrReceivedAt: DateTime.now().toIso8601String()
|
||||
columnSendAt: messageSendAt.toIso8601String()
|
||||
});
|
||||
globalCallBackOnMessageChange(userIdFrom);
|
||||
return messageId;
|
||||
|
|
@ -165,7 +186,7 @@ class DbMessages extends CvModelBase {
|
|||
}
|
||||
|
||||
static Future<int?> insertOtherMessage(int userIdFrom, MessageKind kind,
|
||||
int messageOtherId, String jsonContent) async {
|
||||
int messageOtherId, String jsonContent, DateTime messageSendAt) async {
|
||||
try {
|
||||
int messageId = await dbProvider.db!.insert(tableName, {
|
||||
columnMessageOtherId: messageOtherId,
|
||||
|
|
@ -175,7 +196,7 @@ class DbMessages extends CvModelBase {
|
|||
columnMessageAcknowledgeByUser:
|
||||
0, // ack in case of sending corresponds to the opened flag
|
||||
columnOtherUserId: userIdFrom,
|
||||
columnSendOrReceivedAt: DateTime.now().toIso8601String()
|
||||
columnSendAt: messageSendAt.toIso8601String()
|
||||
});
|
||||
globalCallBackOnMessageChange(userIdFrom);
|
||||
return messageId;
|
||||
|
|
@ -330,13 +351,8 @@ class DbMessages extends CvModelBase {
|
|||
}
|
||||
|
||||
@override
|
||||
List<CvField> get fields => [
|
||||
messageId,
|
||||
messageKind,
|
||||
messageContentJson,
|
||||
messageOpenedAt,
|
||||
sendOrReceivedAt
|
||||
];
|
||||
List<CvField> get fields =>
|
||||
[messageId, messageKind, messageContentJson, messageOpenedAt, sendAt];
|
||||
|
||||
static Future<List<DbMessage>> convertToDbMessage(
|
||||
List<dynamic> fromDb) async {
|
||||
|
|
@ -366,8 +382,7 @@ class DbMessages extends CvModelBase {
|
|||
}
|
||||
parsedUsers.add(
|
||||
DbMessage(
|
||||
sendOrReceivedAt:
|
||||
DateTime.tryParse(fromDb[i][columnSendOrReceivedAt])!,
|
||||
sendAt: DateTime.tryParse(fromDb[i][columnSendAt])!,
|
||||
messageId: fromDb[i][columnMessageId],
|
||||
messageOtherId: messageOtherId,
|
||||
otherUserId: fromDb[i][columnOtherUserId],
|
||||
|
|
|
|||
|
|
@ -46,13 +46,8 @@ Future tryTransmitMessages() async {
|
|||
if (encryptedMedia != null) {
|
||||
final content = retransmit[i].messageContent;
|
||||
if (content is MediaMessageContent) {
|
||||
uploadMediaFile(
|
||||
msgId,
|
||||
Int64(retransmit[i].otherUserId),
|
||||
encryptedMedia,
|
||||
content.isRealTwonly,
|
||||
content.maxShowTime,
|
||||
);
|
||||
uploadMediaFile(msgId, Int64(retransmit[i].otherUserId), encryptedMedia,
|
||||
content.isRealTwonly, content.maxShowTime, retransmit[i].sendAt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -88,18 +83,18 @@ Future<Result> encryptAndSendMessage(Int64 userId, Message msg) async {
|
|||
Future sendTextMessage(Int64 target, String message) async {
|
||||
MessageContent content = TextMessageContent(text: message);
|
||||
|
||||
DateTime messageSendAt =
|
||||
DateTime.now().subtract(Duration(days: 1, minutes: 120));
|
||||
|
||||
int? messageId = await DbMessages.insertMyMessage(
|
||||
target.toInt(),
|
||||
MessageKind.textMessage,
|
||||
content,
|
||||
);
|
||||
target.toInt(), MessageKind.textMessage, content, messageSendAt);
|
||||
if (messageId == null) return;
|
||||
|
||||
Message msg = Message(
|
||||
kind: MessageKind.textMessage,
|
||||
messageId: messageId,
|
||||
content: content,
|
||||
timestamp: DateTime.now(),
|
||||
timestamp: messageSendAt,
|
||||
);
|
||||
|
||||
encryptAndSendMessage(target, msg);
|
||||
|
|
@ -112,6 +107,7 @@ Future uploadMediaFile(
|
|||
Uint8List encryptedMedia,
|
||||
bool isRealTwonly,
|
||||
int maxShowTime,
|
||||
DateTime messageSendAt,
|
||||
) async {
|
||||
Box box = await getMediaStorage();
|
||||
|
||||
|
|
@ -156,7 +152,7 @@ Future uploadMediaFile(
|
|||
maxShowTime: maxShowTime,
|
||||
isRealTwonly: isRealTwonly,
|
||||
isVideo: false),
|
||||
timestamp: DateTime.now(),
|
||||
timestamp: messageSendAt,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -167,6 +163,7 @@ Future encryptAndUploadMediaFile(
|
|||
bool isRealTwonly,
|
||||
int maxShowTime,
|
||||
) async {
|
||||
DateTime messageSendAt = DateTime.now();
|
||||
int? messageId = await DbMessages.insertMyMessage(
|
||||
target.toInt(),
|
||||
MessageKind.image,
|
||||
|
|
@ -174,7 +171,9 @@ Future encryptAndUploadMediaFile(
|
|||
downloadToken: [],
|
||||
maxShowTime: maxShowTime,
|
||||
isRealTwonly: isRealTwonly,
|
||||
isVideo: false));
|
||||
isVideo: false,
|
||||
),
|
||||
messageSendAt);
|
||||
// isRealTwonly,
|
||||
if (messageId == null) return;
|
||||
|
||||
|
|
@ -185,8 +184,8 @@ Future encryptAndUploadMediaFile(
|
|||
return;
|
||||
}
|
||||
|
||||
await uploadMediaFile(
|
||||
messageId, target, encryptBytes, isRealTwonly, maxShowTime);
|
||||
await uploadMediaFile(messageId, target, encryptBytes, isRealTwonly,
|
||||
maxShowTime, messageSendAt);
|
||||
}
|
||||
|
||||
Future sendImage(
|
||||
|
|
@ -253,11 +252,11 @@ Future<Uint8List?> getDownloadedMedia(
|
|||
final box = await getMediaStorage();
|
||||
Uint8List? media = box.get("${mediaToken}_downloaded");
|
||||
|
||||
// int fromUserId = box.get("${mediaToken}_fromUserId");
|
||||
// await userOpenedOtherMessage(fromUserId, messageOtherId);
|
||||
// box.delete(mediaToken.toString());
|
||||
// box.put("${mediaToken}_downloaded", "deleted");
|
||||
// box.delete("${mediaToken}_fromUserId");
|
||||
int fromUserId = box.get("${mediaToken}_fromUserId");
|
||||
await userOpenedOtherMessage(fromUserId, messageOtherId);
|
||||
box.delete(mediaToken.toString());
|
||||
box.put("${mediaToken}_downloaded", "deleted");
|
||||
box.delete("${mediaToken}_fromUserId");
|
||||
|
||||
return media;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,11 @@ Future<client.Response> handleNewMessage(
|
|||
} else {
|
||||
String content = jsonEncode(message.content.toJson());
|
||||
int? messageId = await DbMessages.insertOtherMessage(
|
||||
fromUserId.toInt(), message.kind, message.messageId!, content);
|
||||
fromUserId.toInt(),
|
||||
message.kind,
|
||||
message.messageId!,
|
||||
content,
|
||||
message.timestamp);
|
||||
|
||||
if (messageId == null) {
|
||||
return client.Response()..error = ErrorCode.InternalError;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:twonly/src/model/contacts_model.dart';
|
||||
import 'package:twonly/src/model/messages_model.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
|
||||
/// This provider does always contains the latest messages send or received
|
||||
/// for every contact.
|
||||
class MessagesChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||
final Map<int, DbMessage> _lastMessage = <int, DbMessage>{};
|
||||
final Map<int, int> _changeCounter = <int, int>{};
|
||||
final Map<int, int> _flamesCounter = <int, int>{};
|
||||
|
||||
Map<int, DbMessage> get lastMessage => _lastMessage;
|
||||
Map<int, int> get changeCounter => _changeCounter;
|
||||
Map<int, int> get flamesCounter => _flamesCounter;
|
||||
|
||||
void updateLastMessageFor(int targetUserId) async {
|
||||
DbMessage? last =
|
||||
|
|
@ -21,6 +24,7 @@ class MessagesChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
|||
changeCounter[targetUserId] = 0;
|
||||
}
|
||||
changeCounter[targetUserId] = changeCounter[targetUserId]! + 1;
|
||||
flamesCounter[targetUserId] = await getFlamesForOtherUser(targetUserId);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
|
@ -33,6 +37,8 @@ class MessagesChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
|||
if (last != null) {
|
||||
_lastMessage[last.otherUserId] = last;
|
||||
}
|
||||
flamesCounter[contact.userId.toInt()] =
|
||||
await getFlamesForOtherUser(contact.userId.toInt());
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:gal/gal.dart';
|
|||
import 'package:logging/logging.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:twonly/src/model/messages_model.dart';
|
||||
import 'package:twonly/src/proto/api/error.pb.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
|
|
@ -131,3 +132,48 @@ Future<Uint8List?> getCompressedImage(Uint8List imageBytes) async {
|
|||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
int getFlameCounter(List<DateTime> dates) {
|
||||
if (dates.isEmpty) return 0;
|
||||
|
||||
int flamesCount = 0;
|
||||
DateTime lastFlameCount = DateTime.now();
|
||||
|
||||
if (dates[0].difference(lastFlameCount).inDays == 0) {
|
||||
flamesCount = 1;
|
||||
lastFlameCount = dates[0];
|
||||
}
|
||||
|
||||
// print(dates[0]);
|
||||
for (int i = 1; i < dates.length; i++) {
|
||||
// print(
|
||||
// "${dates[i]} ${dates[i].difference(dates[i - 1]).inDays} ${dates[i].difference(lastFlameCount).inDays}");
|
||||
if (dates[i].difference(dates[i - 1]).inDays == 0) {
|
||||
if (lastFlameCount.difference(dates[i]).inDays == 1) {
|
||||
flamesCount++;
|
||||
lastFlameCount = dates[i];
|
||||
}
|
||||
} else {
|
||||
break; // Stop counting if there's a break in the sequence
|
||||
}
|
||||
}
|
||||
return flamesCount;
|
||||
}
|
||||
|
||||
Future<int> getFlamesForOtherUser(int otherUserId) async {
|
||||
List<(DateTime, int?)> dates = await DbMessages.getMessageDates(otherUserId);
|
||||
// print("Dates ${dates.length}");
|
||||
if (dates.isEmpty) return 0;
|
||||
|
||||
List<DateTime> received =
|
||||
dates.where((x) => x.$2 != null).map((x) => x.$1).toList();
|
||||
List<DateTime> send =
|
||||
dates.where((x) => x.$2 == null).map((x) => x.$1).toList();
|
||||
|
||||
// print("Received ${received.length} and send ${send.length}");
|
||||
|
||||
int a = getFlameCounter(received);
|
||||
int b = getFlameCounter(send);
|
||||
// print("Received $a and send $b");
|
||||
return min(a, b);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ import 'dart:typed_data';
|
|||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:twonly/src/components/best_friends_selector.dart';
|
||||
import 'package:twonly/src/components/flame.dart';
|
||||
import 'package:twonly/src/components/headline.dart';
|
||||
import 'package:twonly/src/components/initialsavatar.dart';
|
||||
import 'package:twonly/src/model/contacts_model.dart';
|
||||
import 'package:twonly/src/providers/api/api.dart';
|
||||
import 'package:twonly/src/providers/messages_change_provider.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/views/home_view.dart';
|
||||
|
||||
|
|
@ -51,10 +53,14 @@ class _ShareImageView extends State<ShareImageView> {
|
|||
}
|
||||
|
||||
Future _updateUsers(List<Contact> users) async {
|
||||
Map<int, int> flameCounters =
|
||||
context.read<MessagesChangeProvider>().flamesCounter;
|
||||
|
||||
// Sort contacts by flameCounter and then by totalMediaCounter
|
||||
users.sort((a, b) {
|
||||
// First, compare by flameCounter
|
||||
int flameComparison = b.flameCounter.compareTo(a.flameCounter);
|
||||
int flameComparison = flameCounters[b.userId.toInt()]!
|
||||
.compareTo(flameCounters[a.userId.toInt()]!);
|
||||
if (flameComparison != 0) {
|
||||
return flameComparison; // Sort by flameCounter in descending order
|
||||
}
|
||||
|
|
@ -74,7 +80,8 @@ class _ShareImageView extends State<ShareImageView> {
|
|||
List<Contact> otherUsers = [];
|
||||
|
||||
for (var contact in users) {
|
||||
if (contact.flameCounter > 0 && bestFriends.length < 6) {
|
||||
if (flameCounters[contact.userId.toInt()]! > 0 &&
|
||||
bestFriends.length < 6) {
|
||||
bestFriends.add(contact);
|
||||
} else {
|
||||
otherUsers.add(contact);
|
||||
|
|
@ -179,7 +186,7 @@ class _ShareImageView extends State<ShareImageView> {
|
|||
// TODO: pop back to the HomeView page popUntil did not work. check later how to improve in case of pushing more then 2
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(context);
|
||||
globalUpdateOfHomeViewPageIndex(0);
|
||||
globalUpdateOfHomeViewPageIndex(1);
|
||||
},
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all<EdgeInsets>(
|
||||
|
|
@ -216,16 +223,21 @@ class UserList extends StatelessWidget {
|
|||
// Step 1: Sort the users alphabetically
|
||||
users.sort((a, b) => a.displayName.compareTo(b.displayName));
|
||||
|
||||
Map<int, int> flameCounters =
|
||||
context.watch<MessagesChangeProvider>().flamesCounter;
|
||||
|
||||
return ListView.builder(
|
||||
restorationId: 'new_message_users_list',
|
||||
itemCount: users.length,
|
||||
itemBuilder: (BuildContext context, int i) {
|
||||
Contact user = users[i];
|
||||
int? flameCounter = flameCounters[user.userId.toInt()];
|
||||
flameCounter ??= 0;
|
||||
return ListTile(
|
||||
title: Row(children: [
|
||||
Text(user.displayName),
|
||||
if (user.flameCounter > 0)
|
||||
FlameCounterWidget(user, maxTotalMediaCounter),
|
||||
if (flameCounter > 0)
|
||||
FlameCounterWidget(user, flameCounter, maxTotalMediaCounter),
|
||||
]),
|
||||
leading: InitialsAvatar(
|
||||
displayName: user.displayName,
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
.toList();
|
||||
activeUsers.sort((b, a) {
|
||||
return lastMessages[a.userId.toInt()]!
|
||||
.sendOrReceivedAt
|
||||
.compareTo(lastMessages[b.userId.toInt()]!.sendOrReceivedAt);
|
||||
.sendAt
|
||||
.compareTo(lastMessages[b.userId.toInt()]!.sendAt);
|
||||
});
|
||||
|
||||
int maxTotalMediaCounter = 0;
|
||||
|
|
@ -165,9 +165,8 @@ class _UserListItem extends State<UserListItem> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int lastMessageInSeconds = DateTime.now()
|
||||
.difference(widget.lastMessage.sendOrReceivedAt)
|
||||
.inSeconds;
|
||||
int lastMessageInSeconds =
|
||||
DateTime.now().difference(widget.lastMessage.sendAt).inSeconds;
|
||||
|
||||
MessageSendState state = widget.lastMessage.getSendState();
|
||||
bool isDownloading = false;
|
||||
|
|
@ -183,6 +182,11 @@ class _UserListItem extends State<UserListItem> {
|
|||
.contains(token.toString());
|
||||
}
|
||||
|
||||
int? flameCounter = context
|
||||
.watch<MessagesChangeProvider>()
|
||||
.flamesCounter[widget.user.userId.toInt()];
|
||||
flameCounter ??= 0;
|
||||
|
||||
return UserContextMenu(
|
||||
user: widget.user,
|
||||
child: ListTile(
|
||||
|
|
@ -196,8 +200,9 @@ class _UserListItem extends State<UserListItem> {
|
|||
formatDuration(lastMessageInSeconds),
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
if (widget.user.flameCounter > 0)
|
||||
FlameCounterWidget(widget.user, widget.maxTotalMediaCounter),
|
||||
if (flameCounter > 0)
|
||||
FlameCounterWidget(
|
||||
widget.user, flameCounter, widget.maxTotalMediaCounter),
|
||||
],
|
||||
),
|
||||
leading: InitialsAvatar(displayName: widget.user.displayName),
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
DateTime? canBeSeenUntil;
|
||||
int maxShowTime = 999999;
|
||||
bool isRealTwonly = false;
|
||||
Timer? _timer;
|
||||
// DateTime opened;
|
||||
|
||||
@override
|
||||
|
|
@ -72,7 +73,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
}
|
||||
|
||||
startTimer() {
|
||||
Future.delayed(canBeSeenUntil!.difference(DateTime.now()), () {
|
||||
_timer = Timer(canBeSeenUntil!.difference(DateTime.now()), () {
|
||||
if (context.mounted) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
|
@ -96,6 +97,8 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
|
||||
_timer?.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ class HomeViewState extends State<HomeView> {
|
|||
activePageIdx = index;
|
||||
},
|
||||
children: [
|
||||
ChatListView(),
|
||||
CameraPreviewViewPermission(),
|
||||
ChatListView(),
|
||||
],
|
||||
),
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
|
|
@ -76,12 +76,12 @@ class HomeViewState extends State<HomeView> {
|
|||
selectedIconTheme:
|
||||
IconThemeData(color: const Color.fromARGB(255, 255, 255, 255)),
|
||||
items: [
|
||||
BottomNavigationBarItem(
|
||||
icon: FaIcon(FontAwesomeIcons.solidComments), label: ""),
|
||||
BottomNavigationBarItem(
|
||||
icon: FaIcon(FontAwesomeIcons.camera),
|
||||
label: "",
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: FaIcon(FontAwesomeIcons.solidComments), label: ""),
|
||||
// BottomNavigationBarItem(
|
||||
// icon: FaIcon(FontAwesomeIcons.userShield), label: ""),
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in a new issue