Initial push to my private server

This commit is contained in:
Hamza-Ayed
2025-09-21 15:02:12 +03:00
parent 7e904ae460
commit f08ee61a7e
32 changed files with 1622 additions and 373 deletions

View File

@@ -426,9 +426,14 @@ class HomeCaptainController extends GetxController {
var res = await CRUD().get(
link: AppLink.getAllPaymentFromRide,
payload: {'driverID': box.read(BoxName.driverID).toString()});
data = jsonDecode(res);
if (res == 'failure') {
totalMoneyInSEFER = '0';
} else {
data = jsonDecode(res);
totalMoneyInSEFER = data['message'][0]['total_amount'];
}
totalMoneyInSEFER = data['message'][0]['total_amount'] ?? '0';
update();
}

View File

@@ -331,13 +331,7 @@ class MapDriverController extends GetxController {
'driverGoToPassengerTime': DateTime.now().toString(),
'status': 'Applied'
});
if (AppLink.endPoint != AppLink.seferCairoServer) {
CRUD().post(link: "${AppLink.endPoint}/ride/rides/update.php", payload: {
'id': (rideId),
'driverGoToPassengerTime': DateTime.now().toString(),
'status': 'Applied'
});
}
// Get.find<HomeCaptainController>().changeToAppliedRide('Applied');
Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(

View File

@@ -0,0 +1,112 @@
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 = "";
}
}

View File

@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:math';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
@@ -10,6 +11,7 @@ import 'package:sefer_driver/constant/colors.dart';
// استخدام نفس مسارات الاستيراد التي قدمتها
import '../../../constant/api_key.dart';
import '../../../constant/links.dart';
import '../../../print.dart';
import '../../functions/crud.dart';
import '../../functions/tts.dart';
@@ -525,45 +527,127 @@ class NavigationController extends GetxController {
String _parseInstruction(String html) =>
html.replaceAll(RegExp(r'<[^>]*>'), ' ');
double _haversineKm(double lat1, double lon1, double lat2, double lon2) {
const R = 6371.0; // km
final dLat = (lat2 - lat1) * math.pi / 180.0;
final dLon = (lon2 - lon1) * math.pi / 180.0;
final a = math.sin(dLat / 2) * math.sin(dLat / 2) +
math.cos(lat1 * math.pi / 180.0) *
math.cos(lat2 * math.pi / 180.0) *
math.sin(dLon / 2) *
math.sin(dLon / 2);
final c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
return R * c;
}
/// تحويل نصف قطر بالكيلومتر إلى دلتا درجات عرض
double _kmToLatDelta(double km) => km / 111.0;
/// تحويل نصف قطر بالكيلومتر إلى دلتا درجات طول (تعتمد على خط العرض)
double _kmToLngDelta(double km, double atLat) =>
km / (111.320 * math.cos(atLat * math.pi / 180.0)).abs().clamp(1e-6, 1e9);
/// حساب درجة التطابق النصي (كل كلمة تبدأ بها الاسم = 2 نقاط، يحتويها = 1 نقطة)
double _relevanceScore(String name, String query) {
final n = name.toLowerCase();
final parts =
query.toLowerCase().split(RegExp(r'\s+')).where((p) => p.length >= 2);
double s = 0.0;
for (final p in parts) {
if (n.startsWith(p)) {
s += 2.0;
} else if (n.contains(p)) {
s += 1.0;
}
}
return s;
}
Future<void> getPlaces() async {
if (placeDestinationController.text.trim().isEmpty) {
final q = placeDestinationController.text.trim();
if (q.isEmpty) {
placesDestination = [];
update();
return;
}
if (myLocation == null) {
Get.snackbar('انتظر', 'جاري تحديد موقعك الحالي...');
return;
}
final query = placeDestinationController.text.trim();
final lat = myLocation!.latitude;
final lng = myLocation!.longitude;
const double range = 2.2;
final lat_min = lat - range,
lat_max = lat + range,
lng_min = lng - range,
lng_max = lng + range;
// نصف قطر البحث بالكيلومتر (عدّل حسب رغبتك)
const radiusKm = 200.0;
// حساب الباوند الصحيح (درجات، وليس 2.2 درجة ثابتة)
final latDelta = _kmToLatDelta(radiusKm);
final lngDelta = _kmToLngDelta(radiusKm, lat);
final latMin = lat - latDelta;
final latMax = lat + latDelta;
final lngMin = lng - lngDelta;
final lngMax = lng + lngDelta;
try {
final response = await CRUD().post(
link: AppLink.getPlacesSyria,
payload: {
'query': query,
'lat_min': lat_min.toString(),
'lat_max': lat_max.toString(),
'lng_min': lng_min.toString(),
'lng_max': lng_max.toString(),
'query': q,
'lat_min': latMin.toString(),
'lat_max': latMax.toString(),
'lng_min': lngMin.toString(),
'lng_max': lngMax.toString(),
},
);
if (response != 'failure') {
placesDestination = response['message'] ?? [];
// يدعم شكلي استجابة: إما {"...","message":[...]} أو قائمة مباشرة [...]
List list;
if (response is Map && response['message'] is List) {
list = List.from(response['message'] as List);
} else if (response is List) {
list = List.from(response);
} else {
placesDestination = [];
print('Unexpected response shape');
return;
}
// جهّز الحقول المحتملة للأسماء
String _bestName(Map p) {
return (p['name'] ?? p['name_ar'] ?? p['name_en'] ?? '').toString();
}
// احسب المسافة ودرجة التطابق والنقاط
for (final p in list) {
final plat = double.tryParse(p['latitude']?.toString() ?? '') ?? 0.0;
final plng = double.tryParse(p['longitude']?.toString() ?? '') ?? 0.0;
final d = _haversineKm(lat, lng, plat, plng);
final rel = _relevanceScore(_bestName(p), q);
// معادلة ترتيب ذكية: مسافة أقل + تطابق أعلى = نقاط أعلى
// تضيف +1 لضمان عدم وصول الوزن للصفر عند عدم وجود تطابق
final score = (1.0 / (1.0 + d)) * (1.0 + rel);
p['distanceKm'] = d;
p['relevance'] = rel;
p['score'] = score;
}
// رتّب حسب score تنازليًا، ثم المسافة تصاعديًا كحسم
list.sort((a, b) {
final sa = (a['score'] ?? 0.0) as double;
final sb = (b['score'] ?? 0.0) as double;
final cmp = sb.compareTo(sa);
if (cmp != 0) return cmp;
final da = (a['distanceKm'] ?? 1e9) as double;
final db = (b['distanceKm'] ?? 1e9) as double;
return da.compareTo(db);
});
// خذ أول 1015 للعرض (اختياري)، أو اعرض الكل
placesDestination = list.take(15).toList();
Log.print('placesDestination: $placesDestination');
update();
} catch (e) {
print('Exception in getPlaces: $e');
} finally {
update();
}
}

View File

@@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:local_auth/local_auth.dart';
import 'package:sefer_driver/constant/box_name.dart';
import 'package:sefer_driver/controller/payment/smsPaymnet/payment_services.dart';
import 'package:sefer_driver/main.dart';
import 'package:sefer_driver/views/widgets/error_snakbar.dart';
import 'package:get/get.dart';
@@ -27,48 +28,48 @@ class PaymobPayout extends GetxController {
sensitiveTransaction: true,
));
if (didAuthenticate) {
var dec = await CRUD()
.postWallet(link: AppLink.paymobPayoutDriverWallet, payload: {
"issuer": issuer,
"method": "wallet",
"amount": amount, //9.0,
"full_name":
'${box.read(BoxName.nameDriver)} ${box.read(BoxName.lastNameDriver)}',
"msisdn": msisdn, //"01010101010",
"bank_transaction_type": "cash_transfer"
});
if (dec['disbursement_status'] == 'successful') {
var paymentToken = await Get.find<CaptainWalletController>()
.generateToken(
((-1) * (double.parse(dec['amount'].toString())) - payOutFee)
.toStringAsFixed(0));
await CRUD().postWallet(link: AppLink.addDrivePayment, payload: {
'rideId': DateTime.now().toIso8601String(),
'amount':
((-1) * (double.parse(dec['amount'].toString())) - payOutFee)
.toStringAsFixed(0),
'payment_method': 'payout',
'passengerID': 'myself',
'token': paymentToken,
'driverID': box.read(BoxName.driverID).toString(),
});
await Get.find<CaptainWalletController>()
.addSeferWallet('payout fee myself', payOutFee.toString());
await updatePaymentToPaid(box.read(BoxName.driverID).toString());
await sendEmail(
box.read(BoxName.driverID).toString(),
amount,
box.read(BoxName.phoneDriver).toString(),
box.read(BoxName.nameDriver).toString(),
'Wallet',
box.read(BoxName.emailDriver).toString());
// var dec = await CRUD()
// .postWallet(link: AppLink.paymobPayoutDriverWallet, payload: {
// "issuer": issuer,
// "method": "wallet",
// "amount": amount, //9.0,
// "full_name":
// '${box.read(BoxName.nameDriver)} ${box.read(BoxName.lastNameDriver)}',
// "msisdn": msisdn, //"01010101010",
// "bank_transaction_type": "cash_transfer"
// });
// if (dec['disbursement_status'] == 'successful') {
// var paymentToken = await Get.find<CaptainWalletController>()
// .generateToken(
// ((-1) * (double.parse(dec['amount'].toString())) - payOutFee)
// .toStringAsFixed(0));
// await CRUD().postWallet(link: AppLink.addDrivePayment, payload: {
// 'rideId': DateTime.now().toIso8601String(),
// 'amount':
// ((-1) * (double.parse(dec['amount'].toString())) - payOutFee)
// .toStringAsFixed(0),
// 'payment_method': 'payout',
// 'passengerID': 'myself',
// 'token': paymentToken,
// 'driverID': box.read(BoxName.driverID).toString(),
// });
// await Get.find<CaptainWalletController>()
// .addSeferWallet('payout fee myself', payOutFee.toString());
// await updatePaymentToPaid(box.read(BoxName.driverID).toString());
// await sendEmail(
// box.read(BoxName.driverID).toString(),
// amount,
// box.read(BoxName.phoneDriver).toString(),
// box.read(BoxName.nameDriver).toString(),
// 'Wallet',
// box.read(BoxName.emailDriver).toString());
mySnackbarSuccess('${'Transaction successful'.tr} ${dec['amount']}');
// mySnackbarSuccess('${'Transaction successful'.tr} ${dec['amount']}');
Get.find<CaptainWalletController>().refreshCaptainWallet();
} else if (dec['disbursement_status'] == 'failed') {
mySnackeBarError('Transaction failed'.tr);
}
// Get.find<CaptainWalletController>().refreshCaptainWallet();
// } else if (dec['disbursement_status'] == 'failed') {
// mySnackeBarError('Transaction failed'.tr);
// }
} else {
MyDialog().getDialog('Authentication failed'.tr, ''.tr, () {
Get.back();

View File

@@ -63,7 +63,7 @@ class SplashScreenController extends GetxController
box.read(BoxName.onBoarding) == null
? Get.off(() => OnBoardingPage())
: box.read(BoxName.phoneDriver) != null &&
box.read(BoxName.phoneVerified) == '1'
box.read(BoxName.phoneVerified).toString() == '1'
? await Get.put(LoginDriverController())
.loginWithGoogleCredential(
box.read(BoxName.driverID).toString(),