chore: add build artifacts, map assets, and routing data

This commit is contained in:
Hamza-Ayed
2026-09-19 12:34:24 +03:00
parent aa2b9f131f
commit 43ad2e0ad4
327 changed files with 52421 additions and 1810 deletions
+239
View File
@@ -0,0 +1,239 @@
import re
path = "packages/tactical_app/lib/screens/tactical_map_screen.dart"
with open(path, "r") as f:
content = f.read()
# 1. Add imports
imports = """
import '../models/tactical_sheet_type.dart';
import '../widgets/persistent_tactical_sheet_wrapper.dart';
"""
content = content.replace("import '../widgets/tactical_viewshed_sheet.dart';", "import '../widgets/tactical_viewshed_sheet.dart';\n" + imports)
# 2. Add Persistent Sheet in Stack
# We will insert it right before the active navigation HUDs (around line 287)
# or just after the InteractiveMapPickerHud (around line 242).
# Let's find " // ── 5. Active Turn-by-Turn Navigation HUD ──────────────"
stack_insert = """
// ── 4c. Persistent Tactical Sheet ──────────────────────────
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Obx(() {
final activeSheet = controller.activeSheet.value;
if (activeSheet == null || navState.isNavigating) {
return const SizedBox.shrink();
}
Widget sheetContent = const SizedBox.shrink();
switch (activeSheet.type) {
case TacticalSheetType.route:
sheetContent = TacticalRoutePlannerSheet(
initialOrigin: controller.pickedRouteOrigin.value,
initialDestination: controller.pickedRouteDestination.value,
currentGps: controller.currentGpsPosition.value ?? const LatLng(31.9539, 35.9106),
resectionFix: controller.resection.resectionResult.value != null
? LatLng(controller.resection.resectionResult.value!.lat, controller.resection.resectionResult.value!.lng)
: null,
onRouteConfirmed: (origin, destination, profile, autoStartNav) async {
final plan = await controller.navigation.calculateRoute(
origin: origin,
destination: destination,
profile: profile,
autoStart: autoStartNav,
mapController: controller.mapController,
);
if (plan != null && plan.polylinePoints.isNotEmpty) {
controller.fitBounds(plan.polylinePoints);
}
},
onPickOriginOnMap: () {
controller.isSheetMinimized.value = true;
controller.setPickerTarget(MapPickerTarget.routeOrigin);
},
onPickDestinationOnMap: () {
controller.isSheetMinimized.value = true;
controller.setPickerTarget(MapPickerTarget.routeDestination);
},
onClose: controller.closeSheet,
);
break;
case TacticalSheetType.los:
sheetContent = TacticalLosSheet(
observer: controller.los.observerPosition.value ?? const LatLng(31.9539, 35.9106),
target: controller.los.targetPosition.value ?? const LatLng(31.9800, 35.9500),
currentGps: controller.currentGpsPosition.value,
angleUnit: controller.angleUnit.value,
onUpdateLocations: (newObs, newTgt) {
controller.los.setObserver(newObs);
controller.los.setTarget(newTgt);
controller.fitBounds([newObs, newTgt]);
},
onVisibilityChanged: (_) {},
onReportGenerated: (_) {},
onPickObserverOnMap: () {
controller.isSheetMinimized.value = true;
controller.setPickerTarget(MapPickerTarget.losObserver);
},
onPickTargetOnMap: () {
controller.isSheetMinimized.value = true;
controller.setPickerTarget(MapPickerTarget.losTarget);
},
onClose: () {
controller.closeSheet();
controller.switchMode('nav');
},
);
break;
case TacticalSheetType.viewshed:
sheetContent = TacticalViewshedSheet(
observer: controller.viewshed.observerPosition.value ?? controller.currentGpsPosition.value ?? const LatLng(31.9539, 35.9106),
currentGps: controller.currentGpsPosition.value,
onUpdateObserver: controller.viewshed.setObserver,
onReportUpdated: (_) {},
onPickObserverOnMap: () {
controller.isSheetMinimized.value = true;
controller.setPickerTarget(MapPickerTarget.viewshedCenter);
},
onClose: controller.closeSheet,
);
break;
case TacticalSheetType.artillery:
sheetContent = TacticalArtillerySheet(
gunPosition: controller.artillery.gunPosition.value ?? controller.currentGpsPosition.value ?? const LatLng(31.9539, 35.9106),
targetPosition: controller.artillery.targetPosition.value,
angleUnit: controller.angleUnit.value,
onPickGun: () {
controller.isSheetMinimized.value = true;
controller.setPickerTarget(MapPickerTarget.artilleryGun);
},
onPickTarget: () {
controller.isSheetMinimized.value = true;
controller.setPickerTarget(MapPickerTarget.artilleryTarget);
},
onSwap: controller.artillery.swapPositions,
onSolutionCalculated: (sol) {
controller.fitBounds([sol.gunPosition, sol.targetPosition]);
},
onClose: controller.closeSheet,
);
break;
case TacticalSheetType.hlz:
sheetContent = TacticalHlzSheet(
selectedPosition: controller.hlz.selectedPosition.value ?? controller.currentGpsPosition.value ?? const LatLng(31.9539, 35.9106),
onPickLocation: () {
controller.isSheetMinimized.value = true;
controller.setPickerTarget(MapPickerTarget.hlzCenter);
},
onAssessmentCompleted: (_) {},
onClose: controller.closeSheet,
);
break;
case TacticalSheetType.minefield:
sheetContent = TacticalMinefieldSheet(
startPoint: controller.minefield.startPoint.value ?? controller.currentGpsPosition.value ?? const LatLng(31.9539, 35.9106),
endPoint: controller.minefield.endPoint.value,
onPickStart: () {
controller.isSheetMinimized.value = true;
controller.setPickerTarget(MapPickerTarget.minefieldStart);
},
onPickEnd: () {
controller.isSheetMinimized.value = true;
controller.setPickerTarget(MapPickerTarget.minefieldEnd);
},
onSwap: controller.minefield.swapPoints,
onZoneCalculated: (res) {
controller.fitBounds([res.startPoint, res.endPoint]);
},
onClose: controller.closeSheet,
);
break;
case TacticalSheetType.isochrone:
sheetContent = TacticalIsochroneSheet(
center: controller.isochrone.center.value ?? controller.currentGpsPosition.value ?? const LatLng(31.9539, 35.9106),
onPickCenter: () {
controller.isSheetMinimized.value = true;
controller.setPickerTarget(MapPickerTarget.isochroneCenter);
},
onIsochronesCalculated: (_) {},
onClose: controller.closeSheet,
);
break;
case TacticalSheetType.symbols:
sheetContent = TacticalSymbolsSheet(
activePlacementType: controller.symbols.activePlacementType.value,
placedSymbols: controller.symbols.placedSymbols,
onSelectSymbolType: (type) {
controller.symbols.selectSymbolForPlacement(type);
controller.isSheetMinimized.value = true;
Get.snackbar(
'الرموز العسكرية',
'انقر على الخريطة لتثبيت الرمز في الميدان 📍',
backgroundColor: const Color(0xFF0071E3),
colorText: Colors.white,
snackPosition: SnackPosition.BOTTOM,
);
},
onDeleteSymbol: (s) => controller.symbols.removeSymbol(s.id),
onClose: controller.closeSheet,
);
break;
case TacticalSheetType.overlays:
sheetContent = TacticalOverlaysSheet(
layers: controller.overlays.overlayLayers,
onToggleLayer: controller.overlays.toggleLayer,
onClose: controller.closeSheet,
);
break;
}
return PersistentTacticalSheetWrapper(
title: activeSheet.title,
icon: activeSheet.icon,
isMinimized: controller.isSheetMinimized.value,
onToggleMinimize: () => controller.isSheetMinimized.toggle(),
onClose: controller.closeSheet,
child: sheetContent,
);
}),
),
// ── 5. Active Turn-by-Turn Navigation HUD ──────────────
"""
content = content.replace(" // ── 5. Active Turn-by-Turn Navigation HUD ──────────────", stack_insert)
# 3. Replace the _openX methods to just open the sheet and not use showModalBottomSheet
replacements = {
"void _openRoutePlanner(BuildContext context) {": "void _openRoutePlanner(BuildContext context) {\n Navigator.pop(context);\n controller.openSheet(ActiveTacticalSheet(TacticalSheetType.route, 'مخطط مسار القوافل', Icons.route));\n }",
"void _openLosSheet(BuildContext context) {": "void _openLosSheet(BuildContext context) {\n Navigator.pop(context);\n controller.openSheet(ActiveTacticalSheet(TacticalSheetType.los, 'تحليل خط الرؤية (LOS)', Icons.visibility));\n }",
"void _openViewshed360Sheet(BuildContext context) {": "void _openViewshed360Sheet(BuildContext context) {\n Navigator.pop(context);\n controller.openSheet(ActiveTacticalSheet(TacticalSheetType.viewshed, 'رادار الرؤية 360 درجة', Icons.radar));\n }",
"void _openArtillerySheet(BuildContext context) {": "void _openArtillerySheet(BuildContext context) {\n Navigator.pop(context);\n controller.openSheet(ActiveTacticalSheet(TacticalSheetType.artillery, 'حاسبة المدفعية الميدانية', Icons.track_changes));\n }",
"void _openHlzSheet(BuildContext context) {": "void _openHlzSheet(BuildContext context) {\n Navigator.pop(context);\n controller.openSheet(ActiveTacticalSheet(TacticalSheetType.hlz, 'استطلاع المهابط (HLZ)', Icons.local_airport));\n }",
"void _openMinefieldSheet(BuildContext context) {": "void _openMinefieldSheet(BuildContext context) {\n Navigator.pop(context);\n controller.openSheet(ActiveTacticalSheet(TacticalSheetType.minefield, 'تأمين الممرات والألغام', Icons.warning_amber_rounded));\n }",
"void _openIsochroneSheet(BuildContext context) {": "void _openIsochroneSheet(BuildContext context) {\n Navigator.pop(context);\n controller.openSheet(ActiveTacticalSheet(TacticalSheetType.isochrone, 'نطاقات الحركة والإمداد', Icons.speed));\n }",
"void _openSymbolsSheet(BuildContext context) {": "void _openSymbolsSheet(BuildContext context) {\n Navigator.pop(context);\n controller.openSheet(ActiveTacticalSheet(TacticalSheetType.symbols, 'الرموز العسكرية (MIL-STD)', Icons.category));\n }",
"void _openOverlaysSheet(BuildContext context) {": "void _openOverlaysSheet(BuildContext context) {\n Navigator.pop(context);\n controller.openSheet(ActiveTacticalSheet(TacticalSheetType.overlays, 'شفافات العمليات (IPB)', Icons.layers));\n }"
}
# We need to remove the existing bodies of these methods.
for func_start, new_func in replacements.items():
# Find the start of the function
idx = content.find(func_start)
if idx == -1: continue
# Find the matching closing brace (very naive approach since it's at the end of the file)
end_idx = idx + len(func_start)
brace_count = 1
while brace_count > 0 and end_idx < len(content):
if content[end_idx] == '{': brace_count += 1
elif content[end_idx] == '}': brace_count -= 1
end_idx += 1
# Replace
content = content[:idx] + new_func + content[end_idx:]
with open(path, "w") as f:
f.write(content)