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 messageID = int.parse(data["Index"]);
var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(conversation);
// We return -1 for protocol message acks if there is no message
if (messageID == -1) break;
var key = contact!.getMessageKeyOrFail(conversation, messageID);
if (key == null) break;
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...
// 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);
break;
case "NewMessageFromGroup":
var identifier = int.parse(data["ConversationID"]);
@ -259,12 +248,8 @@ class CwtchNotifier {
case "IndexedFailure":
var identifier = int.parse(data["ConversationID"]);
var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier);
var idx = int.parse(data["Index"]);
var key = contact?.getMessageKeyOrFail(contact.identifier, idx);
if (key != null) {
var message = Provider.of<MessageMetadata>(key.currentContext!, listen: false);
message.error = true;
}
var messageID = int.parse(data["Index"]);
contact!.errCache(messageID);
break;
case "AppError":
EnvironmentConfig.debugLog("New App Error: $data");

View File

@ -1,6 +1,8 @@
{
"@@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",
"successfullAddedContact": "Wedi llwyddo i ychwanegu: ",
"serverMetricsLabel": "Metrigau Gweinydd",
@ -281,9 +283,7 @@
"settingLanguage": "Laith",
"password": "Cyfrinair",
"addNewProfileBtn": "Ychwanegu proffil newydd",
"deleteConfirmText": "DELETE",
"deleteProfileConfirmBtn": "Dileu Proffil yn Wirioneddol",
"deleteConfirmLabel": "Teipiwch DELETE i gadarnhau",
"deleteProfileBtn": "Dileu Proffil",
"passwordErrorMatch": "Nid yw cyfrineiriau'n cyfateb",
"saveProfileBtn": "Cadw Proffil",

View File

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

View File

@ -1,6 +1,7 @@
{
"@@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",
"localeCy": "Walisisch",
"pasteAddressToAddContact": "Cwtch Adresse, Einladung oder Schlüssel hier hinzufügen, um eine neue Konversation hinzuzufügen",
@ -176,7 +177,6 @@
"yourServers": "Deine Server",
"yourProfiles": "Deine Profile",
"enterProfilePassword": "Gib ein Passwort ein, um deine Profile anzuzeigen",
"deleteConfirmLabel": "Gib LÖSCHEN ein um zu bestätigen",
"notificationNewMessageFromGroup": "Neue Nachricht in einer Gruppe!",
"notificationNewMessageFromPeer": "Neue Nachricht von einem Kontakt!",
"tooltipHidePassword": "Password verstecken",

View File

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

View File

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

View File

@ -1,6 +1,6 @@
{
"@@locale": "es",
"@@last_modified": "2022-03-03T19:10:17+01:00",
"@@last_modified": "2022-03-04T17:33:01+01:00",
"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",
"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",
"@@last_modified": "2022-03-03T19:10:17+01:00",
"@@last_modified": "2022-03-04T17:33:01+01:00",
"localeDa": "Danois",
"localeCy": "Gallois",
"conversationNotificationPolicySettingDescription": "Contrôler le comportement de notification de cette conversation",

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
{
"@@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",
"localeNo": "Norweski",
"localeEl": "Grecki",
@ -63,7 +64,6 @@
"addNewProfileBtn": "Dodaj",
"deleteConfirmText": "USUŃ",
"deleteProfileConfirmBtn": "Usuń",
"deleteConfirmLabel": "Wpisz USUŃ aby potwierdzić",
"deleteProfileBtn": "Usuń profil",
"passwordChangeError": "Zmiana hasła nie powiodła się: hasło niepoprawne",
"passwordErrorMatch": "Hasła nie są identyczne",

View File

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

View File

@ -1,6 +1,8 @@
{
"@@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ă",
"localeCy": "Velşă",
"conversationNotificationPolicySettingDescription": "Controlați comportamentul de notificare al acestei conversații",
@ -89,8 +91,6 @@
"passwordErrorMatch": "Parolele nu se potrivesc",
"passwordChangeError": "Eroare la schimbarea parolei: Parola furnizată a fost respinsă",
"deleteProfileBtn": "Ștergeți profilul",
"deleteConfirmLabel": "Tastați DELETE pentru a confirma",
"deleteProfileConfirmBtn": "Sigur ștergeti profilul",
"deleteConfirmText": "ȘTERGE",
"addNewProfileBtn": "Adăugați un profil nou",
"enterProfilePassword": "Introduceți o parolă pentru a vă vizualiza profilurile",

View File

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

View File

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

View File

@ -1,3 +1,5 @@
import 'package:flutter/foundation.dart';
import 'message.dart';
class MessageInfo {
@ -6,7 +8,7 @@ class MessageInfo {
MessageInfo(this.metadata, this.wrapper);
}
class MessageCache {
class MessageCache extends ChangeNotifier {
late Map<int, MessageInfo> cache;
late List<int?> cacheByIndex;
late Map<String, int> cacheByHash;
@ -35,6 +37,7 @@ class MessageCache {
if (contenthash != null && contenthash != "") {
this.cacheByHash[contenthash] = messageID;
}
notifyListeners();
}
void add(MessageInfo messageInfo, int index, String? contenthash) {
@ -43,6 +46,7 @@ class MessageCache {
if (contenthash != null && contenthash != "") {
this.cacheByHash[contenthash] = messageInfo.metadata.messageID;
}
notifyListeners();
}
void addUnindexed(MessageInfo messageInfo, String? contenthash) {
@ -50,9 +54,16 @@ class MessageCache {
if (contenthash != null && contenthash != "") {
this.cacheByHash[contenthash] = messageInfo.metadata.messageID;
}
notifyListeners();
}
void ackCache(int messageID) {
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
Widget build(BuildContext context) {
var fromMe = Provider.of<MessageMetadata>(context).senderHandle == Provider.of<ProfileInfoState>(context).onion;
var prettyDate = "";
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);
DateTime messageDate = Provider.of<MessageMetadata>(context).timestamp;

View File

@ -87,7 +87,10 @@ class _MessageListState extends State<MessageList> {
builder: (context, snapshot) {
if (snapshot.hasData) {
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);
} else {
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);
_dragAffinity = fromMe ? Alignment.centerRight : Alignment.centerLeft;
if (_dragAlignment == Alignment.center) {
_dragAlignment = fromMe ? Alignment.centerRight : Alignment.centerLeft;
}
_dragAlignment = fromMe ? Alignment.centerRight : Alignment.centerLeft;
var senderDisplayStr = "";
if (!fromMe) {