🐛 Add well defined mounted check in messages notifier

This commit is contained in:
2026-01-11 12:53:57 +08:00
parent eec181da55
commit bf59108569

View File

@@ -128,7 +128,7 @@ class MessagesNotifier extends _$MessagesNotifier {
uniqueMessages.add(message);
}
}
state = AsyncValue.data(uniqueMessages);
if (ref.mounted) state = AsyncValue.data(uniqueMessages);
} finally {
_isUpdatingState = false;
}
@@ -350,7 +350,7 @@ class MessagesNotifier extends _$MessagesNotifier {
offset: 0,
take: _pageSize,
);
state = AsyncValue.data(newMessages);
if (ref.mounted) state = AsyncValue.data(newMessages);
return;
}
@@ -408,7 +408,9 @@ class MessagesNotifier extends _$MessagesNotifier {
} finally {
talker.log('Finished message sync');
// Always reset global syncing state, regardless of disposal
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(false));
Future.microtask(() {
if (ref.mounted) ref.read(chatSyncingProvider.notifier).set(false);
});
_isSyncing = false;
}
}
@@ -498,7 +500,7 @@ class MessagesNotifier extends _$MessagesNotifier {
_hasMore = messages.length == _pageSize;
state = AsyncValue.data(messages);
if (ref.mounted) state = AsyncValue.data(messages);
}
Future<void> loadMore() async {
@@ -509,7 +511,7 @@ class MessagesNotifier extends _$MessagesNotifier {
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(true));
}
try {
final currentMessages = state.value ?? [];
final currentMessages = (ref.mounted ? state.value : null) ?? [];
final offset = currentMessages.length;
final newMessages = await listMessages(offset: offset, take: _pageSize);
@@ -518,9 +520,11 @@ class MessagesNotifier extends _$MessagesNotifier {
_hasMore = false;
}
state = AsyncValue.data(
_sortMessages([...currentMessages, ...newMessages]),
);
if (ref.mounted) {
state = AsyncValue.data(
_sortMessages([...currentMessages, ...newMessages]),
);
}
} catch (err, stackTrace) {
talker.log(
'Error loading more messages',
@@ -531,12 +535,14 @@ class MessagesNotifier extends _$MessagesNotifier {
showErrorAlert(err);
} finally {
// Always reset global syncing state, regardless of disposal
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(false));
Future.microtask(() {
if (ref.mounted) ref.read(chatSyncingProvider.notifier).set(false);
});
}
}
Future<void> sendMessage(
WidgetRef ref,
WidgetRef outerRef,
String content,
List<UniversalFile> attachments, {
SnPoll? poll,
@@ -569,14 +575,14 @@ class MessagesNotifier extends _$MessagesNotifier {
_fileUploadProgress[localMessage.id] = {};
await _database.saveMessageWithSender(localMessage);
final currentMessages = state.value ?? [];
final currentMessages = (ref.mounted ? state.value : null) ?? [];
state = AsyncValue.data([localMessage, ...currentMessages]);
try {
var cloudAttachments = List.empty(growable: true);
for (var idx = 0; idx < attachments.length; idx++) {
final cloudFile = await FileUploader.createCloudFile(
ref: ref,
ref: outerRef,
fileData: attachments[idx],
onProgress: (progress, _) {
_fileUploadProgress[localMessage.id]?[idx] = progress ?? 0.0;
@@ -619,24 +625,27 @@ class MessagesNotifier extends _$MessagesNotifier {
await _database.deleteMessage(localMessage.id);
await _database.saveMessageWithSender(updatedMessage);
final currentMessages = state.value ?? [];
if (editingTo != null) {
final newMessages = currentMessages
.where((m) => m.id != localMessage.id) // remove pending message
.map(
(m) => m.id == editingTo.id ? updatedMessage : m,
) // update original message
.toList();
state = AsyncValue.data(newMessages);
} else {
final newMessages = currentMessages.map((m) {
if (m.id == localMessage.id) {
return updatedMessage;
}
return m;
}).toList();
state = AsyncValue.data(newMessages);
if (ref.mounted) {
final currentMessages = state.value ?? [];
if (editingTo != null) {
final newMessages = currentMessages
.where((m) => m.id != localMessage.id) // remove pending message
.map(
(m) => m.id == editingTo.id ? updatedMessage : m,
) // update original message
.toList();
state = AsyncValue.data(newMessages);
} else {
final newMessages = currentMessages.map((m) {
if (m.id == localMessage.id) {
return updatedMessage;
}
return m;
}).toList();
state = AsyncValue.data(newMessages);
}
}
talker.log('Message with nonce $nonce sent successfully');
} catch (e, stackTrace) {
talker.log(
@@ -651,13 +660,15 @@ class MessagesNotifier extends _$MessagesNotifier {
localMessage.id,
MessageStatus.failed,
);
final newMessages = (state.value ?? []).map((m) {
if (m.id == localMessage.id) {
return m..status = MessageStatus.failed;
}
return m;
}).toList();
state = AsyncValue.data(newMessages);
if (ref.mounted) {
final newMessages = (state.value ?? []).map((m) {
if (m.id == localMessage.id) {
return m..status = MessageStatus.failed;
}
return m;
}).toList();
state = AsyncValue.data(newMessages);
}
showErrorAlert(e);
}
}
@@ -698,13 +709,15 @@ class MessagesNotifier extends _$MessagesNotifier {
await _database.deleteMessage(pendingMessageId);
await _database.saveMessageWithSender(updatedMessage);
final newMessages = (state.value ?? []).map((m) {
if (m.id == pendingMessageId) {
return updatedMessage;
}
return m;
}).toList();
state = AsyncValue.data(newMessages);
if (ref.mounted) {
final newMessages = (state.value ?? []).map((m) {
if (m.id == pendingMessageId) {
return updatedMessage;
}
return m;
}).toList();
state = AsyncValue.data(newMessages);
}
} catch (e, stackTrace) {
talker.log(
'Failed to retry message $pendingMessageId',
@@ -718,13 +731,15 @@ class MessagesNotifier extends _$MessagesNotifier {
pendingMessageId,
MessageStatus.failed,
);
final newMessages = (state.value ?? []).map((m) {
if (m.id == pendingMessageId) {
return m..status = MessageStatus.failed;
}
return m;
}).toList();
state = AsyncValue.data(_sortMessages(newMessages));
if (ref.mounted) {
final newMessages = (state.value ?? []).map((m) {
if (m.id == pendingMessageId) {
return m..status = MessageStatus.failed;
}
return m;
}).toList();
state = AsyncValue.data(_sortMessages(newMessages));
}
showErrorAlert(e);
}
}
@@ -756,21 +771,23 @@ class MessagesNotifier extends _$MessagesNotifier {
if (!isSilentMessage) {
await _database.saveMessageWithSender(localMessage);
final currentMessages = state.value ?? [];
final currentMessages = (ref.mounted ? state.value : null) ?? [];
final existingIndex = currentMessages.indexWhere(
(m) =>
m.id == localMessage.id ||
(localMessage.nonce != null && m.nonce == localMessage.nonce),
);
if (existingIndex >= 0) {
final newList = [...currentMessages];
newList[existingIndex] = localMessage;
state = AsyncValue.data(_sortMessages(newList));
} else {
state = AsyncValue.data(
_sortMessages([localMessage, ...currentMessages]),
);
if (ref.mounted) {
if (existingIndex >= 0) {
final newList = [...currentMessages];
newList[existingIndex] = localMessage;
state = AsyncValue.data(_sortMessages(newList));
} else {
state = AsyncValue.data(
_sortMessages([localMessage, ...currentMessages]),
);
}
}
}
@@ -837,13 +854,15 @@ class MessagesNotifier extends _$MessagesNotifier {
await _database.updateMessage(_database.messageToCompanion(updatedMessage));
final currentMessages = state.value ?? [];
final currentMessages = (ref.mounted ? state.value : null) ?? [];
final index = currentMessages.indexWhere((m) => m.id == updatedMessage.id);
if (index >= 0) {
final newList = [...currentMessages];
newList[index] = updatedMessage;
state = AsyncValue.data(_sortMessages(newList));
if (ref.mounted) {
if (index >= 0) {
final newList = [...currentMessages];
newList[index] = updatedMessage;
state = AsyncValue.data(_sortMessages(newList));
}
}
}
@@ -857,7 +876,7 @@ class MessagesNotifier extends _$MessagesNotifier {
talker.log('Received message deletion $messageId');
_pendingMessages.remove(messageId);
final currentMessages = state.value ?? [];
final currentMessages = (ref.mounted ? state.value : null) ?? [];
final messageIndex = currentMessages.indexWhere((m) => m.id == messageId);
LocalChatMessage? messageToUpdate;
@@ -883,10 +902,12 @@ class MessagesNotifier extends _$MessagesNotifier {
await _database.saveMessageWithSender(deletedMessage);
if (messageIndex != -1) {
final newList = [...currentMessages];
newList[messageIndex] = deletedMessage;
state = AsyncValue.data(newList);
if (ref.mounted) {
if (messageIndex != -1) {
final newList = [...currentMessages];
newList[messageIndex] = deletedMessage;
state = AsyncValue.data(newList);
}
}
}
@@ -907,7 +928,7 @@ class MessagesNotifier extends _$MessagesNotifier {
_pendingMessages.remove(messageId);
await _database.deleteMessage(messageId);
final currentMessages = state.value ?? [];
final currentMessages = (ref.mounted ? state.value : null) ?? [];
final newMessages = currentMessages
.where((m) => m.id != messageId)
.toList();
@@ -1063,7 +1084,7 @@ class MessagesNotifier extends _$MessagesNotifier {
}
// Check if message is already in current state to avoid duplicate loading
final currentMessages = state.value ?? [];
final currentMessages = (ref.mounted ? state.value : null) ?? [];
final existingIndex = currentMessages.indexWhere(
(m) => m.id == messageId,
);