Files
maps-saas/packages/tactical_app/lib/widgets/interactive_map_picker_hud.dart
T

258 lines
9.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import '../services/military_grid_utils.dart';
enum MapPickerTarget {
losObserver,
losTarget,
viewshedCenter,
routeOrigin,
routeDestination,
artilleryGun,
artilleryTarget,
hlzCenter,
minefieldStart,
minefieldEnd,
isochroneCenter,
resectionLandmark,
}
class InteractiveMapPickerHud extends StatelessWidget {
final MapPickerTarget target;
final LatLng centerPosition;
final VoidCallback onConfirm;
final VoidCallback onCancel;
const InteractiveMapPickerHud({
super.key,
required this.target,
required this.centerPosition,
required this.onConfirm,
required this.onCancel,
});
String get title {
switch (target) {
case MapPickerTarget.losObserver:
return 'تحديد موقع الراصد الميداني (Observer) 🔴';
case MapPickerTarget.losTarget:
return 'تحديد موقع الهدف التكتيكي (Target) 🎯';
case MapPickerTarget.viewshedCenter:
return 'تحديد مركز الرصد الدائري 360° (Radar) 📡';
case MapPickerTarget.routeOrigin:
return 'تحديد نقطة الانطلاق (البداية) 🟢';
case MapPickerTarget.routeDestination:
return 'تحديد نقطة الوصول والهدف (الوجهة) 🏁';
case MapPickerTarget.artilleryGun:
return 'تحديد مربض المدفعية (Battery Position) 🎯';
case MapPickerTarget.artilleryTarget:
return 'تحديد الهدف المعادي للمدفعية (Target) 💥';
case MapPickerTarget.hlzCenter:
return 'تحديد موقع مهبط المروحيات (HLZ) 🚁';
case MapPickerTarget.minefieldStart:
return 'تحديد بداية حقل الألغام (Point A) ⚠️';
case MapPickerTarget.minefieldEnd:
return 'تحديد نهاية حقل الألغام (Point B) ⚠️';
case MapPickerTarget.isochroneCenter:
return 'تحديد قاعدة قوة التدخل السريع (QRF) ⚡';
case MapPickerTarget.resectionLandmark:
return 'تحديد المعلم الجغرافي للتقاطع البصري (Landmark) 📍';
}
}
Color get themeColor {
switch (target) {
case MapPickerTarget.losObserver:
case MapPickerTarget.viewshedCenter:
return const Color(0xFF38BDF8);
case MapPickerTarget.losTarget:
case MapPickerTarget.artilleryTarget:
return const Color(0xFFEF4444);
case MapPickerTarget.routeOrigin:
case MapPickerTarget.hlzCenter:
return const Color(0xFF22C55E);
case MapPickerTarget.routeDestination:
case MapPickerTarget.minefieldStart:
case MapPickerTarget.minefieldEnd:
return const Color(0xFFF59E0B);
case MapPickerTarget.artilleryGun:
return const Color(0xFF0071E3);
case MapPickerTarget.isochroneCenter:
case MapPickerTarget.resectionLandmark:
return const Color(0xFFA855F7);
}
}
IconData get pinIcon {
switch (target) {
case MapPickerTarget.losObserver:
return Icons.person_pin_circle;
case MapPickerTarget.losTarget:
case MapPickerTarget.artilleryTarget:
return Icons.gps_fixed;
case MapPickerTarget.viewshedCenter:
return Icons.radar;
case MapPickerTarget.routeOrigin:
return Icons.my_location;
case MapPickerTarget.routeDestination:
return Icons.flag;
case MapPickerTarget.artilleryGun:
return Icons.adjust;
case MapPickerTarget.hlzCenter:
return Icons.flight_land;
case MapPickerTarget.minefieldStart:
case MapPickerTarget.minefieldEnd:
return Icons.warning_amber;
case MapPickerTarget.isochroneCenter:
return Icons.flash_on;
case MapPickerTarget.resectionLandmark:
return Icons.location_searching;
}
}
@override
Widget build(BuildContext context) {
final mgrs = MilitaryGridUtils.latLngToMgrs(centerPosition.latitude, centerPosition.longitude);
return Stack(
children: [
// ── 1. Center Crosshair / Pointer ─────────────────────────
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: const Color(0xFF090E17),
shape: BoxShape.circle,
border: Border.all(color: themeColor, width: 2),
boxShadow: [
BoxShadow(
color: themeColor.withAlpha(120),
blurRadius: 16,
spreadRadius: 2,
),
],
),
child: Icon(pinIcon, color: themeColor, size: 28),
),
const SizedBox(height: 2),
// Pointer Dot
Container(
width: 6,
height: 6,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
border: Border.all(color: themeColor, width: 1.5),
),
),
],
),
),
// ── 2. Top Instructions & MGRS Banner ───────────────────────
Positioned(
top: 60,
left: 16,
right: 16,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: const Color(0xFF090E17).withAlpha(240),
borderRadius: BorderRadius.circular(14),
border: Border.all(color: themeColor.withAlpha(120), width: 1.2),
boxShadow: const [
BoxShadow(color: Colors.black87, blurRadius: 16, spreadRadius: 2),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
title,
style: const TextStyle(
color: Colors.white,
fontSize: 13,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 4),
Text(
'حرّك الخريطة وضع النقطة في مركز المؤشر ثم اضغط "تثبيت"',
style: TextStyle(
color: Colors.white.withAlpha(180),
fontSize: 10.5,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 6),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
decoration: BoxDecoration(
color: Colors.white10,
borderRadius: BorderRadius.circular(6),
),
child: Text(
'MGRS: $mgrs',
style: TextStyle(
color: themeColor,
fontSize: 11,
fontFamily: 'monospace',
fontWeight: FontWeight.bold,
),
),
),
],
),
),
),
// ── 3. Bottom Confirm / Cancel Actions ─────────────────────
Positioned(
bottom: 30,
left: 20,
right: 20,
child: Row(
children: [
Expanded(
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: themeColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 8,
),
icon: const Icon(Icons.check, size: 20),
label: const Text(
'تثبيت النقطة في الميدان',
style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold),
),
onPressed: onConfirm,
),
),
const SizedBox(width: 12),
Container(
decoration: BoxDecoration(
color: const Color(0xFF0F172A),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white24),
),
child: IconButton(
icon: const Icon(Icons.close, color: Colors.white70),
onPressed: onCancel,
),
),
],
),
),
],
);
}
}