231
Message finalMessage, {
232
required bool isCurrentContext,
233
}) async {
234
+ if (!ref.mounted) return;
235
final timeline = isCurrentContext
236
? state.messages
237
: MessageVariants.resolveActiveTimeline(
245
),
246
);
247
248
+ if (!ref.mounted) return;
249
final preview = finalMessage.content.length > 100
250
? '${finalMessage.content.substring(0, 100)}...'
251
: finalMessage.content;
262
characterCount: totalChars,
263
preview: preview,
264
);
265
+ if (!ref.mounted) return;
266
_recomputeConversationTotal(conversationId, messages: timeline);
267
268
if (isCurrentContext) {
318
}
319
320
Future<void> _tryResumeLastChat() async {
321
+ if (!ref.mounted) return;
322
final settings = ref.read(settingsProvider);
323
if (!settings.resumeLastChat) return;
324
if (state.messages.isNotEmpty || _currentConversationId != null) return;
329
330
try {
331
final conversations = await ref.read(conv.conversationsProvider.future);
332
+ if (!ref.mounted) return;
333
Conversation? target;
334
for (final conversation in conversations) {
335
if (conversation.id == lastId && !conversation.isTemporary) {
346
}
347
348
void _persistLastActiveConversation(String conversationId) {
349
+ if (!ref.mounted) return;
350
if (!ref.read(settingsProvider).resumeLastChat) return;
351
ref
352
.read(sharedPreferencesProvider)
355
356
Future<void> loadConversation(Conversation conversation) async {
357
await cancelStream();
358
+ if (!ref.mounted) return;
359
_currentConversationId = conversation.id;
360
ref.read(smartReplyServiceProvider).reset();
361
state = state.copyWith(
373
conversation.id,
374
);
375
376
+ if (!ref.mounted) return;
377
+
378
state = ChatState(
379
allMessages: messages,
380
messages: MessageVariants.resolveActiveTimeline(messages),
394
.setEnabled(conversation.mcpEnabled ?? false);
395
} catch (e, stackTrace) {
396
Log.fatal(error: e, stackTrace: stackTrace);
388
- state = state.copyWith(
389
- isLoading: false,
390
- errorMessage: 'Failed to load conversation: $e',
391
- );
397
+ if (ref.mounted) {
398
+ state = state.copyWith(
399
+ isLoading: false,
400
+ errorMessage: 'Failed to load conversation: $e',
401
+ );
402
+ }
403
}
404
}
405
722
isTemporary: false,
723
folderId: ref.read(pendingNewChatFolderIdProvider.notifier).consume(),
724
);
725
+ if (!ref.mounted) return;
726
_currentConversationId = conversation.id;
727
ref
728
.read(conv.activeConversationIdProvider.notifier)
1551
if (!_titleGenerationsInFlight.add(conversationId)) return;
1552
try {
1553
final title = await generateTitleWithAi(conversationId);
1554
+ if (!ref.mounted) return;
1555
if (title == null || title.isEmpty || title == 'New Chat') return;
1556
1557
await ref
1564
1565
Future<String?> generateTitleWithAi(String conversationId) async {
1566
final messages = await _loadMessagesForConversation(conversationId);
1567
+ if (!ref.mounted) return null;
1568
if (messages.isEmpty) return null;
1569
1570
final timeline = MessageVariants.resolveActiveTimeline(messages);
1597
params: ref.read(chatParamsProvider),
1598
);
1599
1600
+ if (!ref.mounted) return null;
1601
if (generated != null && generated.isNotEmpty) {
1602
return generated;
1603
}
2100
stopReason: 'error',
2101
);
2102
await _saveMessage(streamingAssistantMessage);
2088
- if (isCurrentContext) {
2089
- _replaceMessageInAll(
2090
- streamingAssistantMessage,
2091
- clearStreaming: true,
2092
- );
2093
- state = state.copyWith(
2094
- isStreaming: false,
2095
- clearStreaming: true,
2096
- );
2103
+ if (ref.mounted) {
2104
+ if (isCurrentContext) {
2105
+ _replaceMessageInAll(
2106
+ streamingAssistantMessage,
2107
+ clearStreaming: true,
2108
+ );
2109
+ state = state.copyWith(
2110
+ isStreaming: false,
2111
+ clearStreaming: true,
2112
+ );
2113
+ }
2114
+ ref.read(isStreamingProvider.notifier).setStreaming(false);
2115
+ ref.read(chatBackgroundServiceProvider).stop();
2116
}
2098
- ref.read(isStreamingProvider.notifier).setStreaming(false);
2099
- ref.read(chatBackgroundServiceProvider).stop();
2117
break;
2118
case ChatResponseType.done:
2119
if (response.stats != null) {
2144
stopReason: 'complete',
2145
);
2146
await _saveMessage(finalMessage);
2147
+ if (!ref.mounted) return;
2148
if (isCurrentContext) {
2149
_replaceMessageInAll(finalMessage, clearStreaming: true);
2150
state = state.copyWith(
2159
finalMessage,
2160
isCurrentContext: isCurrentContext,
2161
);
2162
+ if (!ref.mounted) return;
2163
_maybeRequestReviewAfterSuccessfulCompletion(
2164
finalMessage: finalMessage,
2165
server: server,
2195
isProcessing: false,
2196
);
2197
await _saveMessage(errorMessage);
2198
+ if (!ref.mounted) return;
2199
if (isCurrentContext) {
2200
_replaceMessageInAll(errorMessage, clearStreaming: true);
2201
state = state.copyWith(