mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-12 00:40:28 +00:00
feat: Enhance message handling for drawings
- Added properties to the Message model to track drawing status and associated drawing ID. - Updated AppProvider to mark messages as drawings and link them to their respective drawing IDs. - Enhanced DrawingProvider to manage received drawings and their visibility. - Implemented navigation to drawings in MapProvider, including dynamic zoom levels based on drawing size. - Updated MessagesProvider to parse drawing messages and manage linked drawings. - Enhanced MessagesTab to support drawing message interactions, including navigation and coordinate copying. - Created DrawingMinimapPreview widget for visual representation of drawings in message bubbles. - Improved DrawingToolbar to handle sharing of drawings, ensuring only unshared drawings are sent. - Added utility functions in DrawingMessageParser for extracting drawing metadata.
This commit is contained in:
135
lib/widgets/drawing_minimap_preview.dart
Normal file
135
lib/widgets/drawing_minimap_preview.dart
Normal file
@@ -0,0 +1,135 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import '../models/map_drawing.dart';
|
||||
|
||||
/// Minimap preview widget for map drawings
|
||||
/// Renders a small 80x80px preview of a drawing on a simple gray background
|
||||
class DrawingMinimapPreview extends StatelessWidget {
|
||||
final MapDrawing drawing;
|
||||
|
||||
const DrawingMinimapPreview({
|
||||
super.key,
|
||||
required this.drawing,
|
||||
});
|
||||
|
||||
/// Calculate bounds for the drawing to fit in the preview
|
||||
LatLngBounds _calculateBounds() {
|
||||
if (drawing is LineDrawing) {
|
||||
final lineDrawing = drawing as LineDrawing;
|
||||
if (lineDrawing.points.isEmpty) {
|
||||
// Fallback to default bounds if no points
|
||||
return LatLngBounds(
|
||||
const LatLng(0, 0),
|
||||
const LatLng(0.01, 0.01),
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate bounds from points
|
||||
double minLat = lineDrawing.points.first.latitude;
|
||||
double maxLat = lineDrawing.points.first.latitude;
|
||||
double minLon = lineDrawing.points.first.longitude;
|
||||
double maxLon = lineDrawing.points.first.longitude;
|
||||
|
||||
for (final point in lineDrawing.points) {
|
||||
if (point.latitude < minLat) minLat = point.latitude;
|
||||
if (point.latitude > maxLat) maxLat = point.latitude;
|
||||
if (point.longitude < minLon) minLon = point.longitude;
|
||||
if (point.longitude > maxLon) maxLon = point.longitude;
|
||||
}
|
||||
|
||||
// Add padding (10% on each side)
|
||||
final latPadding = (maxLat - minLat) * 0.1;
|
||||
final lonPadding = (maxLon - minLon) * 0.1;
|
||||
|
||||
return LatLngBounds(
|
||||
LatLng(minLat - latPadding, minLon - lonPadding),
|
||||
LatLng(maxLat + latPadding, maxLon + lonPadding),
|
||||
);
|
||||
} else if (drawing is RectangleDrawing) {
|
||||
final rectDrawing = drawing as RectangleDrawing;
|
||||
|
||||
// Add padding (10% on each side)
|
||||
final latDiff = (rectDrawing.bottomRight.latitude - rectDrawing.topLeft.latitude).abs();
|
||||
final lonDiff = (rectDrawing.bottomRight.longitude - rectDrawing.topLeft.longitude).abs();
|
||||
final latPadding = latDiff * 0.1;
|
||||
final lonPadding = lonDiff * 0.1;
|
||||
|
||||
return LatLngBounds(
|
||||
LatLng(
|
||||
rectDrawing.topLeft.latitude - latPadding,
|
||||
rectDrawing.topLeft.longitude - lonPadding,
|
||||
),
|
||||
LatLng(
|
||||
rectDrawing.bottomRight.latitude + latPadding,
|
||||
rectDrawing.bottomRight.longitude + lonPadding,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Fallback to default bounds
|
||||
return LatLngBounds(
|
||||
const LatLng(0, 0),
|
||||
const LatLng(0.01, 0.01),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bounds = _calculateBounds();
|
||||
|
||||
return Container(
|
||||
width: 80,
|
||||
height: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: Colors.grey.shade400,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(7),
|
||||
child: FlutterMap(
|
||||
options: MapOptions(
|
||||
initialCameraFit: CameraFit.bounds(
|
||||
bounds: bounds,
|
||||
padding: const EdgeInsets.all(8),
|
||||
),
|
||||
interactionOptions: const InteractionOptions(
|
||||
flags: InteractiveFlag.none, // Disable all interactions
|
||||
),
|
||||
),
|
||||
children: [
|
||||
// Simple gray background (no tiles for performance)
|
||||
Container(color: Colors.grey.shade300),
|
||||
|
||||
// Render the drawing
|
||||
if (drawing is LineDrawing)
|
||||
PolylineLayer(
|
||||
polylines: [
|
||||
Polyline(
|
||||
points: (drawing as LineDrawing).points,
|
||||
strokeWidth: 3.0,
|
||||
color: drawing.color,
|
||||
),
|
||||
],
|
||||
)
|
||||
else if (drawing is RectangleDrawing)
|
||||
PolygonLayer(
|
||||
polygons: [
|
||||
Polygon(
|
||||
points: (drawing as RectangleDrawing).corners,
|
||||
color: drawing.color.withValues(alpha: 0.3),
|
||||
borderColor: drawing.color,
|
||||
borderStrokeWidth: 3.0,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user