feat: Add Intaleq Native Android Kotlin & iOS Swift SDKs, Incline slope routing, Topographic contours and modular tactical app

This commit is contained in:
Hamza-Ayed
2026-08-20 23:54:58 +03:00
parent 4f6595b1eb
commit 431d1f95ff
187 changed files with 20640 additions and 151 deletions
@@ -0,0 +1,44 @@
enum AngleUnit {
degrees, // 0° - 360°
mils, // 0 - 6400 NATO Mils (₥)
dual, // Both: 045° (0800 ₥)
}
class AngleFormatter {
static const double degToMilsNato = 17.7777777778; // 6400 mils / 360 deg
static double toMils(double deg) {
return (deg * degToMilsNato) % 6400;
}
static double fromMils(double mils) {
return (mils / degToMilsNato) % 360;
}
static String format(double deg, AngleUnit unit, {bool includeLabel = true}) {
final cleanDeg = (deg % 360 + 360) % 360;
final milsVal = (cleanDeg * degToMilsNato).round() % 6400;
final degStr = '${cleanDeg.toStringAsFixed(1)}°';
final milsStr = '${milsVal.toString().padLeft(4, '0')} ₥';
switch (unit) {
case AngleUnit.degrees:
return includeLabel ? 'السمت: $degStr' : degStr;
case AngleUnit.mils:
return includeLabel ? 'السمت: $milsStr' : milsStr;
case AngleUnit.dual:
return includeLabel ? '$degStr ($milsStr)' : '$degStr ($milsStr)';
}
}
static String unitLabel(AngleUnit unit) {
switch (unit) {
case AngleUnit.degrees:
return 'الدرجات (Degrees °)';
case AngleUnit.mils:
return 'الميل العسكري (NATO Mils ₥)';
case AngleUnit.dual:
return 'عرض مزدوج (درجات + ميل)';
}
}
}
@@ -0,0 +1,114 @@
import 'package:flutter/material.dart';
enum LandmarkType {
minaret,
tower,
waterTank,
fort,
mountain,
militaryBase,
grainSilo,
}
class TacticalLandmark {
final String id;
final String name;
final String region;
final LandmarkType type;
final double lat;
final double lng;
final int elevationM;
final String description;
const TacticalLandmark({
required this.id,
required this.name,
required this.region,
required this.type,
required this.lat,
required this.lng,
required this.elevationM,
required this.description,
});
IconData get typeIcon {
switch (type) {
case LandmarkType.minaret:
return Icons.mosque;
case LandmarkType.tower:
return Icons.cell_tower;
case LandmarkType.waterTank:
return Icons.water_drop;
case LandmarkType.fort:
return Icons.castle;
case LandmarkType.mountain:
return Icons.terrain;
case LandmarkType.militaryBase:
return Icons.shield;
case LandmarkType.grainSilo:
return Icons.inventory_2;
}
}
String get typeLabelArabic {
switch (type) {
case LandmarkType.minaret:
return 'مئذنة / مسجد';
case LandmarkType.tower:
return 'برج اتصالات / إرسال';
case LandmarkType.waterTank:
return 'خزان مياه عالي';
case LandmarkType.fort:
return 'قلعة / موقع أثري';
case LandmarkType.mountain:
return 'قمة جبل / نقطة مثلثة';
case LandmarkType.militaryBase:
return 'قاعدة / مطار عسكري';
case LandmarkType.grainSilo:
return 'صوامع حبوب / منشأة عالية';
}
}
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
'region': region,
'type': type.name,
'lat': lat,
'lng': lng,
'elevationM': elevationM,
'description': description,
};
}
}
class ResectionObservation {
final TacticalLandmark landmark;
final double observedAzimuthDeg;
final double trueAzimuthDeg;
final DateTime timestamp;
ResectionObservation({
required this.landmark,
required this.observedAzimuthDeg,
required this.trueAzimuthDeg,
DateTime? timestamp,
}) : timestamp = timestamp ?? DateTime.now();
}
class ResectionResult {
final double lat;
final double lng;
final double estimatedAccuracyMeters;
final List<ResectionObservation> observations;
final Map<String, double> distanceToLandmarksKm;
const ResectionResult({
required this.lat,
required this.lng,
required this.estimatedAccuracyMeters,
required this.observations,
required this.distanceToLandmarksKm,
});
}
@@ -0,0 +1,94 @@
import 'package:flutter/material.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
enum ManeuverType {
straight,
slightRight,
right,
sharpRight,
slightLeft,
left,
sharpLeft,
keepRight,
keepLeft,
uTurn,
roundabout,
arrive,
unknown,
}
class NavigationStep {
final String instructionAr;
final String streetName;
final ManeuverType maneuver;
final double distanceMeters;
final LatLng location;
const NavigationStep({
required this.instructionAr,
required this.streetName,
required this.maneuver,
required this.distanceMeters,
required this.location,
});
IconData get icon {
switch (maneuver) {
case ManeuverType.arrive:
return Icons.flag_circle_rounded;
case ManeuverType.roundabout:
return Icons.roundabout_right_rounded;
case ManeuverType.right:
case ManeuverType.keepRight:
return Icons.turn_right_rounded;
case ManeuverType.slightRight:
return Icons.turn_slight_right_rounded;
case ManeuverType.left:
case ManeuverType.keepLeft:
return Icons.turn_left_rounded;
case ManeuverType.slightLeft:
return Icons.turn_slight_left_rounded;
case ManeuverType.sharpRight:
return Icons.turn_sharp_right_rounded;
case ManeuverType.sharpLeft:
return Icons.turn_sharp_left_rounded;
case ManeuverType.uTurn:
return Icons.u_turn_right_rounded;
case ManeuverType.straight:
default:
return Icons.straight_rounded;
}
}
}
class ActiveNavigationState {
final bool isNavigating;
final List<LatLng> routePoints;
final List<NavigationStep> steps;
final int currentStepIndex;
final double remainingDistanceKm;
final double remainingDurationMinutes;
final double currentSpeedKmH;
final double currentHeadingDeg;
final LatLng? currentPosition;
final bool isSimulating;
const ActiveNavigationState({
this.isNavigating = false,
this.routePoints = const [],
this.steps = const [],
this.currentStepIndex = 0,
this.remainingDistanceKm = 0.0,
this.remainingDurationMinutes = 0.0,
this.currentSpeedKmH = 0.0,
this.currentHeadingDeg = 0.0,
this.currentPosition,
this.isSimulating = false,
});
NavigationStep? get currentStep =>
(steps.isNotEmpty && currentStepIndex < steps.length) ? steps[currentStepIndex] : null;
NavigationStep? get nextStep =>
(steps.isNotEmpty && currentStepIndex + 1 < steps.length) ? steps[currentStepIndex + 1] : null;
}