chore: add build artifacts, map assets, and routing data
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user