From 0bcfe75a63215e119268ecf49f20b7dee3522630 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 28 Apr 2022 08:57:31 -0700 Subject: [PATCH 1/3] rework cache android resume based off message count totals, force pre fetch on load message list, tweak new messages bubble behaviour --- lib/models/contact.dart | 19 ++++++++----------- lib/models/message.dart | 30 ++++++++++++++++++++++-------- lib/models/messagecache.dart | 24 ++++++------------------ lib/models/profile.dart | 11 +++++------ lib/views/contactsview.dart | 10 +++++++++- lib/widgets/messagelist.dart | 9 +++++++++ 6 files changed, 59 insertions(+), 44 deletions(-) diff --git a/lib/models/contact.dart b/lib/models/contact.dart index 7906401c..56bfe8b3 100644 --- a/lib/models/contact.dart +++ b/lib/models/contact.dart @@ -43,7 +43,6 @@ class ContactInfoState extends ChangeNotifier { late DateTime _lastMessageTime; late Map> keys; int _newMarkerMsgId = -1; - DateTime _newMarkerClearAt = DateTime.now(); late MessageCache messageCache; // todo: a nicer way to model contacts, groups and other "entities" @@ -145,24 +144,22 @@ class ContactInfoState extends ChangeNotifier { notifyListeners(); } + void selected() { + this._unreadMessages = 0; + } + + void unselected() { + this._newMarkerMsgId = -1; + } + int get unreadMessages => this._unreadMessages; set unreadMessages(int newVal) { - if (newVal == 0 && this._unreadMessages != 0) { - // conversation has been selected, start the countdown for the New Messager marker to be reset - this._newMarkerClearAt = DateTime.now().add(const Duration(minutes: 2)); - } this._unreadMessages = newVal; notifyListeners(); } int get newMarkerMsgId { - if (DateTime.now().isAfter(this._newMarkerClearAt)) { - // perform heresy - this._newMarkerMsgId = -1; - // no need to notifyListeners() because presumably this getter is - // being called from a renderer anyway - } return this._newMarkerMsgId; } diff --git a/lib/models/message.dart b/lib/models/message.dart index 0ab95a07..d7786fdf 100644 --- a/lib/models/message.dart +++ b/lib/models/message.dart @@ -78,7 +78,7 @@ class ByIndex implements CacheHandler { Future get(Cwtch cwtch, String profileOnion, int conversationIdentifier, MessageCache cache) async { // if in cache, get. But if the cache has unsynced or not in cache, we'll have to do a fetch - if (cache.indexUnsynced == 0 && index < cache.cacheByIndex.length) { + if (index < cache.cacheByIndex.length) { return cache.getByIndex(index); } @@ -92,12 +92,6 @@ class ByIndex implements CacheHandler { amount += index - start; } - // on android we may have recieved messages on the backend that we didn't process in the UI, get them - // override the index chunk setting, the index math is wrong will we fetch these and these are all that should be missing - if (cache.indexUnsynced > 0) { - start = 0; - amount = cache.indexUnsynced; - } // check that we aren't asking for messages beyond stored messages if (start + amount >= cache.storageMessageCount) { @@ -108,6 +102,27 @@ class ByIndex implements CacheHandler { } cache.lockIndexes(start, start + amount); + await fetchAndProcess(start, amount, cwtch, profileOnion, conversationIdentifier, cache); + + return cache.getByIndex(index); + } + + void loadUnsynced(Cwtch cwtch, String profileOnion, int conversationIdentifier, MessageCache cache) { + // return if inadvertently called when no unsynced messages + if (cache.indexUnsynced == 0) { + return; + } + + // otherwise we are going to fetch, so we'll fetch a chunk of messages + var start = 0; + var amount = cache.indexUnsynced; + + cache.lockIndexes(start, start + amount); + fetchAndProcess(start, amount, cwtch, profileOnion, conversationIdentifier, cache); + return; + } + + Future fetchAndProcess(int start, int amount, Cwtch cwtch, String profileOnion, int conversationIdentifier, MessageCache cache) async { var msgs = await cwtch.GetMessages(profileOnion, conversationIdentifier, start, amount); int i = 0; // i used to loop through returned messages. if doesn't reach the requested count, we will use it in the finally stanza to error out the remaining asked for messages in the cache try { @@ -124,7 +139,6 @@ class ByIndex implements CacheHandler { cache.malformIndexes(start + i, start + amount); } } - return cache.getByIndex(index); } void add(MessageCache cache, MessageInfo messageInfo) { diff --git a/lib/models/messagecache.dart b/lib/models/messagecache.dart index 33325c22..b6f89059 100644 --- a/lib/models/messagecache.dart +++ b/lib/models/messagecache.dart @@ -98,25 +98,16 @@ class MessageCache extends ChangeNotifier { this._storageMessageCount = newval; } - // On android reconnect, get unread message cound and the last seen Id - // sync this data with what we have cached to determine if/how many messages are now at the front of the index that we don't have cached - void addFrontIndexGap(int count, int lastSeenId) { - // scan across indexed message the unread count amount (that's the last time UI/BE acked a message) - // if we find the last seen ID, the diff of unread count is what's unsynced - for (var i = 0; i < (count + 1) && i < cacheByIndex.length; i++) { - if (this.cacheByIndex[i].messageId == lastSeenId) { - // we have found the matching lastSeenId so we can calculate the unsynced as the unread messages before it - this._indexUnsynced = count - i; - notifyListeners(); - return; - } - } - // we did not find a matching index, diff to the back end is too great, reset index cache - resetIndexCache(); + // On android reconnect, if backend supplied message count > UI message count, add the differnce to the front of the index + void addFrontIndexGap(int count) { + this._indexUnsynced = count; + // TODO: needed? maybe not? since after totalmessatges and profile will notify + //notifyListeners(); } int get indexUnsynced => _indexUnsynced; + // TODO: unused? delete? void resetIndexCache() { this._indexUnsynced = 0; cacheByIndex = List.empty(growable: true); @@ -144,7 +135,6 @@ class MessageCache extends ChangeNotifier { if (contenthash != null && contenthash != "") { this.cacheByHash[contenthash] = messageID; } - notifyListeners(); } // inserts place holder values into the index cache that will block on .get() until .finishLoad() is called on them with message contents @@ -175,7 +165,6 @@ class MessageCache extends ChangeNotifier { this.cacheByIndex.insert(index, LocalIndexMessage(messageInfo.metadata.messageID)); } this.cacheByHash[messageInfo.metadata.contenthash] = messageInfo.metadata.messageID; - notifyListeners(); } void addUnindexed(MessageInfo messageInfo) { @@ -183,7 +172,6 @@ class MessageCache extends ChangeNotifier { if (messageInfo.metadata.contenthash != "") { this.cacheByHash[messageInfo.metadata.contenthash] = messageInfo.metadata.messageID; } - notifyListeners(); } void ackCache(int messageID) { diff --git a/lib/models/profile.dart b/lib/models/profile.dart index 61ce24f9..4a7a59fc 100644 --- a/lib/models/profile.dart +++ b/lib/models/profile.dart @@ -176,14 +176,13 @@ class ProfileInfoState extends ChangeNotifier { this._unreadMessages += contact["numUnread"] as int; if (profileContact != null) { profileContact.status = contact["status"]; - profileContact.totalMessages = contact["numMessages"]; - profileContact.unreadMessages = contact["numUnread"]; - if (contact["numUnread"] > MaxUnreadBeforeCacheReset || (contact["numUnread"] > 0 && contact["lastSeenMessageId"] == -1)) { - profileContact.messageCache.resetIndexCache(); - } else if (contact["numUnread"] > 0) { - profileContact.messageCache.addFrontIndexGap(contact["numUnread"], contact["lastSeenMessageId"]); + var newCount = contact["numMessages"]; + if (newCount != profileContact.totalMessages) { + profileContact.messageCache.addFrontIndexGap(newCount - profileContact.totalMessages); } + profileContact.totalMessages = newCount; + profileContact.unreadMessages = contact["numUnread"]; profileContact.lastMessageTime = DateTime.fromMillisecondsSinceEpoch(1000 * int.parse(contact["lastMsgTime"])); } else { this._contacts.add(ContactInfoState( diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index 106a9722..7809450e 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -30,7 +30,15 @@ class ContactsView extends StatefulWidget { void selectConversation(BuildContext context, int handle) { // requery instead of using contactinfostate directly because sometimes listview gets confused about data that resorts var initialIndex = Provider.of(context, listen: false).contactList.getContact(handle)!.unreadMessages; - Provider.of(context, listen: false).contactList.getContact(handle)!.unreadMessages = 0; + var previouslySelected = Provider.of(context, listen: false).selectedConversation; + if (previouslySelected != null) { + Provider + .of(context, listen: false) + .contactList + .getContact(previouslySelected)! + .unselected(); + } + Provider.of(context, listen: false).contactList.getContact(handle)!.selected(); // triggers update in Double/TripleColumnView Provider.of(context, listen: false).initialScrollIndex = initialIndex; Provider.of(context, listen: false).selectedConversation = handle; diff --git a/lib/widgets/messagelist.dart b/lib/widgets/messagelist.dart index ec644504..6dd3a69d 100644 --- a/lib/widgets/messagelist.dart +++ b/lib/widgets/messagelist.dart @@ -1,6 +1,7 @@ import 'package:cwtch/models/appstate.dart'; import 'package:cwtch/models/contact.dart'; import 'package:cwtch/models/message.dart'; +import 'package:cwtch/models/messagecache.dart'; import 'package:cwtch/models/profile.dart'; import 'package:cwtch/widgets/messageloadingbubble.dart'; import 'package:flutter/material.dart'; @@ -8,6 +9,7 @@ import 'package:flutter/rendering.dart'; import 'package:provider/provider.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import '../main.dart'; import '../settings.dart'; class MessageList extends StatefulWidget { @@ -22,6 +24,13 @@ class MessageList extends StatefulWidget { class _MessageListState extends State { @override Widget build(BuildContext outerContext) { + // On Android we can have unsynced messages at the front of the index from when the UI was asleep, if there are some, kick off sync of those first + if (Provider.of(outerContext).messageCache.indexUnsynced != 0) { + var conversationId = Provider.of(context, listen: false).selectedConversation!; + MessageCache? cache = Provider.of(context, listen: false).contactList.getContact(conversationId)?.messageCache; + ByIndex(Provider.of(context, listen: false).selectedIndex!).loadUnsynced(Provider.of(context, listen: false).cwtch, Provider.of(context, listen: false).selectedProfile!, conversationId, cache!); + } + var initi = Provider.of(outerContext, listen: false).initialScrollIndex; bool isP2P = !Provider.of(context).isGroup; bool isGroupAndSyncing = Provider.of(context).isGroup == true && Provider.of(context).status == "Authenticated"; From 0647a2d98d365b3042dec83b2b82437af03df903 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 28 Apr 2022 16:19:32 -0700 Subject: [PATCH 2/3] android pre load unsynced messages --- lib/models/messagecache.dart | 2 -- lib/views/messageview.dart | 10 ++++++++++ lib/widgets/messagelist.dart | 8 ++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/models/messagecache.dart b/lib/models/messagecache.dart index b6f89059..9c218930 100644 --- a/lib/models/messagecache.dart +++ b/lib/models/messagecache.dart @@ -101,8 +101,6 @@ class MessageCache extends ChangeNotifier { // On android reconnect, if backend supplied message count > UI message count, add the differnce to the front of the index void addFrontIndexGap(int count) { this._indexUnsynced = count; - // TODO: needed? maybe not? since after totalmessatges and profile will notify - //notifyListeners(); } int get indexUnsynced => _indexUnsynced; diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index dbf976b9..78bafa76 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -168,6 +168,16 @@ class _MessageViewState extends State { Future _onWillPop() async { Provider.of(context, listen: false).unreadMessages = 0; + + var previouslySelected = Provider.of(context, listen: false).selectedConversation; + if (previouslySelected != null) { + Provider + .of(context, listen: false) + .contactList + .getContact(previouslySelected)! + .unselected(); + } + Provider.of(context, listen: false).selectedConversation = null; return true; } diff --git a/lib/widgets/messagelist.dart b/lib/widgets/messagelist.dart index 6dd3a69d..f5100234 100644 --- a/lib/widgets/messagelist.dart +++ b/lib/widgets/messagelist.dart @@ -25,10 +25,10 @@ class _MessageListState extends State { @override Widget build(BuildContext outerContext) { // On Android we can have unsynced messages at the front of the index from when the UI was asleep, if there are some, kick off sync of those first - if (Provider.of(outerContext).messageCache.indexUnsynced != 0) { - var conversationId = Provider.of(context, listen: false).selectedConversation!; - MessageCache? cache = Provider.of(context, listen: false).contactList.getContact(conversationId)?.messageCache; - ByIndex(Provider.of(context, listen: false).selectedIndex!).loadUnsynced(Provider.of(context, listen: false).cwtch, Provider.of(context, listen: false).selectedProfile!, conversationId, cache!); + if (Provider.of(context).messageCache.indexUnsynced != 0) { + var conversationId = Provider.of(outerContext, listen: false).selectedConversation!; + MessageCache? cache = Provider.of(outerContext, listen: false).contactList.getContact(conversationId)?.messageCache; + ByIndex(0).loadUnsynced(Provider.of(context, listen: false).cwtch, Provider.of(outerContext, listen: false).selectedProfile!, conversationId, cache!); } var initi = Provider.of(outerContext, listen: false).initialScrollIndex; From ffa51e83a19568253d346341b884d2afbe07928c Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 29 Apr 2022 16:00:52 -0700 Subject: [PATCH 3/3] new message marker moved from id to index and now works on old messages --- lib/models/contact.dart | 15 +++++++++------ lib/models/message.dart | 23 ++++++++++++----------- lib/models/messagecache.dart | 7 ------- lib/models/messages/filemessage.dart | 12 ++++++------ lib/models/messages/invitemessage.dart | 6 +++--- lib/models/messages/malformedmessage.dart | 4 ++-- lib/models/messages/quotedmessage.dart | 4 ++-- lib/models/messages/textmessage.dart | 4 ++-- lib/widgets/messagelist.dart | 2 +- lib/widgets/messagerow.dart | 9 +++------ 10 files changed, 40 insertions(+), 46 deletions(-) diff --git a/lib/models/contact.dart b/lib/models/contact.dart index 56bfe8b3..5cbdd5cf 100644 --- a/lib/models/contact.dart +++ b/lib/models/contact.dart @@ -42,7 +42,7 @@ class ContactInfoState extends ChangeNotifier { late int _totalMessages = 0; late DateTime _lastMessageTime; late Map> keys; - int _newMarkerMsgId = -1; + int _newMarkerMsgIndex = -1; late MessageCache messageCache; // todo: a nicer way to model contacts, groups and other "entities" @@ -145,11 +145,12 @@ class ContactInfoState extends ChangeNotifier { } void selected() { + this._newMarkerMsgIndex = this._unreadMessages-1; this._unreadMessages = 0; } void unselected() { - this._newMarkerMsgId = -1; + this._newMarkerMsgIndex = -1; } int get unreadMessages => this._unreadMessages; @@ -159,8 +160,8 @@ class ContactInfoState extends ChangeNotifier { notifyListeners(); } - int get newMarkerMsgId { - return this._newMarkerMsgId; + int get newMarkerMsgIndex { + return this._newMarkerMsgIndex; } int get totalMessages => this._totalMessages; @@ -240,8 +241,10 @@ class ContactInfoState extends ChangeNotifier { if (!selectedConversation) { unreadMessages++; } - if (_newMarkerMsgId == -1) { - _newMarkerMsgId = messageID; + if (_newMarkerMsgIndex == -1) { + _newMarkerMsgIndex = 0; + } else { + _newMarkerMsgIndex++; } this._lastMessageTime = timestamp; diff --git a/lib/models/message.dart b/lib/models/message.dart index d7786fdf..67e0bc02 100644 --- a/lib/models/message.dart +++ b/lib/models/message.dart @@ -32,33 +32,34 @@ const GroupConversationHandleLength = 32; abstract class Message { MessageMetadata getMetadata(); - Widget getWidget(BuildContext context, Key key); + Widget getWidget(BuildContext context, Key key, int index); Widget getPreviewWidget(BuildContext context); } -Message compileOverlay(MessageMetadata metadata, String messageData) { - try { - dynamic message = jsonDecode(messageData); +Message compileOverlay(MessageInfo messageInfo) { + + try { + dynamic message = jsonDecode(messageInfo.wrapper); var content = message['d'] as dynamic; var overlay = int.parse(message['o'].toString()); switch (overlay) { case TextMessageOverlay: - return TextMessage(metadata, content); + return TextMessage(messageInfo.metadata, content); case SuggestContactOverlay: case InviteGroupOverlay: - return InviteMessage(overlay, metadata, content); + return InviteMessage(overlay, messageInfo.metadata, content); case QuotedMessageOverlay: - return QuotedMessage(metadata, content); + return QuotedMessage(messageInfo.metadata, content); case FileShareOverlay: - return FileMessage(metadata, content); + return FileMessage(messageInfo.metadata, content); default: // Metadata is valid, content is not.. - return MalformedMessage(metadata); + return MalformedMessage(messageInfo.metadata); } } catch (e) { - return MalformedMessage(metadata); + return MalformedMessage(messageInfo.metadata); } } @@ -222,7 +223,7 @@ Future messageHandler(BuildContext context, String profileOnion, int co MessageInfo? messageInfo = await cacheHandler.get(cwtch, profileOnion, conversationIdentifier, cache); if (messageInfo != null) { - return compileOverlay(messageInfo.metadata, messageInfo.wrapper); + return compileOverlay(messageInfo); } else { return MalformedMessage(malformedMetadata); } diff --git a/lib/models/messagecache.dart b/lib/models/messagecache.dart index 9c218930..b2c348ce 100644 --- a/lib/models/messagecache.dart +++ b/lib/models/messagecache.dart @@ -105,13 +105,6 @@ class MessageCache extends ChangeNotifier { int get indexUnsynced => _indexUnsynced; - // TODO: unused? delete? - void resetIndexCache() { - this._indexUnsynced = 0; - cacheByIndex = List.empty(growable: true); - notifyListeners(); - } - MessageInfo? getById(int id) => cache[id]; Future getByIndex(int index) async { diff --git a/lib/models/messages/filemessage.dart b/lib/models/messages/filemessage.dart index c68b24e5..3ba18fad 100644 --- a/lib/models/messages/filemessage.dart +++ b/lib/models/messages/filemessage.dart @@ -18,13 +18,13 @@ class FileMessage extends Message { FileMessage(this.metadata, this.content); @override - Widget getWidget(BuildContext context, Key key) { + Widget getWidget(BuildContext context, Key key, int index) { return ChangeNotifierProvider.value( value: this.metadata, builder: (bcontext, child) { dynamic shareObj = jsonDecode(this.content); if (shareObj == null) { - return MessageRow(MalformedBubble()); + return MessageRow(MalformedBubble(), index); } String nameSuggestion = shareObj['f'] as String; String rootHash = shareObj['h'] as String; @@ -39,10 +39,10 @@ class FileMessage extends Message { } if (!validHash(rootHash, nonce)) { - return MessageRow(MalformedBubble()); + return MessageRow(MalformedBubble(), index); } - return MessageRow(FileBubble(nameSuggestion, rootHash, nonce, fileSize, isAuto: metadata.isAuto), key: key); + return MessageRow(FileBubble(nameSuggestion, rootHash, nonce, fileSize, isAuto: metadata.isAuto), index, key: key); }); } @@ -53,14 +53,14 @@ class FileMessage extends Message { builder: (bcontext, child) { dynamic shareObj = jsonDecode(this.content); if (shareObj == null) { - return MessageRow(MalformedBubble()); + return MessageRow(MalformedBubble(), 0); } String nameSuggestion = shareObj['n'] as String; String rootHash = shareObj['h'] as String; String nonce = shareObj['n'] as String; int fileSize = shareObj['s'] as int; if (!validHash(rootHash, nonce)) { - return MessageRow(MalformedBubble()); + return MessageRow(MalformedBubble(), 0); } return Container( alignment: Alignment.center, diff --git a/lib/models/messages/invitemessage.dart b/lib/models/messages/invitemessage.dart index 50a28806..02fc7512 100644 --- a/lib/models/messages/invitemessage.dart +++ b/lib/models/messages/invitemessage.dart @@ -17,7 +17,7 @@ class InviteMessage extends Message { InviteMessage(this.overlay, this.metadata, this.content); @override - Widget getWidget(BuildContext context, Key key) { + Widget getWidget(BuildContext context, Key key, int index) { return ChangeNotifierProvider.value( value: this.metadata, builder: (bcontext, child) { @@ -36,10 +36,10 @@ class InviteMessage extends Message { inviteTarget = jsonObj['GroupID']; inviteNick = jsonObj['GroupName']; } else { - return MessageRow(MalformedBubble()); + return MessageRow(MalformedBubble(), index); } } - return MessageRow(InvitationBubble(overlay, inviteTarget, inviteNick, invite), key: key); + return MessageRow(InvitationBubble(overlay, inviteTarget, inviteNick, invite), index, key: key); }); } diff --git a/lib/models/messages/malformedmessage.dart b/lib/models/messages/malformedmessage.dart index 0ebf2281..033663f2 100644 --- a/lib/models/messages/malformedmessage.dart +++ b/lib/models/messages/malformedmessage.dart @@ -9,11 +9,11 @@ class MalformedMessage extends Message { MalformedMessage(this.metadata); @override - Widget getWidget(BuildContext context, Key key) { + Widget getWidget(BuildContext context, Key key, int index) { return ChangeNotifierProvider.value( value: this.metadata, builder: (context, child) { - return MessageRow(MalformedBubble(), key: key); + return MessageRow(MalformedBubble(), index, key: key); }); } diff --git a/lib/models/messages/quotedmessage.dart b/lib/models/messages/quotedmessage.dart index c43ac12c..1519037a 100644 --- a/lib/models/messages/quotedmessage.dart +++ b/lib/models/messages/quotedmessage.dart @@ -48,7 +48,7 @@ class QuotedMessage extends Message { } @override - Widget getWidget(BuildContext context, Key key) { + Widget getWidget(BuildContext context, Key key, int index) { try { dynamic message = jsonDecode(this.content); @@ -59,7 +59,7 @@ class QuotedMessage extends Message { return ChangeNotifierProvider.value( value: this.metadata, builder: (bcontext, child) { - return MessageRow(QuotedMessageBubble(message["body"], messageHandler(bcontext, metadata.profileOnion, metadata.conversationIdentifier, ByContentHash(message["quotedHash"]))), key: key); + return MessageRow(QuotedMessageBubble(message["body"], messageHandler(bcontext, metadata.profileOnion, metadata.conversationIdentifier, ByContentHash(message["quotedHash"]))), index, key: key); }); } catch (e) { return MalformedBubble(); diff --git a/lib/models/messages/textmessage.dart b/lib/models/messages/textmessage.dart index ecfeab70..908a7d53 100644 --- a/lib/models/messages/textmessage.dart +++ b/lib/models/messages/textmessage.dart @@ -29,12 +29,12 @@ class TextMessage extends Message { } @override - Widget getWidget(BuildContext context, Key key) { + Widget getWidget(BuildContext context, Key key, int index) { return ChangeNotifierProvider.value( value: this.metadata, builder: (bcontext, child) { return MessageRow( - MessageBubble(this.content), + MessageBubble(this.content), index, key: key, ); }); diff --git a/lib/widgets/messagelist.dart b/lib/widgets/messagelist.dart index f5100234..6e5583e5 100644 --- a/lib/widgets/messagelist.dart +++ b/lib/widgets/messagelist.dart @@ -100,7 +100,7 @@ class _MessageListState extends State { // reliably use this without running into duplicate keys...it isn't ideal as it means keys need to be re-built // when new messages are added...however it is better than the alternative of not having widget keys at all. var key = Provider.of(outerContext, listen: false).getMessageKey(contactHandle, messageIndex); - return message.getWidget(context, key); + return message.getWidget(context, key, messageIndex); } else { return MessageLoadingBubble(); } diff --git a/lib/widgets/messagerow.dart b/lib/widgets/messagerow.dart index 710109e1..f52921c8 100644 --- a/lib/widgets/messagerow.dart +++ b/lib/widgets/messagerow.dart @@ -18,8 +18,9 @@ import '../settings.dart'; class MessageRow extends StatefulWidget { final Widget child; + final int index; - MessageRow(this.child, {Key? key}) : super(key: key); + MessageRow(this.child, this.index, {Key? key}) : super(key: key); @override MessageRowState createState() => MessageRowState(); @@ -32,12 +33,9 @@ class MessageRowState extends State with SingleTickerProviderStateMi late Alignment _dragAlignment = Alignment.center; Alignment _dragAffinity = Alignment.center; - late int index; - @override void initState() { super.initState(); - index = Provider.of(context, listen: false).messageID; _controller = AnimationController(vsync: this); _controller.addListener(() { setState(() { @@ -224,8 +222,7 @@ class MessageRowState extends State with SingleTickerProviderStateMi children: widgetRow, ))))); - var markMsgId = Provider.of(context).newMarkerMsgId; - if (markMsgId == Provider.of(context).messageID) { + if (Provider.of(context).newMarkerMsgIndex == widget.index) { return Column(crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [Align(alignment: Alignment.center, child: _bubbleNew()), mr]); } else { return mr;