Merge pull request 'Stop using key-based lookups for messages, use the message cache instead.' (#392) from message_row_fixes into trunk
continuous-integration/drone/push Build is pending Details

Reviewed-on: #392
This commit is contained in:
Dan Ballard 2022-03-04 21:14:34 +00:00
commit 8eaa3974c9
20 changed files with 53 additions and 54 deletions

View File

@ -192,25 +192,14 @@ class CwtchNotifier {
var conversation = int.parse(data["ConversationID"]); var conversation = int.parse(data["ConversationID"]);
var messageID = int.parse(data["Index"]); var messageID = int.parse(data["Index"]);
var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(conversation); // We only ever see acks from authenticated peers.
// We return -1 for protocol message acks if there is no message // If the contact is marked as offline then override this - can happen when the contact is removed from the front
if (messageID == -1) break; // end during syncing.
var key = contact!.getMessageKeyOrFail(conversation, messageID); if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(conversation)!.isOnline() == false) {
if (key == null) break; profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(conversation)!.status = "Authenticated";
try {
var message = Provider.of<MessageMetadata>(key.currentContext!, listen: false);
message.ackd = true;
// We only ever see acks from authenticated peers.
// If the contact is marked as offline then override this - can happen when the contact is removed from the front
// end during syncing.
if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(conversation)!.isOnline() == false) {
profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(conversation)!.status = "Authenticated";
}
profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(conversation)!.ackCache(messageID);
} catch (e) {
// ignore, most likely cause is the key got optimized out...
} }
profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(conversation)!.ackCache(messageID);
break; break;
case "NewMessageFromGroup": case "NewMessageFromGroup":
var identifier = int.parse(data["ConversationID"]); var identifier = int.parse(data["ConversationID"]);
@ -259,12 +248,8 @@ class CwtchNotifier {
case "IndexedFailure": case "IndexedFailure":
var identifier = int.parse(data["ConversationID"]); var identifier = int.parse(data["ConversationID"]);
var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier); var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier);
var idx = int.parse(data["Index"]); var messageID = int.parse(data["Index"]);
var key = contact?.getMessageKeyOrFail(contact.identifier, idx); contact!.errCache(messageID);
if (key != null) {
var message = Provider.of<MessageMetadata>(key.currentContext!, listen: false);
message.error = true;
}
break; break;
case "AppError": case "AppError":
EnvironmentConfig.debugLog("New App Error: $data"); EnvironmentConfig.debugLog("New App Error: $data");

View File

@ -1,6 +1,8 @@
{ {
"@@locale": "cy", "@@locale": "cy",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"deleteConfirmLabel": "Teipiwch DILEU i gadarnhau",
"deleteConfirmText": "DILEU",
"localeDa": "Daneg", "localeDa": "Daneg",
"successfullAddedContact": "Wedi llwyddo i ychwanegu: ", "successfullAddedContact": "Wedi llwyddo i ychwanegu: ",
"serverMetricsLabel": "Metrigau Gweinydd", "serverMetricsLabel": "Metrigau Gweinydd",
@ -281,9 +283,7 @@
"settingLanguage": "Laith", "settingLanguage": "Laith",
"password": "Cyfrinair", "password": "Cyfrinair",
"addNewProfileBtn": "Ychwanegu proffil newydd", "addNewProfileBtn": "Ychwanegu proffil newydd",
"deleteConfirmText": "DELETE",
"deleteProfileConfirmBtn": "Dileu Proffil yn Wirioneddol", "deleteProfileConfirmBtn": "Dileu Proffil yn Wirioneddol",
"deleteConfirmLabel": "Teipiwch DELETE i gadarnhau",
"deleteProfileBtn": "Dileu Proffil", "deleteProfileBtn": "Dileu Proffil",
"passwordErrorMatch": "Nid yw cyfrineiriau'n cyfateb", "passwordErrorMatch": "Nid yw cyfrineiriau'n cyfateb",
"saveProfileBtn": "Cadw Proffil", "saveProfileBtn": "Cadw Proffil",

View File

@ -1,6 +1,6 @@
{ {
"@@locale": "da", "@@locale": "da",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"serverLabel": "Server", "serverLabel": "Server",
"profileOnionLabel": "Send denne adresse til personer du ønsker forbindelse med", "profileOnionLabel": "Send denne adresse til personer du ønsker forbindelse med",
"saveBtn": "Gem", "saveBtn": "Gem",

View File

@ -1,6 +1,7 @@
{ {
"@@locale": "de", "@@locale": "de",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"deleteConfirmLabel": "Gib LÖSCHEN ein, um zu bestätigen",
"localeDa": "Dänisch", "localeDa": "Dänisch",
"localeCy": "Walisisch", "localeCy": "Walisisch",
"pasteAddressToAddContact": "Cwtch Adresse, Einladung oder Schlüssel hier hinzufügen, um eine neue Konversation hinzuzufügen", "pasteAddressToAddContact": "Cwtch Adresse, Einladung oder Schlüssel hier hinzufügen, um eine neue Konversation hinzuzufügen",
@ -176,7 +177,6 @@
"yourServers": "Deine Server", "yourServers": "Deine Server",
"yourProfiles": "Deine Profile", "yourProfiles": "Deine Profile",
"enterProfilePassword": "Gib ein Passwort ein, um deine Profile anzuzeigen", "enterProfilePassword": "Gib ein Passwort ein, um deine Profile anzuzeigen",
"deleteConfirmLabel": "Gib LÖSCHEN ein um zu bestätigen",
"notificationNewMessageFromGroup": "Neue Nachricht in einer Gruppe!", "notificationNewMessageFromGroup": "Neue Nachricht in einer Gruppe!",
"notificationNewMessageFromPeer": "Neue Nachricht von einem Kontakt!", "notificationNewMessageFromPeer": "Neue Nachricht von einem Kontakt!",
"tooltipHidePassword": "Password verstecken", "tooltipHidePassword": "Password verstecken",

View File

@ -1,6 +1,6 @@
{ {
"@@locale": "el", "@@locale": "el",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"localeCy": "Ουαλικά", "localeCy": "Ουαλικά",
"localeDa": "Δανικά", "localeDa": "Δανικά",
"server": "Διακομιστής", "server": "Διακομιστής",

View File

@ -1,6 +1,6 @@
{ {
"@@locale": "en", "@@locale": "en",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"localeDa": "Danish", "localeDa": "Danish",
"localeCy": "Welsh", "localeCy": "Welsh",
"localeEl": "Greek", "localeEl": "Greek",

View File

@ -1,6 +1,6 @@
{ {
"@@locale": "es", "@@locale": "es",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"localeDa": "Danés", "localeDa": "Danés",
"groupInviteSettingsWarning": "¡Has recibido una invitación para unirte a un grupo! Por favor habilita el experimento de chat grupal en Configuración para ver esta invitación", "groupInviteSettingsWarning": "¡Has recibido una invitación para unirte a un grupo! Por favor habilita el experimento de chat grupal en Configuración para ver esta invitación",
"plainServerDescription": "Te recomendamos que protejas tus servidores de Cwtch con una contraseña. Si no estableces una contraseña en este servidor, cualquiera que tenga acceso a este dispositivo podrá acceder a la información sobre este servidor incluyendo claves criptográficas confidenciales", "plainServerDescription": "Te recomendamos que protejas tus servidores de Cwtch con una contraseña. Si no estableces una contraseña en este servidor, cualquiera que tenga acceso a este dispositivo podrá acceder a la información sobre este servidor incluyendo claves criptográficas confidenciales",

View File

@ -1,6 +1,6 @@
{ {
"@@locale": "fr", "@@locale": "fr",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"localeDa": "Danois", "localeDa": "Danois",
"localeCy": "Gallois", "localeCy": "Gallois",
"conversationNotificationPolicySettingDescription": "Contrôler le comportement de notification de cette conversation", "conversationNotificationPolicySettingDescription": "Contrôler le comportement de notification de cette conversation",

View File

@ -1,6 +1,6 @@
{ {
"@@locale": "it", "@@locale": "it",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"localeDa": "Danese", "localeDa": "Danese",
"localeCy": "Gallese", "localeCy": "Gallese",
"settingTheme": "Usa Temi Leggeri", "settingTheme": "Usa Temi Leggeri",

View File

@ -1,6 +1,6 @@
{ {
"@@locale": "lb", "@@locale": "lb",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"localeDa": "Danish", "localeDa": "Danish",
"localeCy": "Welsh", "localeCy": "Welsh",
"serverSynced": "Synchroniséiert", "serverSynced": "Synchroniséiert",

View File

@ -1,6 +1,6 @@
{ {
"@@locale": "no", "@@locale": "no",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"localeDa": "Dansk", "localeDa": "Dansk",
"localeCy": "Walisisk", "localeCy": "Walisisk",
"serverLabel": "Tjener", "serverLabel": "Tjener",

View File

@ -1,6 +1,7 @@
{ {
"@@locale": "pl", "@@locale": "pl",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"deleteConfirmLabel": "Wpisz USUŃ aby potwierdzić",
"localeLb": "Luksemburski", "localeLb": "Luksemburski",
"localeNo": "Norweski", "localeNo": "Norweski",
"localeEl": "Grecki", "localeEl": "Grecki",
@ -63,7 +64,6 @@
"addNewProfileBtn": "Dodaj", "addNewProfileBtn": "Dodaj",
"deleteConfirmText": "USUŃ", "deleteConfirmText": "USUŃ",
"deleteProfileConfirmBtn": "Usuń", "deleteProfileConfirmBtn": "Usuń",
"deleteConfirmLabel": "Wpisz USUŃ aby potwierdzić",
"deleteProfileBtn": "Usuń profil", "deleteProfileBtn": "Usuń profil",
"passwordChangeError": "Zmiana hasła nie powiodła się: hasło niepoprawne", "passwordChangeError": "Zmiana hasła nie powiodła się: hasło niepoprawne",
"passwordErrorMatch": "Hasła nie są identyczne", "passwordErrorMatch": "Hasła nie są identyczne",

View File

@ -1,6 +1,6 @@
{ {
"@@locale": "pt", "@@locale": "pt",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"localeDa": "Danish", "localeDa": "Danish",
"localeCy": "Welsh", "localeCy": "Welsh",
"localeEl": "Greek", "localeEl": "Greek",

View File

@ -1,6 +1,8 @@
{ {
"@@locale": "ro", "@@locale": "ro",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"deleteProfileConfirmBtn": "Sigur ștergeti profilul",
"deleteConfirmLabel": "Tastați ȘTERGE pentru a confirma",
"localeDa": "Daneză", "localeDa": "Daneză",
"localeCy": "Velşă", "localeCy": "Velşă",
"conversationNotificationPolicySettingDescription": "Controlați comportamentul de notificare al acestei conversații", "conversationNotificationPolicySettingDescription": "Controlați comportamentul de notificare al acestei conversații",
@ -89,8 +91,6 @@
"passwordErrorMatch": "Parolele nu se potrivesc", "passwordErrorMatch": "Parolele nu se potrivesc",
"passwordChangeError": "Eroare la schimbarea parolei: Parola furnizată a fost respinsă", "passwordChangeError": "Eroare la schimbarea parolei: Parola furnizată a fost respinsă",
"deleteProfileBtn": "Ștergeți profilul", "deleteProfileBtn": "Ștergeți profilul",
"deleteConfirmLabel": "Tastați DELETE pentru a confirma",
"deleteProfileConfirmBtn": "Sigur ștergeti profilul",
"deleteConfirmText": "ȘTERGE", "deleteConfirmText": "ȘTERGE",
"addNewProfileBtn": "Adăugați un profil nou", "addNewProfileBtn": "Adăugați un profil nou",
"enterProfilePassword": "Introduceți o parolă pentru a vă vizualiza profilurile", "enterProfilePassword": "Introduceți o parolă pentru a vă vizualiza profilurile",

View File

@ -1,6 +1,8 @@
{ {
"@@locale": "ru", "@@locale": "ru",
"@@last_modified": "2022-03-03T19:10:17+01:00", "@@last_modified": "2022-03-04T17:33:01+01:00",
"deleteConfirmLabel": "Введите УДАЛИТЬ, чтобы продолжить",
"deleteConfirmText": "УДАЛИТЬ",
"localeCy": "Валлийский", "localeCy": "Валлийский",
"localeDa": "Датский", "localeDa": "Датский",
"localeEl": "Греческий", "localeEl": "Греческий",
@ -241,9 +243,7 @@
"password": "Пароль", "password": "Пароль",
"enterProfilePassword": "Введите пароль для просмотра ваших профилей", "enterProfilePassword": "Введите пароль для просмотра ваших профилей",
"addNewProfileBtn": "Добавить новый профиль", "addNewProfileBtn": "Добавить новый профиль",
"deleteConfirmText": "УДАЛИТЬ",
"deleteProfileConfirmBtn": "Действительно удалить профиль?", "deleteProfileConfirmBtn": "Действительно удалить профиль?",
"deleteConfirmLabel": "Введите DELETE чтобы продолжить",
"deleteProfileBtn": "Удалить профиль", "deleteProfileBtn": "Удалить профиль",
"passwordChangeError": "Ошибка при смене пароля: Введенный пароль отклонен", "passwordChangeError": "Ошибка при смене пароля: Введенный пароль отклонен",
"passwordErrorMatch": "Пароли не совпадают", "passwordErrorMatch": "Пароли не совпадают",

View File

@ -276,6 +276,11 @@ class ContactInfoState extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void errCache(int messageID) {
this.messageCache.errCache(messageID);
notifyListeners();
}
static ConversationNotificationPolicy notificationPolicyFromString(String val) { static ConversationNotificationPolicy notificationPolicyFromString(String val) {
switch (val) { switch (val) {
case "ConversationNotificationPolicy.Default": case "ConversationNotificationPolicy.Default":

View File

@ -1,3 +1,5 @@
import 'package:flutter/foundation.dart';
import 'message.dart'; import 'message.dart';
class MessageInfo { class MessageInfo {
@ -6,7 +8,7 @@ class MessageInfo {
MessageInfo(this.metadata, this.wrapper); MessageInfo(this.metadata, this.wrapper);
} }
class MessageCache { class MessageCache extends ChangeNotifier {
late Map<int, MessageInfo> cache; late Map<int, MessageInfo> cache;
late List<int?> cacheByIndex; late List<int?> cacheByIndex;
late Map<String, int> cacheByHash; late Map<String, int> cacheByHash;
@ -35,6 +37,7 @@ class MessageCache {
if (contenthash != null && contenthash != "") { if (contenthash != null && contenthash != "") {
this.cacheByHash[contenthash] = messageID; this.cacheByHash[contenthash] = messageID;
} }
notifyListeners();
} }
void add(MessageInfo messageInfo, int index, String? contenthash) { void add(MessageInfo messageInfo, int index, String? contenthash) {
@ -43,6 +46,7 @@ class MessageCache {
if (contenthash != null && contenthash != "") { if (contenthash != null && contenthash != "") {
this.cacheByHash[contenthash] = messageInfo.metadata.messageID; this.cacheByHash[contenthash] = messageInfo.metadata.messageID;
} }
notifyListeners();
} }
void addUnindexed(MessageInfo messageInfo, String? contenthash) { void addUnindexed(MessageInfo messageInfo, String? contenthash) {
@ -50,9 +54,16 @@ class MessageCache {
if (contenthash != null && contenthash != "") { if (contenthash != null && contenthash != "") {
this.cacheByHash[contenthash] = messageInfo.metadata.messageID; this.cacheByHash[contenthash] = messageInfo.metadata.messageID;
} }
notifyListeners();
} }
void ackCache(int messageID) { void ackCache(int messageID) {
cache[messageID]?.metadata.ackd = true; cache[messageID]?.metadata.ackd = true;
notifyListeners();
}
void errCache(int messageID) {
cache[messageID]?.metadata.error = true;
notifyListeners();
} }
} }

View File

@ -30,9 +30,7 @@ class MessageBubbleState extends State<MessageBubble> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var fromMe = Provider.of<MessageMetadata>(context).senderHandle == Provider.of<ProfileInfoState>(context).onion; var fromMe = Provider.of<MessageMetadata>(context).senderHandle == Provider.of<ProfileInfoState>(context).onion;
var prettyDate = "";
var borderRadiousEh = 15.0; var borderRadiousEh = 15.0;
// var myKey = Provider.of<MessageState>(context).profileOnion + "::" + Provider.of<MessageState>(context).contactHandle + "::" + Provider.of<MessageState>(context).messageIndex.toString();
var showClickableLinks = Provider.of<Settings>(context).isExperimentEnabled(ClickableLinksExperiment); var showClickableLinks = Provider.of<Settings>(context).isExperimentEnabled(ClickableLinksExperiment);
DateTime messageDate = Provider.of<MessageMetadata>(context).timestamp; DateTime messageDate = Provider.of<MessageMetadata>(context).timestamp;

View File

@ -87,7 +87,10 @@ class _MessageListState extends State<MessageList> {
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
var message = snapshot.data as Message; var message = snapshot.data as Message;
var key = Provider.of<ContactInfoState>(outerContext, listen: false).getMessageKey(contactHandle, message.getMetadata().messageID); // here we create an index key for the contact and assign it to the row. Indexes are unique so we can
// 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<ContactInfoState>(outerContext, listen: false).getMessageKey(contactHandle, messageIndex);
return message.getWidget(context, key); return message.getWidget(context, key);
} else { } else {
return MessageLoadingBubble(); return MessageLoadingBubble();

View File

@ -63,10 +63,7 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
var actualMessage = Flexible(flex: Platform.isAndroid ? 10 : 3, fit: FlexFit.loose, child: widget.child); var actualMessage = Flexible(flex: Platform.isAndroid ? 10 : 3, fit: FlexFit.loose, child: widget.child);
_dragAffinity = fromMe ? Alignment.centerRight : Alignment.centerLeft; _dragAffinity = fromMe ? Alignment.centerRight : Alignment.centerLeft;
_dragAlignment = fromMe ? Alignment.centerRight : Alignment.centerLeft;
if (_dragAlignment == Alignment.center) {
_dragAlignment = fromMe ? Alignment.centerRight : Alignment.centerLeft;
}
var senderDisplayStr = ""; var senderDisplayStr = "";
if (!fromMe) { if (!fromMe) {