152 lines
4.8 KiB
Dart
152 lines
4.8 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import 'road_alert_models.dart';
|
|
|
|
@immutable
|
|
class SwarmReport {
|
|
final String id;
|
|
final RoadAlertCategory category;
|
|
final double latitude;
|
|
final double longitude;
|
|
final double? heading;
|
|
final String? roadName;
|
|
final String description;
|
|
final String reporterUid;
|
|
final DateTime reportedAt;
|
|
final DateTime expiresAt;
|
|
final int confirmations;
|
|
final int dismissals;
|
|
final String? groupRideId;
|
|
|
|
const SwarmReport({
|
|
required this.id,
|
|
required this.category,
|
|
required this.latitude,
|
|
required this.longitude,
|
|
this.heading,
|
|
this.roadName,
|
|
required this.description,
|
|
required this.reporterUid,
|
|
required this.reportedAt,
|
|
required this.expiresAt,
|
|
this.confirmations = 1,
|
|
this.dismissals = 0,
|
|
this.groupRideId,
|
|
});
|
|
|
|
double get confidence {
|
|
final total = confirmations + dismissals;
|
|
if (total == 0) return 0.8;
|
|
return (confirmations / total).clamp(0.1, 1.0);
|
|
}
|
|
|
|
bool get isExpired => DateTime.now().isAfter(expiresAt);
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'id': id,
|
|
'category': category.name,
|
|
'latitude': latitude,
|
|
'longitude': longitude,
|
|
if (heading != null) 'heading': heading,
|
|
if (roadName != null) 'roadName': roadName,
|
|
'description': description,
|
|
'reporterUid': reporterUid,
|
|
'reportedAt': reportedAt.millisecondsSinceEpoch,
|
|
'expiresAt': expiresAt.millisecondsSinceEpoch,
|
|
'confirmations': confirmations,
|
|
'dismissals': dismissals,
|
|
if (groupRideId != null) 'groupRideId': groupRideId,
|
|
};
|
|
|
|
factory SwarmReport.fromJson(Map<String, dynamic> json) {
|
|
final catName = json['category']?.toString() ?? 'other';
|
|
final category = RoadAlertCategory.values.firstWhere(
|
|
(c) => c.name == catName,
|
|
orElse: () => RoadAlertCategory.other,
|
|
);
|
|
|
|
final rawReportedAt = json['reportedAt'];
|
|
final reportedAt = rawReportedAt is num
|
|
? DateTime.fromMillisecondsSinceEpoch(rawReportedAt.toInt())
|
|
: (DateTime.tryParse(rawReportedAt?.toString() ?? '') ?? DateTime.now());
|
|
|
|
final rawExpiresAt = json['expiresAt'];
|
|
final expiresAt = rawExpiresAt is num
|
|
? DateTime.fromMillisecondsSinceEpoch(rawExpiresAt.toInt())
|
|
: (DateTime.tryParse(rawExpiresAt?.toString() ?? '') ??
|
|
reportedAt.add(const Duration(hours: 1)));
|
|
|
|
return SwarmReport(
|
|
id: json['id']?.toString() ?? '',
|
|
category: category,
|
|
latitude: (json['latitude'] as num).toDouble(),
|
|
longitude: (json['longitude'] as num).toDouble(),
|
|
heading: json['heading'] != null ? (json['heading'] as num).toDouble() : null,
|
|
roadName: json['roadName']?.toString(),
|
|
description: json['description']?.toString() ?? 'Swarm Report',
|
|
reporterUid: json['reporterUid']?.toString() ?? 'anonymous',
|
|
reportedAt: reportedAt,
|
|
expiresAt: expiresAt,
|
|
confirmations: (json['confirmations'] as num?)?.toInt() ?? 1,
|
|
dismissals: (json['dismissals'] as num?)?.toInt() ?? 0,
|
|
groupRideId: json['groupRideId']?.toString(),
|
|
);
|
|
}
|
|
|
|
RoadAlert toRoadAlert({double? distanceFromUser}) {
|
|
final isPoliceOrAccident =
|
|
category == RoadAlertCategory.police || category == RoadAlertCategory.accident;
|
|
final sourceName = groupRideId != null ? 'Pack Rider Report' : 'MotorSignal Swarm';
|
|
|
|
return RoadAlert(
|
|
id: id,
|
|
providerId: 'swarm_alerts',
|
|
category: category,
|
|
latitude: latitude,
|
|
longitude: longitude,
|
|
heading: heading,
|
|
roadName: roadName,
|
|
description: description,
|
|
reportedAt: reportedAt,
|
|
expiresAt: expiresAt,
|
|
lastUpdated: DateTime.now(),
|
|
confidence: confidence,
|
|
severity: isPoliceOrAccident ? RoadAlertSeverity.high : RoadAlertSeverity.medium,
|
|
source: sourceName,
|
|
sourceType: RoadAlertSourceType.userReported,
|
|
distanceFromUser: distanceFromUser,
|
|
);
|
|
}
|
|
|
|
SwarmReport copyWith({
|
|
String? id,
|
|
RoadAlertCategory? category,
|
|
double? latitude,
|
|
double? longitude,
|
|
double? heading,
|
|
String? roadName,
|
|
String? description,
|
|
String? reporterUid,
|
|
DateTime? reportedAt,
|
|
DateTime? expiresAt,
|
|
int? confirmations,
|
|
int? dismissals,
|
|
String? groupRideId,
|
|
}) {
|
|
return SwarmReport(
|
|
id: id ?? this.id,
|
|
category: category ?? this.category,
|
|
latitude: latitude ?? this.latitude,
|
|
longitude: longitude ?? this.longitude,
|
|
heading: heading ?? this.heading,
|
|
roadName: roadName ?? this.roadName,
|
|
description: description ?? this.description,
|
|
reporterUid: reporterUid ?? this.reporterUid,
|
|
reportedAt: reportedAt ?? this.reportedAt,
|
|
expiresAt: expiresAt ?? this.expiresAt,
|
|
confirmations: confirmations ?? this.confirmations,
|
|
dismissals: dismissals ?? this.dismissals,
|
|
groupRideId: groupRideId ?? this.groupRideId,
|
|
);
|
|
}
|
|
}
|