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