feat: N1d/N2/N3 + قانون فلاتر وإعادة ضبط تطبيق السائق
الباك إند: - تعيين أول أدمن صار يُنشئ المستخدم إن لم يوجد — كان يشترط دخولاً سابقاً، وهي بيضة ودجاجة تمنع الدخول إلى لوحة أي مستأجر جديد أصلاً. - OTP_DEV_MODE كان يفشل مفتوحاً (`!== 'false'`): غياب المتغيّر أو خطأ مطبعي يترك الإنتاج برمز ثابت يفتح كل حساب، ويحرس السحب المالي كذلك. صار `=== 'true'` في الإعداد وفي قارئَيه، مع تحذير عند الإقلاع. - N2: التحقّق من اللوغو عند الرفع (PNG/JPEG · 512+ · مربّع · سقف 5MB) عبر قراءة الترويسة بلا اعتمادية — بدل اكتشاف أيقونة ممطوطة بعد النشر. N3: السكربت يولّد build_config.dart بأعلام const (طبقات docs/22 §1.5)، ويضبط bundle IDs واسم التطبيق والأيقونات/splash، و--build يشغّل Shorebird. فلاتر: - docs/23: قانون مُلزِم للتطبيقين (البنية · Cubit · طبقة الشبكة · الأعلام). - السائق: أُزيل Dart القديم (GetX) مع الإبقاء على الأصيل والإضافات وشهادات التوقيع وShorebird وFirebase الخاص به، وأُعيد هيكلته مطابقاً للراكب. - طبقة الشبكة ترسل x-device-id وتجدّد التوكن عند 401 مرة واحدة فقط. - الحزم موحّدة بين التطبيقين، والـAPI https حصراً في الاثنين. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
3ab74a13a8
commit
de4bbd00ac
@@ -1,112 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:google_polyline_algorithm/google_polyline_algorithm.dart';
|
||||
import 'package:sefer_driver/constant/api_key.dart';
|
||||
import 'package:sefer_driver/constant/box_name.dart';
|
||||
import 'package:sefer_driver/constant/links.dart';
|
||||
import 'package:sefer_driver/controller/functions/crud.dart';
|
||||
import 'package:sefer_driver/controller/functions/tts.dart';
|
||||
|
||||
import '../../../main.dart';
|
||||
|
||||
/// Handles map-related logic: fetching routes, drawing polylines, and managing markers.
|
||||
class NavigationService extends GetxService {
|
||||
final CRUD _crud = CRUD();
|
||||
final TextToSpeechController _tts = Get.put(TextToSpeechController());
|
||||
|
||||
final RxSet<Marker> markers = <Marker>{}.obs;
|
||||
final RxSet<Polyline> polylines = <Polyline>{}.obs;
|
||||
final RxString currentInstruction = "".obs;
|
||||
|
||||
BitmapDescriptor carIcon = BitmapDescriptor.defaultMarker;
|
||||
BitmapDescriptor passengerIcon = BitmapDescriptor.defaultMarker;
|
||||
BitmapDescriptor startIcon = BitmapDescriptor.defaultMarker;
|
||||
BitmapDescriptor endIcon = BitmapDescriptor.defaultMarker;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_loadCustomIcons();
|
||||
}
|
||||
|
||||
void _loadCustomIcons() async {
|
||||
carIcon = await _createBitmapDescriptor('assets/images/car.png');
|
||||
passengerIcon = await _createBitmapDescriptor('assets/images/picker.png');
|
||||
startIcon = await _createBitmapDescriptor('assets/images/A.png');
|
||||
endIcon = await _createBitmapDescriptor('assets/images/b.png');
|
||||
}
|
||||
|
||||
Future<BitmapDescriptor> _createBitmapDescriptor(String assetName) {
|
||||
return BitmapDescriptor.fromAssetImage(
|
||||
ImageConfiguration(
|
||||
size: const Size(30, 35), devicePixelRatio: Get.pixelRatio),
|
||||
assetName,
|
||||
);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> getRoute({
|
||||
required LatLng origin,
|
||||
required LatLng destination,
|
||||
}) async {
|
||||
final url =
|
||||
'${AppLink.googleMapsLink}directions/json?language=${box.read(BoxName.lang)}&destination=${destination.latitude},${destination.longitude}&origin=${origin.latitude},${origin.longitude}&key=${AK.mapAPIKEY}';
|
||||
|
||||
final response = await _crud.getGoogleApi(link: url, payload: {});
|
||||
|
||||
if (response != null && response['routes'].isNotEmpty) {
|
||||
return response['routes'][0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void drawRoute(Map<String, dynamic> routeData, {Color color = Colors.blue}) {
|
||||
final pointsString = routeData["overview_polyline"]["points"];
|
||||
final points = decodePolyline(pointsString)
|
||||
.map((p) => LatLng(p[0].toDouble(), p[1].toDouble()))
|
||||
.toList();
|
||||
|
||||
final polyline = Polyline(
|
||||
polylineId: PolylineId(routeData["summary"] ?? DateTime.now().toString()),
|
||||
points: points,
|
||||
width: 8,
|
||||
color: color,
|
||||
);
|
||||
|
||||
polylines.add(polyline);
|
||||
}
|
||||
|
||||
void updateCarMarker(LatLng position, double heading) {
|
||||
markers.removeWhere((m) => m.markerId.value == 'MyLocation');
|
||||
markers.add(
|
||||
Marker(
|
||||
markerId: MarkerId('MyLocation'.tr),
|
||||
position: position,
|
||||
icon: carIcon,
|
||||
rotation: heading,
|
||||
anchor: const Offset(0.5, 0.5),
|
||||
flat: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void setInitialMarkers(
|
||||
LatLng passengerLocation, LatLng passengerDestination) {
|
||||
markers.clear();
|
||||
markers.add(Marker(
|
||||
markerId: const MarkerId('passengerLocation'),
|
||||
position: passengerLocation,
|
||||
icon: passengerIcon,
|
||||
));
|
||||
markers.add(Marker(
|
||||
markerId: const MarkerId('passengerDestination'),
|
||||
position: passengerDestination,
|
||||
icon: endIcon,
|
||||
));
|
||||
}
|
||||
|
||||
void clearRoutes() {
|
||||
polylines.clear();
|
||||
currentInstruction.value = "";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user