import '../../core/protocol/opcode_map.dart'; import '../../core/utils/logger.dart'; import '../../models/attachment.dart'; import '../api.dart'; const Map _attachTypeByName = { 'PHOTO': AttachmentType.photo, 'VIDEO': AttachmentType.video, 'AUDIO': AttachmentType.audio, 'FILE': AttachmentType.file, 'SHARE': AttachmentType.share, }; class SharedMediaItem { final String messageId; final int chatId; final int senderId; final int time; final MessageAttachment attachment; const SharedMediaItem({ required this.messageId, required this.chatId, required this.senderId, required this.time, required this.attachment, }); String get dedupKey { final a = attachment; final String tail; if (a is PhotoAttachment) { tail = 'p${a.photoId ?? a.baseUrl}'; } else if (a is VideoAttachment) { tail = 'v${a.videoId ?? a.baseUrl}'; } else if (a is FileAttachment) { tail = 'f${a.fileId ?? a.name}'; } else if (a is AudioAttachment) { tail = 'a${a.audioId ?? a.fileUrl}'; } else if (a is ShareAttachment) { tail = 's${a.shareId ?? a.url}'; } else { tail = a.hashCode.toString(); } return '$messageId:$tail'; } } class SharedMediaPage { final List items; final int total; const SharedMediaPage({required this.items, required this.total}); static const empty = SharedMediaPage(items: [], total: 0); } class CommonChatEntry { final int id; final String type; final String title; final String? iconUrl; final int participantsCount; final List participantIds; const CommonChatEntry({ required this.id, required this.type, required this.title, required this.iconUrl, required this.participantsCount, required this.participantIds, }); factory CommonChatEntry.fromMap(Map map) { final participants = map['participants']; final ids = []; if (participants is Map) { for (final key in participants.keys) { final id = key is int ? key : int.tryParse(key.toString()); if (id != null) ids.add(id); } } return CommonChatEntry( id: (map['id'] as num?)?.toInt() ?? 0, type: map['type']?.toString() ?? 'CHAT', title: map['title']?.toString() ?? '', iconUrl: map['baseIconUrl'] as String?, participantsCount: (map['participantsCount'] as num?)?.toInt() ?? ids.length, participantIds: ids, ); } } class SharedContentModule { final Api _api; SharedContentModule(this._api); Future fetchMedia({ required int chatId, required String anchorMessageId, required List attachTypes, int forward = 0, int backward = 60, }) async { try { final response = await _api.sendRequest(Opcode.chatMedia, { 'chatId': chatId, 'messageId': int.tryParse(anchorMessageId) ?? 0, 'attachTypes': attachTypes, 'forward': forward, 'backward': backward, }); if (!response.isOk) return SharedMediaPage.empty; final data = response.payload; if (data is! Map) return SharedMediaPage.empty; final messages = data['messages']; if (messages is! List) return SharedMediaPage.empty; final wanted = attachTypes .map((t) => _attachTypeByName[t]) .whereType() .toSet(); final out = []; for (final m in messages) { if (m is! Map) continue; final map = Map.from(m); final id = map['id']?.toString(); if (id == null) continue; final sender = (map['sender'] as num?)?.toInt() ?? 0; final time = (map['time'] as num?)?.toInt() ?? 0; final attaches = map['attaches']; if (attaches is! List) continue; for (final a in attaches) { if (a is! Map) continue; final att = MessageAttachment.fromMap(Map.from(a)); if (!wanted.contains(att.type)) continue; out.add( SharedMediaItem( messageId: id, chatId: chatId, senderId: sender, time: time, attachment: att, ), ); } } out.sort((a, b) => b.time.compareTo(a.time)); final total = (data['total'] as num?)?.toInt() ?? out.length; return SharedMediaPage(items: out, total: total); } catch (e) { logger.w('SharedContent.fetchMedia failed: $e'); return SharedMediaPage.empty; } } Future> fetchCommonChats(int userId) async { try { final response = await _api.sendRequest( Opcode.chatSearchCommonParticipants, { 'userIds': [userId], }, ); if (!response.isOk) return const []; final data = response.payload; if (data is! Map) return const []; final chats = data['commonChats']; if (chats is! List) return const []; final out = []; for (final c in chats) { if (c is Map) { out.add(CommonChatEntry.fromMap(Map.from(c))); } } return out; } catch (e) { logger.w('SharedContent.fetchCommonChats failed: $e'); return const []; } } }