mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
154 lines
4.1 KiB
Dart
154 lines
4.1 KiB
Dart
import 'package:latlong2/latlong.dart';
|
|
import '../models/sar_marker.dart';
|
|
import '../models/message.dart';
|
|
|
|
/// Parser for SAR (Search & Rescue) special messages
|
|
/// Format: S:<emoji>:<latitude>,<longitude>
|
|
/// Examples:
|
|
/// S:🧑:37.7749,-122.4194
|
|
/// S:🔥:40.7128,-74.0060
|
|
/// S:🏕️:34.0522,-118.2437
|
|
class SarMessageParser {
|
|
static final RegExp _sarPattern = RegExp(
|
|
r'^S:(.):(-?\d+\.?\d*),(-?\d+\.?\d*)$',
|
|
multiLine: false,
|
|
);
|
|
|
|
/// Check if a message is a SAR marker message
|
|
static bool isSarMessage(String text) {
|
|
return text.trim().startsWith('S:') && _sarPattern.hasMatch(text.trim());
|
|
}
|
|
|
|
/// Parse a SAR message and extract marker information
|
|
/// Returns null if the message is not a valid SAR message
|
|
static SarMarkerInfo? parse(String text) {
|
|
final trimmed = text.trim();
|
|
if (!trimmed.startsWith('S:')) return null;
|
|
|
|
final match = _sarPattern.firstMatch(trimmed);
|
|
if (match == null) return null;
|
|
|
|
try {
|
|
final emoji = match.group(1)!;
|
|
final latitude = double.parse(match.group(2)!);
|
|
final longitude = double.parse(match.group(3)!);
|
|
|
|
// Validate coordinates
|
|
if (latitude < -90 || latitude > 90) return null;
|
|
if (longitude < -180 || longitude > 180) return null;
|
|
|
|
final markerType = SarMarkerType.fromEmoji(emoji);
|
|
final location = LatLng(latitude, longitude);
|
|
|
|
return SarMarkerInfo(
|
|
type: markerType,
|
|
location: location,
|
|
emoji: emoji,
|
|
);
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// Enhance a Message with SAR marker information
|
|
static Message enhanceMessage(Message message) {
|
|
final sarInfo = parse(message.text);
|
|
if (sarInfo == null) return message;
|
|
|
|
return message.copyWith(
|
|
isSarMarker: true,
|
|
sarMarkerType: sarInfo.type,
|
|
sarGpsCoordinates: sarInfo.location,
|
|
);
|
|
}
|
|
|
|
/// Create a SAR marker message text
|
|
static String createSarMessage({
|
|
required SarMarkerType type,
|
|
required LatLng location,
|
|
String? notes,
|
|
}) {
|
|
final text = 'S:${type.emoji}:${location.latitude},${location.longitude}';
|
|
if (notes != null && notes.isNotEmpty) {
|
|
return '$text\n$notes';
|
|
}
|
|
return text;
|
|
}
|
|
|
|
/// Extract additional notes from SAR message (text after the marker)
|
|
static String? extractNotes(String text) {
|
|
final trimmed = text.trim();
|
|
final lines = trimmed.split('\n');
|
|
if (lines.length <= 1) return null;
|
|
|
|
// Everything after the first line is considered notes
|
|
return lines.sublist(1).join('\n').trim();
|
|
}
|
|
|
|
/// Validate SAR message format
|
|
static bool isValidFormat(String text) {
|
|
return isSarMessage(text) && parse(text) != null;
|
|
}
|
|
|
|
/// Get a user-friendly error message for invalid SAR format
|
|
static String? getFormatError(String text) {
|
|
if (!text.trim().startsWith('S:')) {
|
|
return 'SAR message must start with "S:"';
|
|
}
|
|
|
|
final parts = text.trim().split(':');
|
|
if (parts.length < 3) {
|
|
return 'Invalid format. Use: S:<emoji>:<latitude>,<longitude>';
|
|
}
|
|
|
|
final emoji = parts[1];
|
|
if (emoji.isEmpty) {
|
|
return 'Missing emoji marker (🧑, 🔥, or 🏕️)';
|
|
}
|
|
|
|
final coords = parts[2];
|
|
if (!coords.contains(',')) {
|
|
return 'Coordinates must be separated by comma';
|
|
}
|
|
|
|
final coordParts = coords.split(',');
|
|
if (coordParts.length != 2) {
|
|
return 'Invalid coordinates format';
|
|
}
|
|
|
|
try {
|
|
final lat = double.parse(coordParts[0]);
|
|
final lon = double.parse(coordParts[1]);
|
|
|
|
if (lat < -90 || lat > 90) {
|
|
return 'Latitude must be between -90 and 90';
|
|
}
|
|
if (lon < -180 || lon > 180) {
|
|
return 'Longitude must be between -180 and 180';
|
|
}
|
|
} catch (e) {
|
|
return 'Invalid coordinate values';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// Parsed SAR marker information
|
|
class SarMarkerInfo {
|
|
final SarMarkerType type;
|
|
final LatLng location;
|
|
final String emoji;
|
|
|
|
SarMarkerInfo({
|
|
required this.type,
|
|
required this.location,
|
|
required this.emoji,
|
|
});
|
|
|
|
@override
|
|
String toString() {
|
|
return 'SarMarkerInfo(type: ${type.displayName}, location: $location)';
|
|
}
|
|
}
|