class WhatsAppSharePayload { const WhatsAppSharePayload({ required this.messageText, this.sourceDisplayName, this.sourceUserId, this.sourceThreadId, }); final String messageText; final String? sourceDisplayName; final String? sourceUserId; final String? sourceThreadId; } /// Parses raw shared text from WhatsApp into normalized fields. class WhatsAppShareParser { const WhatsAppShareParser._(); static final RegExp _datePrefixPattern = RegExp( r'^\[[^\]]+\]\s*([^:\n]{2,80}):\s*(.+)$', dotAll: true, ); static final RegExp _namePrefixPattern = RegExp( r'^([^:\n]{2,80}):\s*(.+)$', dotAll: true, ); static WhatsAppSharePayload parse(String raw) { final String input = raw.trim(); if (input.isEmpty) { return const WhatsAppSharePayload(messageText: ''); } String? senderName; String messageText = input; final RegExpMatch? dateMatch = _datePrefixPattern.firstMatch(input); if (dateMatch != null) { senderName = _cleanSender(dateMatch.group(1)); messageText = dateMatch.group(2)?.trim() ?? input; } else { final RegExpMatch? nameMatch = _namePrefixPattern.firstMatch(input); if (nameMatch != null) { senderName = _cleanSender(nameMatch.group(1)); messageText = nameMatch.group(2)?.trim() ?? input; } } final String? sourceUserId = _normalizedKey(senderName); return WhatsAppSharePayload( messageText: messageText, sourceDisplayName: senderName, sourceUserId: sourceUserId, sourceThreadId: null, ); } static bool looksLikeWhatsAppMessage(String raw) { final String input = raw.trim(); if (input.isEmpty) { return false; } return _datePrefixPattern.hasMatch(input) || _namePrefixPattern.hasMatch(input); } static String? _cleanSender(String? input) { if (input == null) { return null; } final String cleaned = input.trim(); return cleaned.isEmpty ? null : cleaned; } static String? _normalizedKey(String? input) { if (input == null) { return null; } final String key = input .toLowerCase() .replaceAll(RegExp(r'[^a-z0-9]+'), ' ') .trim() .replaceAll(RegExp(r'\s+'), ' '); return key.isEmpty ? null : 'wa:$key'; } }