chore: add build artifacts, map assets, and routing data
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import '../env/env.dart';
|
||||
|
||||
class ApiConstants {
|
||||
ApiConstants._();
|
||||
|
||||
// Official Keys extracted from Siro Ecosystem (Encrypted & Obfuscated via Envied)
|
||||
static final String mapSaasKey = Env.mapSaasApiKey;
|
||||
static final String googleMapApiKey = Env.googleMapApiKey;
|
||||
|
||||
// MapSaaS Endpoints
|
||||
static const String mapSaasRoute = 'https://map-saas.intaleqapp.com/api/maps/route';
|
||||
static const String mapSaasSearch = 'https://map-saas.intaleqapp.com/api/geocoding/search';
|
||||
static const String mapSaasPlaces = 'https://map-saas.intaleqapp.com/api/geocoding/places';
|
||||
static const String mapSaasTelemetry = 'https://map-saas.intaleqapp.com/api/telemetry';
|
||||
static const String mapSaasStyleBase = 'https://map-saas.intaleqapp.com/api/maps/style.json';
|
||||
static const String googlePlacesNearby = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json';
|
||||
|
||||
// 50 km Radius Threshold (Strictly as specified)
|
||||
static const double maxSearchRadiusMeters = 50000.0;
|
||||
static const double maxSearchRadiusKm = 50.0;
|
||||
|
||||
// Secondary / Alternative Routing Engines
|
||||
static const String osrmRouteJordan = 'https://routesjo.intaleq.xyz/route/v1/driving';
|
||||
static const String osrmRouteSyria = 'https://routes-syria.siromove.com/route/v1/driving';
|
||||
static const String osrmRouteEgypt = 'https://routes-egypt.siromove.com/route/v1/driving';
|
||||
|
||||
// Default Jordan Geospatial Center (Amman 7th Circle / Abdoun)
|
||||
static const double defaultLat = 31.9539;
|
||||
static const double defaultLng = 35.9106;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppColors {
|
||||
AppColors._();
|
||||
|
||||
// Pure White & Canvas
|
||||
static const Color pureWhite = Color(0xFFFFFFFF);
|
||||
static const Color canvasLight = Color(0xFFFBFBFD);
|
||||
static const Color surfaceCard = Color(0xFFFFFFFF);
|
||||
static const Color surfaceMuted = Color(0xFFF5F5F7);
|
||||
|
||||
// Apple Text Palette
|
||||
static const Color textPrimary = Color(0xFF1D1D1F);
|
||||
static const Color textSecondary = Color(0xFF424245);
|
||||
static const Color textMuted = Color(0xFF86868B);
|
||||
|
||||
// Sovereign / Apple Accent Colors
|
||||
static const Color appleBlue = Color(0xFF0071E3);
|
||||
static const Color appleBlueHover = Color(0xFF0077ED);
|
||||
static const Color tacticalNavy = Color(0xFF0B192C);
|
||||
static const Color tacticalEmerald = Color(0xFF059669);
|
||||
static const Color sovereignGold = Color(0xFFD97706);
|
||||
static const Color coralDanger = Color(0xFFDC2626);
|
||||
|
||||
// Borders & Dividers
|
||||
static const Color borderSubtle = Color(0x12000000);
|
||||
static const Color borderGlass = Color(0x1F000000);
|
||||
static const Color glassFill = Color(0xD1FFFFFF);
|
||||
|
||||
// Dark Theme Palette
|
||||
static const Color darkCanvas = Color(0xFF0B0F17);
|
||||
static const Color darkSurface = Color(0xFF161A22);
|
||||
static const Color darkCard = Color(0xFF1F2430);
|
||||
static const Color darkText = Color(0xFFF5F5F7);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class CarPlatformBridge {
|
||||
CarPlatformBridge._();
|
||||
|
||||
static const _channel = MethodChannel('com.siro.siro_maps/car_navigation');
|
||||
static bool _isInitialized = false;
|
||||
|
||||
static void ensureInitialized() {
|
||||
if (_isInitialized) return;
|
||||
_channel.setMethodCallHandler(_handleMethodCall);
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
static Future<dynamic> _handleMethodCall(MethodCall call) async {
|
||||
switch (call.method) {
|
||||
case 'isCarAppConnected':
|
||||
return false;
|
||||
default:
|
||||
throw MissingPluginException();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> updateNavState({
|
||||
required double lat,
|
||||
required double lng,
|
||||
required double bearing,
|
||||
required double speed,
|
||||
required String instruction,
|
||||
required double distanceToStep,
|
||||
required double totalDistance,
|
||||
required double eta,
|
||||
required int maneuver,
|
||||
required bool isNavigating,
|
||||
bool isMapDarkMode = false,
|
||||
}) async {
|
||||
try {
|
||||
await _channel.invokeMethod('updateNavState', {
|
||||
'lat': lat,
|
||||
'lng': lng,
|
||||
'bearing': bearing,
|
||||
'speed': speed,
|
||||
'instruction': instruction,
|
||||
'distanceToStep': distanceToStep,
|
||||
'totalDistance': totalDistance,
|
||||
'eta': eta,
|
||||
'maneuver': maneuver,
|
||||
'isNavigating': isNavigating,
|
||||
'isMapDarkMode': isMapDarkMode,
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
static Future<void> stopNavigation() async {
|
||||
try {
|
||||
await _channel.invokeMethod('stopNavigation');
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import 'dart:async';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
|
||||
class ConnectivityService {
|
||||
ConnectivityService._();
|
||||
static final ConnectivityService instance = ConnectivityService._();
|
||||
|
||||
final Connectivity _connectivity = Connectivity();
|
||||
StreamSubscription<List<ConnectivityResult>>? _subscription;
|
||||
final StreamController<bool> _controller = StreamController<bool>.broadcast();
|
||||
|
||||
Stream<bool> get onConnectivityChanged => _controller.stream;
|
||||
|
||||
Future<bool> checkConnection() async {
|
||||
try {
|
||||
final results = await _connectivity.checkConnectivity();
|
||||
return _hasConnection(results);
|
||||
} catch (_) {
|
||||
return true; // Fallback to optimistic
|
||||
}
|
||||
}
|
||||
|
||||
void initialize() {
|
||||
_subscription?.cancel();
|
||||
_subscription = _connectivity.onConnectivityChanged.listen((results) {
|
||||
_controller.add(_hasConnection(results));
|
||||
});
|
||||
}
|
||||
|
||||
bool _hasConnection(List<ConnectivityResult> results) {
|
||||
return results.any((r) =>
|
||||
r == ConnectivityResult.mobile ||
|
||||
r == ConnectivityResult.wifi ||
|
||||
r == ConnectivityResult.ethernet ||
|
||||
r == ConnectivityResult.vpn);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_subscription?.cancel();
|
||||
_controller.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import 'dart:async';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
class LocationService {
|
||||
LocationService._();
|
||||
static final LocationService instance = LocationService._();
|
||||
|
||||
Future<bool> checkAndRequestPermission() async {
|
||||
print("🛰️ [LocationService] Checking location service & permissions...");
|
||||
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
if (!serviceEnabled) {
|
||||
print("⚠️ [LocationService] Device location services are DISABLED!");
|
||||
return false;
|
||||
}
|
||||
|
||||
LocationPermission permission = await Geolocator.checkPermission();
|
||||
print("🛰️ [LocationService] Current permission status: $permission");
|
||||
if (permission == LocationPermission.denied) {
|
||||
print("🛰️ [LocationService] Requesting location permission...");
|
||||
permission = await Geolocator.requestPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
print("❌ [LocationService] User DENIED location permission!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (permission == LocationPermission.deniedForever) {
|
||||
print("❌ [LocationService] Location permission is permanently denied!");
|
||||
return false;
|
||||
}
|
||||
|
||||
print("✅ [LocationService] Location permission granted: $permission");
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<Position?> getCurrentPosition() async {
|
||||
final hasPerm = await checkAndRequestPermission();
|
||||
if (!hasPerm) {
|
||||
print("⚠️ [LocationService] Cannot get current position (permission missing)");
|
||||
return null;
|
||||
}
|
||||
|
||||
print("🛰️ [LocationService] Fetching current GPS position from hardware...");
|
||||
final pos = await Geolocator.getCurrentPosition(
|
||||
locationSettings: const LocationSettings(
|
||||
accuracy: LocationAccuracy.high,
|
||||
),
|
||||
);
|
||||
print("📍 [LocationService] Acquired GPS fix: lat=${pos.latitude.toStringAsFixed(6)}, lng=${pos.longitude.toStringAsFixed(6)}, alt=${pos.altitude.toStringAsFixed(1)}m, speed=${pos.speed.toStringAsFixed(1)}m/s, heading=${pos.heading.toStringAsFixed(1)}°");
|
||||
return pos;
|
||||
}
|
||||
|
||||
Stream<Position> getPositionStream({
|
||||
int distanceFilter = 2,
|
||||
}) {
|
||||
final locationSettings = LocationSettings(
|
||||
accuracy: LocationAccuracy.bestForNavigation,
|
||||
distanceFilter: distanceFilter,
|
||||
);
|
||||
return Geolocator.getPositionStream(locationSettings: locationSettings);
|
||||
}
|
||||
|
||||
double calculateDistance(LatLng start, LatLng end) {
|
||||
return Geolocator.distanceBetween(
|
||||
start.latitude,
|
||||
start.longitude,
|
||||
end.latitude,
|
||||
end.longitude,
|
||||
);
|
||||
}
|
||||
|
||||
double calculateBearing(LatLng start, LatLng end) {
|
||||
return Geolocator.bearingBetween(
|
||||
start.latitude,
|
||||
start.longitude,
|
||||
end.latitude,
|
||||
end.longitude,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter_tts/flutter_tts.dart';
|
||||
|
||||
class TtsService {
|
||||
TtsService._();
|
||||
static final TtsService instance = TtsService._();
|
||||
|
||||
final FlutterTts _flutterTts = FlutterTts();
|
||||
bool _isMuted = false;
|
||||
bool _isInitialized = false;
|
||||
|
||||
bool get isMuted => _isMuted;
|
||||
|
||||
Future<void> init() async {
|
||||
if (_isInitialized) return;
|
||||
try {
|
||||
await _flutterTts.setLanguage('ar');
|
||||
await _flutterTts.setSpeechRate(0.5);
|
||||
await _flutterTts.setVolume(1.0);
|
||||
await _flutterTts.setPitch(1.0);
|
||||
_isInitialized = true;
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void toggleMute() {
|
||||
_isMuted = !_isMuted;
|
||||
if (_isMuted) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> speak(String text) async {
|
||||
if (_isMuted || text.trim().isEmpty) return;
|
||||
try {
|
||||
await init();
|
||||
await _flutterTts.stop();
|
||||
await _flutterTts.speak(text);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
try {
|
||||
await _flutterTts.stop();
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../constants/app_colors.dart';
|
||||
|
||||
class AppTheme {
|
||||
AppTheme._();
|
||||
|
||||
static ThemeData get lightTheme {
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.light,
|
||||
fontFamily: '.SF Pro Text', // Native iOS San Francisco & SF Arabic
|
||||
scaffoldBackgroundColor: AppColors.canvasLight,
|
||||
colorScheme: const ColorScheme.light(
|
||||
primary: AppColors.appleBlue,
|
||||
secondary: AppColors.tacticalNavy,
|
||||
surface: AppColors.surfaceCard,
|
||||
error: AppColors.coralDanger,
|
||||
onPrimary: Colors.white,
|
||||
onSurface: AppColors.textPrimary,
|
||||
),
|
||||
textTheme: const TextTheme(
|
||||
displayLarge: TextStyle(
|
||||
color: AppColors.textPrimary,
|
||||
fontWeight: FontWeight.w800,
|
||||
letterSpacing: -0.5,
|
||||
),
|
||||
titleLarge: TextStyle(
|
||||
color: AppColors.textPrimary,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
bodyLarge: TextStyle(
|
||||
color: AppColors.textPrimary,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
bodyMedium: TextStyle(
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
appBarTheme: const AppBarTheme(
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
systemOverlayStyle: SystemUiOverlayStyle.dark,
|
||||
iconTheme: IconThemeData(color: AppColors.textPrimary),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
List<LatLng> decodePolylineIsolate(String encoded) {
|
||||
List<LatLng> points = [];
|
||||
int index = 0, len = encoded.length;
|
||||
int lat = 0, lng = 0;
|
||||
|
||||
while (index < len) {
|
||||
int b, shift = 0, result = 0;
|
||||
do {
|
||||
b = encoded.codeUnitAt(index++) - 63;
|
||||
result |= (b & 0x1f) << shift;
|
||||
shift += 5;
|
||||
} while (b >= 0x20);
|
||||
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
|
||||
lat += dlat;
|
||||
|
||||
shift = 0;
|
||||
result = 0;
|
||||
do {
|
||||
b = encoded.codeUnitAt(index++) - 63;
|
||||
result |= (b & 0x1f) << shift;
|
||||
shift += 5;
|
||||
} while (b >= 0x20);
|
||||
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
|
||||
lng += dlng;
|
||||
|
||||
points.add(LatLng(lat / 1E5, lng / 1E5));
|
||||
}
|
||||
return points;
|
||||
}
|
||||
Reference in New Issue
Block a user