From e21935eedf7aeec81189654d1c1cf034e04a168d Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 11 Feb 2025 11:08:08 +0100 Subject: [PATCH] some performance improvements and fix #18 --- lib/src/app.dart | 10 +++++--- lib/src/model/messages_model.dart | 25 +++++++++++++------ lib/src/providers/api/api.dart | 17 ++++++------- lib/src/providers/api/server_messages.dart | 6 ++--- .../providers/messages_change_provider.dart | 21 +++++++++++++--- .../share_image_editor_view.dart | 5 ++-- .../camera_to_share/share_image_view.dart | 14 ++++++++--- .../views/chats/chat_item_details_view.dart | 2 ++ 8 files changed, 66 insertions(+), 34 deletions(-) diff --git a/lib/src/app.dart b/lib/src/app.dart index d69291c..4ec6d69 100644 --- a/lib/src/app.dart +++ b/lib/src/app.dart @@ -27,7 +27,7 @@ bool globalIsAppInBackground = true; // these two callbacks are called on updated to the corresponding database Function globalCallBackOnContactChange = () {}; -Future Function(int) globalCallBackOnMessageChange = (a) async {}; +Future Function(int, int?) globalCallBackOnMessageChange = (a, b) async {}; Function(List, bool) globalCallBackOnDownloadChange = (a, b) {}; /// The Widget that configures your application. @@ -67,8 +67,10 @@ class _MyAppState extends State with WidgetsBindingObserver { context.read().update(token, add); }; - globalCallBackOnMessageChange = (userId) async { - await context.read().updateLastMessageFor(userId); + globalCallBackOnMessageChange = (userId, messageId) async { + await context + .read() + .updateLastMessageFor(userId, messageId); }; WidgetsBinding.instance.addPostFrameCallback((_) { @@ -194,7 +196,7 @@ class _MyAppState extends State with WidgetsBindingObserver { globalCallbackConnectionState = (a) {}; globalCallBackOnDownloadChange = (a, b) {}; globalCallBackOnContactChange = () {}; - globalCallBackOnMessageChange = (a) async {}; + globalCallBackOnMessageChange = (a, b) async {}; super.dispose(); } diff --git a/lib/src/model/messages_model.dart b/lib/src/model/messages_model.dart index 092c86c..53415c4 100644 --- a/lib/src/model/messages_model.dart +++ b/lib/src/model/messages_model.dart @@ -152,7 +152,7 @@ class DbMessages extends CvModelBase { ); int? fromUserId = await getFromUserIdByMessageId(messageId); if (fromUserId != null) { - globalCallBackOnMessageChange(fromUserId); + globalCallBackOnMessageChange(fromUserId, messageId); } return fromUserId; } @@ -179,7 +179,7 @@ class DbMessages extends CvModelBase { columnOtherUserId: userIdFrom, columnSendAt: messageSendAt.toIso8601String() }); - globalCallBackOnMessageChange(userIdFrom); + globalCallBackOnMessageChange(userIdFrom, messageId); return messageId; } catch (e) { Logger("messsage_model/insertMyMessage").shout("$e"); @@ -200,7 +200,7 @@ class DbMessages extends CvModelBase { columnOtherUserId: userIdFrom, columnSendAt: messageSendAt.toIso8601String() }); - globalCallBackOnMessageChange(userIdFrom); + globalCallBackOnMessageChange(userIdFrom, messageId); return messageId; } catch (e) { Logger("messsage_model/insertOtherMessage").shout("$e"); @@ -235,6 +235,13 @@ class DbMessages extends CvModelBase { return messages; } + static Future getMessageById(int messageId) async { + var rows = await dbProvider.db!.query(tableName, + where: "$columnMessageId = ?", whereArgs: [messageId]); + List messages = await convertToDbMessage(rows); + return messages.firstOrNull; + } + static Future> getAllMessagesForRetransmitting() async { var rows = await dbProvider.db!.query( tableName, @@ -289,7 +296,7 @@ class DbMessages extends CvModelBase { if (notifyFlutterState) { int? fromUserId = await getFromUserIdByMessageId(messageId); if (fromUserId != null) { - globalCallBackOnMessageChange(fromUserId); + globalCallBackOnMessageChange(fromUserId, messageId); } } } @@ -302,7 +309,7 @@ class DbMessages extends CvModelBase { where: "$columnMessageOtherId = ?", whereArgs: [messageId], ); - globalCallBackOnMessageChange(fromUserId); + globalCallBackOnMessageChange(fromUserId, messageId); } // this ensures that the message id can be spoofed by another person @@ -314,7 +321,7 @@ class DbMessages extends CvModelBase { where: "$columnMessageId = ? AND $columnOtherUserId = ?", whereArgs: [messageId, fromUserId], ); - globalCallBackOnMessageChange(fromUserId); + globalCallBackOnMessageChange(fromUserId, messageId); } static Future userOpenedOtherMessage( @@ -351,7 +358,7 @@ class DbMessages extends CvModelBase { where: "$messageId = ? AND $columnOtherUserId = ?", whereArgs: [messageId, fromUserId], ); - globalCallBackOnMessageChange(fromUserId); + globalCallBackOnMessageChange(fromUserId, messageId); } @override @@ -374,6 +381,7 @@ class DbMessages extends CvModelBase { List fromDb) async { try { List parsedUsers = []; + final box = await getMediaStorage(); for (int i = 0; i < fromDb.length; i++) { dynamic messageOpenedAt = fromDb[i][columnMessageOpenedAt]; @@ -397,7 +405,8 @@ class DbMessages extends CvModelBase { if (messageOtherId != null) { if (content is MediaMessageContent) { // 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( diff --git a/lib/src/providers/api/api.dart b/lib/src/providers/api/api.dart index f5d8e6c..b94f225 100644 --- a/lib/src/providers/api/api.dart +++ b/lib/src/providers/api/api.dart @@ -91,7 +91,11 @@ Future sendTextMessage(Int64 target, String message) async { DateTime messageSendAt = DateTime.now(); int? messageId = await DbMessages.insertMyMessage( - target.toInt(), MessageKind.textMessage, content, messageSendAt); + target.toInt(), + MessageKind.textMessage, + content, + messageSendAt, + ); if (messageId == null) return; Message msg = Message( @@ -264,13 +268,11 @@ Future sendImage( } // first step encrypt and store the encrypted image - for (SendImage task in tasks) { - await task.encryptAndStore(); - } + await Future.wait(tasks.map((task) => task.encryptAndStore())); // after the images are safely stored try do upload them one by one for (SendImage task in tasks) { - await task.upload(); + task.upload(); } } @@ -332,11 +334,6 @@ Future getDownloadedMedia( return media; } -Future isMediaDownloaded(List mediaToken) async { - final box = await getMediaStorage(); - return box.containsKey("${mediaToken}_downloaded"); -} - Future initMediaStorage() async { final storage = getSecureStorage(); var containsEncryptionKey = diff --git a/lib/src/providers/api/server_messages.dart b/lib/src/providers/api/server_messages.dart index 3f03288..e2f53e8 100644 --- a/lib/src/providers/api/server_messages.dart +++ b/lib/src/providers/api/server_messages.dart @@ -57,15 +57,15 @@ Future handleDownloadData(DownloadData data) async { final box = await getMediaStorage(); String boxId = data.uploadToken.toString(); + int? messageId = box.get("${data.uploadToken}_messageId"); if (data.fin && data.data.isEmpty) { // media file was deleted by the server. remove the media from device - int? messageId = box.get("${data.uploadToken}_messageId"); if (messageId != null) { int? fromUserId = await DbMessages.deleteMessageById(messageId); box.delete(boxId); if (fromUserId != null) { - globalCallBackOnMessageChange(fromUserId); + globalCallBackOnMessageChange(fromUserId, messageId); } box.delete("${data.uploadToken}_fromUserId"); box.delete("${data.uploadToken}_downloaded"); @@ -107,7 +107,7 @@ Future handleDownloadData(DownloadData data) async { } box.delete(boxId); - await globalCallBackOnMessageChange(fromUserId); + await globalCallBackOnMessageChange(fromUserId, messageId); globalCallBackOnDownloadChange(data.uploadToken, false); } } else { diff --git a/lib/src/providers/messages_change_provider.dart b/lib/src/providers/messages_change_provider.dart index fcc8661..b35488a 100644 --- a/lib/src/providers/messages_change_provider.dart +++ b/lib/src/providers/messages_change_provider.dart @@ -17,16 +17,31 @@ class MessagesChangeProvider with ChangeNotifier, DiagnosticableTreeMixin { Map get changeCounter => _changeCounter; Map get flamesCounter => _flamesCounter; - Future updateLastMessageFor(int targetUserId) async { + Future updateLastMessageFor(int targetUserId, int? messageId) async { DbMessage? last = await DbMessages.getLastMessagesForPreviewForUser(targetUserId); if (last != null) { _lastMessage[last.otherUserId] = last; } flamesCounter[targetUserId] = await getFlamesForOtherUser(targetUserId); - notifyListeners(); + // notifyListeners(); - loadMessagesForUser(targetUserId, force: true); + if (messageId == null || _allMessagesFromUser[targetUserId] == null) { + 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 { diff --git a/lib/src/views/camera_to_share/share_image_editor_view.dart b/lib/src/views/camera_to_share/share_image_editor_view.dart index 281d229..9d61d1e 100644 --- a/lib/src/views/camera_to_share/share_image_editor_view.dart +++ b/lib/src/views/camera_to_share/share_image_editor_view.dart @@ -373,15 +373,16 @@ class _ShareImageEditorView extends State { icon: FaIcon(FontAwesomeIcons.solidPaperPlane), onPressed: () async { if (sendNextMediaToUserId != null) { - Navigator.popUntil(context, (route) => route.isFirst); Uint8List? imageBytes = await getMergedImage(); - globalUpdateOfHomeViewPageIndex(1); sendImage( [Int64(sendNextMediaToUserId)], imageBytes!, _isRealTwonly, _maxShowTime, ); + Navigator.popUntil(context, (route) => route.isFirst); + globalUpdateOfHomeViewPageIndex(1); + // send hier... return; } diff --git a/lib/src/views/camera_to_share/share_image_view.dart b/lib/src/views/camera_to_share/share_image_view.dart index fa1a50a..88a72b0 100644 --- a/lib/src/views/camera_to_share/share_image_view.dart +++ b/lib/src/views/camera_to_share/share_image_view.dart @@ -36,6 +36,7 @@ class _ShareImageView extends State { List _bestFriends = []; int maxTotalMediaCounter = 0; Uint8List? imageBytes; + bool sendingImage = false; final HashSet _selectedUserIds = HashSet(); final TextEditingController searchUserName = TextEditingController(); bool showRealTwonlyWarning = false; @@ -188,7 +189,7 @@ class _ShareImageView extends State { mainAxisAlignment: MainAxisAlignment.end, children: [ FilledButton.icon( - icon: imageBytes == null + icon: imageBytes == null || sendingImage ? SizedBox( height: 12, width: 12, @@ -202,14 +203,19 @@ class _ShareImageView extends State { if (imageBytes == null || _selectedUserIds.isEmpty) { return; } - sendImage( + setState(() { + sendingImage = true; + }); + await sendImage( _selectedUserIds.toList(), imageBytes!, widget.isRealTwonly, widget.maxShowTime, ); - Navigator.popUntil(context, (route) => route.isFirst); - globalUpdateOfHomeViewPageIndex(1); + if (context.mounted) { + Navigator.popUntil(context, (route) => route.isFirst); + globalUpdateOfHomeViewPageIndex(1); + } }, style: ButtonStyle( padding: WidgetStateProperty.all( diff --git a/lib/src/views/chats/chat_item_details_view.dart b/lib/src/views/chats/chat_item_details_view.dart index 83996f6..0ad74cd 100644 --- a/lib/src/views/chats/chat_item_details_view.dart +++ b/lib/src/views/chats/chat_item_details_view.dart @@ -165,6 +165,7 @@ class _ChatItemDetailsViewState extends State { .watch() .allMessagesFromUser[user.userId.toInt()] ?? []; + print(messages.length); messages.where((x) => x.messageOpenedAt == null).forEach((message) { if (message.messageOtherId != null && @@ -219,6 +220,7 @@ class _ChatItemDetailsViewState extends State { itemCount: messages.length, // Number of items in the list reverse: true, itemBuilder: (context, i) { + print(i); bool lastMessageFromSameUser = false; if (i > 0) { lastMessageFromSameUser =