// ignore_for_file: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member part of 'chat_bloc.dart'; extension _ChatBlocAttachments on ChatBloc { void _syncUploadedAttachments({ required String messageId, required List uploadedAttachments, }) { if (uploadedAttachments.isEmpty) { _markAttachmentUploadDone(messageId); return; } final items = state.items.map((item) { if (item is! TextMessageItem || item.id != messageId) { return item; } final synced = item.attachments.map((attachment) { final localPath = attachment['path']; if (localPath is! String || localPath.isEmpty) { return {...attachment, 'uploading': false}; } UploadedAttachment? matched; for (final candidate in uploadedAttachments) { if (candidate.localPath == localPath) { matched = candidate; break; } } if (matched == null) { return {...attachment, 'uploading': false}; } return { ...attachment, 'url': matched.url, 'mimeType': matched.mimeType, 'uploading': false, }; }).toList(); return item.copyWith(attachments: synced); }).toList(); emit(state.copyWith(items: items)); } void _markAttachmentUploadDone(String messageId) { final items = state.items.map((item) { if (item is! TextMessageItem || item.id != messageId) { return item; } final done = item.attachments .map( (attachment) => { ...attachment, 'uploading': false, }, ) .toList(); return item.copyWith(attachments: done); }).toList(); emit(state.copyWith(items: items)); } Future _loadAttachmentPreview(String previewPath) async { final cached = _attachmentPreviewCache[previewPath]; if (cached != null) { return cached; } final pending = _attachmentPreviewInflight[previewPath]; if (pending != null) { return pending; } final future = (() async { try { final bytes = await _service.fetchAttachmentPreview(previewPath); _attachmentPreviewCache[previewPath] = bytes; return bytes; } catch (e, stackTrace) { _logger.error( message: 'Failed to load attachment preview', error: e, stackTrace: stackTrace, extra: {'preview_path': previewPath}, ); return null; } finally { _attachmentPreviewInflight.remove(previewPath); } })(); _attachmentPreviewInflight[previewPath] = future; return future; } }