diff --git a/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt b/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt index d2eafd73..7d19a003 100644 --- a/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt +++ b/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt @@ -331,8 +331,9 @@ class MainActivity: FlutterActivity() { val conversation: Int = call.argument("conversation") ?: 0 val indexI: Int = call.argument("index") ?: 0 val count: Int = call.argument("count") ?: 1 + val ucount : Int = maxOf(1, count) // don't allow negative counts - result.success(Cwtch.getMessages(profile, conversation.toLong(), indexI.toLong(), count.toLong())) + result.success(Cwtch.getMessages(profile, conversation.toLong(), indexI.toLong(), ucount.toLong())) return } "SendMessage" -> { diff --git a/lib/models/contact.dart b/lib/models/contact.dart index e0931169..851b54a0 100644 --- a/lib/models/contact.dart +++ b/lib/models/contact.dart @@ -230,6 +230,7 @@ class ContactInfoState extends ChangeNotifier { return this._newMarkerMsgIndex; } + int get totalMessages => this._totalMessages; int get totalMessages => this._totalMessages; set totalMessages(int newVal) { diff --git a/lib/models/messagecache.dart b/lib/models/messagecache.dart index b1807a0a..94bb834e 100644 --- a/lib/models/messagecache.dart +++ b/lib/models/messagecache.dart @@ -30,22 +30,27 @@ class LocalIndexMessage { this.messageId = messageId; this.cacheOnly = cacheOnly; this.isLoading = isLoading; - if (isLoading) { - loader = Completer(); - loaded = loader.future; + loader = Completer(); + loaded = loader.future; + if (!isLoading) { + loader.complete(); // complete this } } void finishLoad(int messageId) { this.messageId = messageId; - isLoading = false; - loader.complete(true); + if (!loader.isCompleted) { + isLoading = false; + loader.complete(true); + } } void failLoad() { this.messageId = null; - isLoading = false; - loader.complete(true); + if (!loader.isCompleted) { + isLoading = false; + loader.complete(true); + } } Future waitForLoad() { @@ -95,7 +100,7 @@ class MessageCache extends ChangeNotifier { this._storageMessageCount = newval; } - // On android reconnect, if backend supplied message count > UI message count, add the differnce to the front of the index + // On android reconnect, if backend supplied message count > UI message count, add the difference to the front of the index void addFrontIndexGap(int count) { this._indexUnsynced = count; } diff --git a/lib/models/profile.dart b/lib/models/profile.dart index 3269f25a..a1e62ac3 100644 --- a/lib/models/profile.dart +++ b/lib/models/profile.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:math'; import 'package:cwtch/config.dart'; import 'package:cwtch/models/remoteserver.dart'; @@ -248,8 +249,22 @@ class ProfileInfoState extends ChangeNotifier { if (profileContact != null) { profileContact.status = contact["status"]; - var newCount = contact["numMessages"]; + var newCount = contact["numMessages"] as int; if (newCount != profileContact.totalMessages) { + if (newCount < profileContact.totalMessages) { + // on Android, when sharing a file the UI may be briefly unloaded for the + // OS to display the file management/selection screen. Afterwards a + // call to ReconnectCwtchForeground will be made which will refresh all values (including count of numMessages) + // **at the same time** the foreground will increment .totalMessages and send a new message to the backend. + // This will result in a negative number of messages being calculated here, and an incorrect totalMessage count. + // This bug is exacerbated in debug mode, and when multiple files are sent in succession. Both cases result in multiple ReconnectCwtchForeground + // events that have the potential to conflict with currentMessageCounts. + // Note that *if* a new message came in at the same time, we would be unable to distinguish this case - as such this is specific instance of a more general problem + // TODO: A true-fix to this bug is to implement a syncing step in the foreground where totalMessages and inFlightMessages can be distinguished + // This requires a change to the backend to confirm submission of an inFlightMessage, which will be implemented in #664 + EnvironmentConfig.debugLog("Conflicting message counts: $newCount ${profileContact.totalMessages}"); + newCount = max(newCount, profileContact.totalMessages); + } profileContact.messageCache.addFrontIndexGap(newCount - profileContact.totalMessages); } profileContact.totalMessages = newCount;