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

241 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,
routeOrigin,
routeDestination,
}
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.routeOrigin:
return 'تحديد نقطة الانطلاق (البداية) 🟢';
case MapPickerTarget.routeDestination:
return 'تحديد نقطة الوصول والهدف (الوجهة) 🏁';
}
}
Color get themeColor {
switch (target) {
case MapPickerTarget.losObserver:
return const Color(0xFF38BDF8);
case MapPickerTarget.losTarget:
return const Color(0xFFEF4444);
case MapPickerTarget.routeOrigin:
return const Color(0xFF22C55E);
case MapPickerTarget.routeDestination:
return const Color(0xFFF59E0B);
}
}
IconData get pinIcon {
switch (target) {
case MapPickerTarget.losObserver:
return Icons.person_pin_circle;
case MapPickerTarget.losTarget:
return Icons.gps_fixed;
case MapPickerTarget.routeOrigin:
return Icons.my_location;
case MapPickerTarget.routeDestination:
return Icons.flag;
}
}
@override
Widget build(BuildContext context) {
final milCoords = MilitaryGridUtils.fromLatLng(centerPosition);
return Stack(
children: [
// ── 1. Center Floating Marker & Tooltip (Siro Rider Style) ──
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Dynamic Floating Coordinates Bubble
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: const Color(0xF20F172A),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: themeColor, width: 1.5),
boxShadow: const [BoxShadow(color: Colors.black54, blurRadius: 15)],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'شرقيات: ${milCoords.eastingStr} م • شماليات: ${milCoords.northingStr} م',
style: const TextStyle(color: Colors.white, fontSize: 11, fontWeight: FontWeight.bold),
),
Text(
'${centerPosition.latitude.toStringAsFixed(5)}, ${centerPosition.longitude.toStringAsFixed(5)}',
style: const TextStyle(color: Color(0xFF94A3B8), fontSize: 9.5),
),
],
),
),
const SizedBox(height: 6),
// Animated Floating Pin Icon
Icon(pinIcon, size: 44, color: themeColor),
// Ground Shadow Reticle
Container(
width: 10,
height: 5,
decoration: BoxDecoration(
color: Colors.black.withAlpha(128),
borderRadius: BorderRadius.circular(10),
),
),
const SizedBox(height: 48), // Offset to position pin tip at exact screen center
],
),
),
// ── 2. Top Instructions Bar ─────────────────────────────────
Positioned(
top: 50,
left: 20,
right: 20,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: const Color(0xF20F172A),
borderRadius: BorderRadius.circular(14),
border: Border.all(color: Colors.white12),
boxShadow: const [BoxShadow(color: Colors.black54, blurRadius: 12)],
),
child: Row(
children: [
Icon(Icons.touch_app, color: themeColor, size: 20),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(color: Colors.white, fontSize: 12.5, fontWeight: FontWeight.bold),
),
const Text(
'حرك الخريطة وضع رأس المؤشر على النقطة المطلوبة بدقة',
style: TextStyle(color: Color(0xFF94A3B8), fontSize: 10),
),
],
),
),
IconButton(
icon: const Icon(Icons.close, color: Colors.white70, size: 18),
onPressed: onCancel,
),
],
),
),
),
// ── 3. Bottom Confirmation Action Bar ────────────────────────
Positioned(
bottom: 24,
left: 16,
right: 16,
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xF50F172A),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: themeColor, width: 1.5),
boxShadow: const [BoxShadow(color: Colors.black87, blurRadius: 25)],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('الموقع المحدد حالياً:', style: TextStyle(color: Color(0xFF94A3B8), fontSize: 11)),
Text(
'المربع: ${milCoords.shortGrid} (${milCoords.zone}N)',
style: TextStyle(color: themeColor, fontSize: 11, fontWeight: FontWeight.bold),
),
],
),
const SizedBox(height: 6),
Container(
width: double.infinity,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: const Color(0xFF1E293B),
borderRadius: BorderRadius.circular(10),
),
child: Text(
milCoords.arabicFullFormat,
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold),
),
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
flex: 3,
child: ElevatedButton.icon(
onPressed: onConfirm,
icon: const Icon(Icons.check, size: 18),
label: const Text('تثبيت وتأكيد هذا الموقع', style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold)),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF0071E3),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 13),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
),
),
const SizedBox(width: 8),
Expanded(
flex: 1,
child: OutlinedButton(
onPressed: onCancel,
style: OutlinedButton.styleFrom(
foregroundColor: const Color(0xFF94A3B8),
side: const BorderSide(color: Colors.white24),
padding: const EdgeInsets.symmetric(vertical: 13),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
child: const Text('إلغاء', style: TextStyle(fontSize: 12)),
),
),
],
),
],
),
),
),
],
);
}
}