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