some performance improvements and fix #18

This commit is contained in:
otsmr 2025-02-11 11:08:08 +01:00
parent 504b528770
commit e21935eedf
8 changed files with 66 additions and 34 deletions

View file

@ -27,7 +27,7 @@ bool globalIsAppInBackground = true;
// these two callbacks are called on updated to the corresponding database // these two callbacks are called on updated to the corresponding database
Function globalCallBackOnContactChange = () {}; Function globalCallBackOnContactChange = () {};
Future Function(int) globalCallBackOnMessageChange = (a) async {}; Future Function(int, int?) globalCallBackOnMessageChange = (a, b) async {};
Function(List<int>, bool) globalCallBackOnDownloadChange = (a, b) {}; Function(List<int>, bool) globalCallBackOnDownloadChange = (a, b) {};
/// The Widget that configures your application. /// The Widget that configures your application.
@ -67,8 +67,10 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
context.read<DownloadChangeProvider>().update(token, add); context.read<DownloadChangeProvider>().update(token, add);
}; };
globalCallBackOnMessageChange = (userId) async { globalCallBackOnMessageChange = (userId, messageId) async {
await context.read<MessagesChangeProvider>().updateLastMessageFor(userId); await context
.read<MessagesChangeProvider>()
.updateLastMessageFor(userId, messageId);
}; };
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
@ -194,7 +196,7 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
globalCallbackConnectionState = (a) {}; globalCallbackConnectionState = (a) {};
globalCallBackOnDownloadChange = (a, b) {}; globalCallBackOnDownloadChange = (a, b) {};
globalCallBackOnContactChange = () {}; globalCallBackOnContactChange = () {};
globalCallBackOnMessageChange = (a) async {}; globalCallBackOnMessageChange = (a, b) async {};
super.dispose(); super.dispose();
} }

View file

@ -152,7 +152,7 @@ class DbMessages extends CvModelBase {
); );
int? fromUserId = await getFromUserIdByMessageId(messageId); int? fromUserId = await getFromUserIdByMessageId(messageId);
if (fromUserId != null) { if (fromUserId != null) {
globalCallBackOnMessageChange(fromUserId); globalCallBackOnMessageChange(fromUserId, messageId);
} }
return fromUserId; return fromUserId;
} }
@ -179,7 +179,7 @@ class DbMessages extends CvModelBase {
columnOtherUserId: userIdFrom, columnOtherUserId: userIdFrom,
columnSendAt: messageSendAt.toIso8601String() columnSendAt: messageSendAt.toIso8601String()
}); });
globalCallBackOnMessageChange(userIdFrom); globalCallBackOnMessageChange(userIdFrom, messageId);
return messageId; return messageId;
} catch (e) { } catch (e) {
Logger("messsage_model/insertMyMessage").shout("$e"); Logger("messsage_model/insertMyMessage").shout("$e");
@ -200,7 +200,7 @@ class DbMessages extends CvModelBase {
columnOtherUserId: userIdFrom, columnOtherUserId: userIdFrom,
columnSendAt: messageSendAt.toIso8601String() columnSendAt: messageSendAt.toIso8601String()
}); });
globalCallBackOnMessageChange(userIdFrom); globalCallBackOnMessageChange(userIdFrom, messageId);
return messageId; return messageId;
} catch (e) { } catch (e) {
Logger("messsage_model/insertOtherMessage").shout("$e"); Logger("messsage_model/insertOtherMessage").shout("$e");
@ -235,6 +235,13 @@ class DbMessages extends CvModelBase {
return messages; return messages;
} }
static Future<DbMessage?> getMessageById(int messageId) async {
var rows = await dbProvider.db!.query(tableName,
where: "$columnMessageId = ?", whereArgs: [messageId]);
List<DbMessage> messages = await convertToDbMessage(rows);
return messages.firstOrNull;
}
static Future<List<DbMessage>> getAllMessagesForRetransmitting() async { static Future<List<DbMessage>> getAllMessagesForRetransmitting() async {
var rows = await dbProvider.db!.query( var rows = await dbProvider.db!.query(
tableName, tableName,
@ -289,7 +296,7 @@ class DbMessages extends CvModelBase {
if (notifyFlutterState) { if (notifyFlutterState) {
int? fromUserId = await getFromUserIdByMessageId(messageId); int? fromUserId = await getFromUserIdByMessageId(messageId);
if (fromUserId != null) { if (fromUserId != null) {
globalCallBackOnMessageChange(fromUserId); globalCallBackOnMessageChange(fromUserId, messageId);
} }
} }
} }
@ -302,7 +309,7 @@ class DbMessages extends CvModelBase {
where: "$columnMessageOtherId = ?", where: "$columnMessageOtherId = ?",
whereArgs: [messageId], whereArgs: [messageId],
); );
globalCallBackOnMessageChange(fromUserId); globalCallBackOnMessageChange(fromUserId, messageId);
} }
// this ensures that the message id can be spoofed by another person // this ensures that the message id can be spoofed by another person
@ -314,7 +321,7 @@ class DbMessages extends CvModelBase {
where: "$columnMessageId = ? AND $columnOtherUserId = ?", where: "$columnMessageId = ? AND $columnOtherUserId = ?",
whereArgs: [messageId, fromUserId], whereArgs: [messageId, fromUserId],
); );
globalCallBackOnMessageChange(fromUserId); globalCallBackOnMessageChange(fromUserId, messageId);
} }
static Future userOpenedOtherMessage( static Future userOpenedOtherMessage(
@ -351,7 +358,7 @@ class DbMessages extends CvModelBase {
where: "$messageId = ? AND $columnOtherUserId = ?", where: "$messageId = ? AND $columnOtherUserId = ?",
whereArgs: [messageId, fromUserId], whereArgs: [messageId, fromUserId],
); );
globalCallBackOnMessageChange(fromUserId); globalCallBackOnMessageChange(fromUserId, messageId);
} }
@override @override
@ -374,6 +381,7 @@ class DbMessages extends CvModelBase {
List<dynamic> fromDb) async { List<dynamic> fromDb) async {
try { try {
List<DbMessage> parsedUsers = []; List<DbMessage> parsedUsers = [];
final box = await getMediaStorage();
for (int i = 0; i < fromDb.length; i++) { for (int i = 0; i < fromDb.length; i++) {
dynamic messageOpenedAt = fromDb[i][columnMessageOpenedAt]; dynamic messageOpenedAt = fromDb[i][columnMessageOpenedAt];
@ -397,7 +405,8 @@ class DbMessages extends CvModelBase {
if (messageOtherId != null) { if (messageOtherId != null) {
if (content is MediaMessageContent) { if (content is MediaMessageContent) {
// when the media was send from the user itself the content is null // when the media was send from the user itself the content is null
isDownloaded = await isMediaDownloaded(content.downloadToken); isDownloaded =
box.containsKey("${content.downloadToken}_downloaded");
} }
} }
parsedUsers.add( parsedUsers.add(

View file

@ -91,7 +91,11 @@ Future sendTextMessage(Int64 target, String message) async {
DateTime messageSendAt = DateTime.now(); DateTime messageSendAt = DateTime.now();
int? messageId = await DbMessages.insertMyMessage( int? messageId = await DbMessages.insertMyMessage(
target.toInt(), MessageKind.textMessage, content, messageSendAt); target.toInt(),
MessageKind.textMessage,
content,
messageSendAt,
);
if (messageId == null) return; if (messageId == null) return;
Message msg = Message( Message msg = Message(
@ -264,13 +268,11 @@ Future sendImage(
} }
// first step encrypt and store the encrypted image // first step encrypt and store the encrypted image
for (SendImage task in tasks) { await Future.wait(tasks.map((task) => task.encryptAndStore()));
await task.encryptAndStore();
}
// after the images are safely stored try do upload them one by one // after the images are safely stored try do upload them one by one
for (SendImage task in tasks) { for (SendImage task in tasks) {
await task.upload(); task.upload();
} }
} }
@ -332,11 +334,6 @@ Future<Uint8List?> getDownloadedMedia(
return media; return media;
} }
Future<bool> isMediaDownloaded(List<int> mediaToken) async {
final box = await getMediaStorage();
return box.containsKey("${mediaToken}_downloaded");
}
Future initMediaStorage() async { Future initMediaStorage() async {
final storage = getSecureStorage(); final storage = getSecureStorage();
var containsEncryptionKey = var containsEncryptionKey =

View file

@ -57,15 +57,15 @@ Future<client.Response> handleDownloadData(DownloadData data) async {
final box = await getMediaStorage(); final box = await getMediaStorage();
String boxId = data.uploadToken.toString(); String boxId = data.uploadToken.toString();
int? messageId = box.get("${data.uploadToken}_messageId");
if (data.fin && data.data.isEmpty) { if (data.fin && data.data.isEmpty) {
// media file was deleted by the server. remove the media from device // media file was deleted by the server. remove the media from device
int? messageId = box.get("${data.uploadToken}_messageId");
if (messageId != null) { if (messageId != null) {
int? fromUserId = await DbMessages.deleteMessageById(messageId); int? fromUserId = await DbMessages.deleteMessageById(messageId);
box.delete(boxId); box.delete(boxId);
if (fromUserId != null) { if (fromUserId != null) {
globalCallBackOnMessageChange(fromUserId); globalCallBackOnMessageChange(fromUserId, messageId);
} }
box.delete("${data.uploadToken}_fromUserId"); box.delete("${data.uploadToken}_fromUserId");
box.delete("${data.uploadToken}_downloaded"); box.delete("${data.uploadToken}_downloaded");
@ -107,7 +107,7 @@ Future<client.Response> handleDownloadData(DownloadData data) async {
} }
box.delete(boxId); box.delete(boxId);
await globalCallBackOnMessageChange(fromUserId); await globalCallBackOnMessageChange(fromUserId, messageId);
globalCallBackOnDownloadChange(data.uploadToken, false); globalCallBackOnDownloadChange(data.uploadToken, false);
} }
} else { } else {

View file

@ -17,16 +17,31 @@ class MessagesChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
Map<int, int> get changeCounter => _changeCounter; Map<int, int> get changeCounter => _changeCounter;
Map<int, int> get flamesCounter => _flamesCounter; Map<int, int> get flamesCounter => _flamesCounter;
Future updateLastMessageFor(int targetUserId) async { Future updateLastMessageFor(int targetUserId, int? messageId) async {
DbMessage? last = DbMessage? last =
await DbMessages.getLastMessagesForPreviewForUser(targetUserId); await DbMessages.getLastMessagesForPreviewForUser(targetUserId);
if (last != null) { if (last != null) {
_lastMessage[last.otherUserId] = last; _lastMessage[last.otherUserId] = last;
} }
flamesCounter[targetUserId] = await getFlamesForOtherUser(targetUserId); flamesCounter[targetUserId] = await getFlamesForOtherUser(targetUserId);
notifyListeners(); // notifyListeners();
if (messageId == null || _allMessagesFromUser[targetUserId] == null) {
loadMessagesForUser(targetUserId, force: true); loadMessagesForUser(targetUserId, force: true);
} else {
DbMessage? msg = await DbMessages.getMessageById(messageId);
if (msg != null) {
int index = _allMessagesFromUser[targetUserId]!
.indexWhere((x) => x.messageId == messageId);
if (index == -1) {
_allMessagesFromUser[targetUserId]!.insert(0, msg);
} else {
_allMessagesFromUser[targetUserId]![index] = msg;
}
}
_allMessagesFromUser[targetUserId] = allMessagesFromUser[targetUserId]!;
notifyListeners();
}
} }
Future loadMessagesForUser(int targetUserId, {bool force = false}) async { Future loadMessagesForUser(int targetUserId, {bool force = false}) async {

View file

@ -373,15 +373,16 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
icon: FaIcon(FontAwesomeIcons.solidPaperPlane), icon: FaIcon(FontAwesomeIcons.solidPaperPlane),
onPressed: () async { onPressed: () async {
if (sendNextMediaToUserId != null) { if (sendNextMediaToUserId != null) {
Navigator.popUntil(context, (route) => route.isFirst);
Uint8List? imageBytes = await getMergedImage(); Uint8List? imageBytes = await getMergedImage();
globalUpdateOfHomeViewPageIndex(1);
sendImage( sendImage(
[Int64(sendNextMediaToUserId)], [Int64(sendNextMediaToUserId)],
imageBytes!, imageBytes!,
_isRealTwonly, _isRealTwonly,
_maxShowTime, _maxShowTime,
); );
Navigator.popUntil(context, (route) => route.isFirst);
globalUpdateOfHomeViewPageIndex(1);
// send hier... // send hier...
return; return;
} }

View file

@ -36,6 +36,7 @@ class _ShareImageView extends State<ShareImageView> {
List<Contact> _bestFriends = []; List<Contact> _bestFriends = [];
int maxTotalMediaCounter = 0; int maxTotalMediaCounter = 0;
Uint8List? imageBytes; Uint8List? imageBytes;
bool sendingImage = false;
final HashSet<Int64> _selectedUserIds = HashSet<Int64>(); final HashSet<Int64> _selectedUserIds = HashSet<Int64>();
final TextEditingController searchUserName = TextEditingController(); final TextEditingController searchUserName = TextEditingController();
bool showRealTwonlyWarning = false; bool showRealTwonlyWarning = false;
@ -188,7 +189,7 @@ class _ShareImageView extends State<ShareImageView> {
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
FilledButton.icon( FilledButton.icon(
icon: imageBytes == null icon: imageBytes == null || sendingImage
? SizedBox( ? SizedBox(
height: 12, height: 12,
width: 12, width: 12,
@ -202,14 +203,19 @@ class _ShareImageView extends State<ShareImageView> {
if (imageBytes == null || _selectedUserIds.isEmpty) { if (imageBytes == null || _selectedUserIds.isEmpty) {
return; return;
} }
sendImage( setState(() {
sendingImage = true;
});
await sendImage(
_selectedUserIds.toList(), _selectedUserIds.toList(),
imageBytes!, imageBytes!,
widget.isRealTwonly, widget.isRealTwonly,
widget.maxShowTime, widget.maxShowTime,
); );
if (context.mounted) {
Navigator.popUntil(context, (route) => route.isFirst); Navigator.popUntil(context, (route) => route.isFirst);
globalUpdateOfHomeViewPageIndex(1); globalUpdateOfHomeViewPageIndex(1);
}
}, },
style: ButtonStyle( style: ButtonStyle(
padding: WidgetStateProperty.all<EdgeInsets>( padding: WidgetStateProperty.all<EdgeInsets>(

View file

@ -165,6 +165,7 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
.watch<MessagesChangeProvider>() .watch<MessagesChangeProvider>()
.allMessagesFromUser[user.userId.toInt()] ?? .allMessagesFromUser[user.userId.toInt()] ??
[]; [];
print(messages.length);
messages.where((x) => x.messageOpenedAt == null).forEach((message) { messages.where((x) => x.messageOpenedAt == null).forEach((message) {
if (message.messageOtherId != null && if (message.messageOtherId != null &&
@ -219,6 +220,7 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
itemCount: messages.length, // Number of items in the list itemCount: messages.length, // Number of items in the list
reverse: true, reverse: true,
itemBuilder: (context, i) { itemBuilder: (context, i) {
print(i);
bool lastMessageFromSameUser = false; bool lastMessageFromSameUser = false;
if (i > 0) { if (i > 0) {
lastMessageFromSameUser = lastMessageFromSameUser =