8/6/2
This commit is contained in:
@@ -194,9 +194,12 @@ class FirebaseMessagesController extends GetxController {
|
||||
title: 'Ok'.tr,
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
await Get.find<MapPassengerController>()
|
||||
.getCarsLocationByPassengerAndReloadMarker(
|
||||
box.read(BoxName.carType), 7000);
|
||||
|
||||
Get.find<MapPassengerController>()
|
||||
.delayAndFetchRideStatusForAllDriverAvailable(
|
||||
Get.find<MapPassengerController>().rideId);
|
||||
.confirmRideForAllDriverAvailable();
|
||||
},
|
||||
),
|
||||
cancel: MyElevatedButton(
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:math' show cos, pow, sqrt;
|
||||
import 'dart:math' show Random, cos, pi, pow, sin, sqrt;
|
||||
import 'dart:math' as math;
|
||||
import 'package:vector_math/vector_math.dart' show radians, degrees;
|
||||
|
||||
import 'package:SEFER/controller/functions/tts.dart';
|
||||
import 'package:SEFER/views/home/map_page_passenger.dart';
|
||||
@@ -354,10 +355,15 @@ class MapPassengerController extends GetxController {
|
||||
if (rideId != 'yet') {
|
||||
await CRUD().post(link: AppLink.updateDriverOrder, payload: {
|
||||
"order_id": rideId.toString(), // Convert to String
|
||||
"status": 'Cancel'
|
||||
"status": 'waiting'
|
||||
});
|
||||
await CRUD().post(link: AppLink.updateRides, payload: {
|
||||
"id": rideId.toString(), // Convert to String
|
||||
"status": 'waiting'
|
||||
});
|
||||
tick = 0;
|
||||
}
|
||||
confirmRideForFirstDriver();
|
||||
confirmRideForAllDriverAvailable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -538,23 +544,33 @@ class MapPassengerController extends GetxController {
|
||||
}
|
||||
|
||||
bool isTimerFromDriverToPassengerAfterAppliedRunning = true;
|
||||
int beginRideInterval = 4; // Interval in seconds for getBeginRideFromDriver
|
||||
|
||||
void startTimerFromDriverToPassengerAfterApplied() async {
|
||||
for (int i = 0;
|
||||
i <= timeToPassengerFromDriverAfterApplied &&
|
||||
isTimerFromDriverToPassengerAfterAppliedRunning;
|
||||
i++) {
|
||||
int secondsElapsed = 0;
|
||||
|
||||
while (secondsElapsed <= timeToPassengerFromDriverAfterApplied &&
|
||||
isTimerFromDriverToPassengerAfterAppliedRunning) {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
secondsElapsed++;
|
||||
|
||||
progressTimerToPassengerFromDriverAfterApplied =
|
||||
i / timeToPassengerFromDriverAfterApplied;
|
||||
secondsElapsed / timeToPassengerFromDriverAfterApplied;
|
||||
remainingTimeToPassengerFromDriverAfterApplied =
|
||||
timeToPassengerFromDriverAfterApplied - i;
|
||||
timeToPassengerFromDriverAfterApplied - secondsElapsed;
|
||||
|
||||
if (remainingTimeToPassengerFromDriverAfterApplied < 69) {
|
||||
if (rideTimerBegin == false) {
|
||||
getBeginRideFromDriver();
|
||||
rideTimerBegin = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Call getBeginRideFromDriver every 4 seconds
|
||||
if (secondsElapsed % beginRideInterval == 0) {
|
||||
getBeginRideFromDriver();
|
||||
uploadPassengerLocation();
|
||||
}
|
||||
|
||||
int minutes =
|
||||
(remainingTimeToPassengerFromDriverAfterApplied / 60).floor();
|
||||
int seconds = remainingTimeToPassengerFromDriverAfterApplied % 60;
|
||||
@@ -565,6 +581,8 @@ class MapPassengerController extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the getBeginRideFromDriverForDuration function as it's no longer needed
|
||||
|
||||
// Function to stop the timer
|
||||
void stopTimerFromDriverToPassengerAfterApplied() {
|
||||
isTimerFromDriverToPassengerAfterAppliedRunning = false;
|
||||
@@ -712,22 +730,23 @@ class MapPassengerController extends GetxController {
|
||||
try {
|
||||
var res = await CRUD()
|
||||
.get(link: AppLink.getRideStatusBegin, payload: {'ride_id': rideId});
|
||||
if (res == 'failure') {}
|
||||
var decode = jsonDecode(res);
|
||||
if (res != 'failure') {
|
||||
var decode = jsonDecode(res);
|
||||
|
||||
if (decode['data']['status'] == 'Begin') {
|
||||
timeToPassengerFromDriverAfterApplied = 0;
|
||||
remainingTime = 0;
|
||||
remainingTimeToPassengerFromDriverAfterApplied = 0;
|
||||
remainingTimeDriverWaitPassenger5Minute = 0;
|
||||
rideTimerBegin = true;
|
||||
statusRide = 'Begin';
|
||||
isDriverInPassengerWay = false;
|
||||
isDriverArrivePassenger = false;
|
||||
update();
|
||||
// isCancelRidePageShown = true;
|
||||
rideIsBeginPassengerTimer();
|
||||
runWhenRideIsBegin();
|
||||
if (decode['data']['status'] == 'Begin') {
|
||||
timeToPassengerFromDriverAfterApplied = 0;
|
||||
remainingTime = 0;
|
||||
remainingTimeToPassengerFromDriverAfterApplied = 0;
|
||||
remainingTimeDriverWaitPassenger5Minute = 0;
|
||||
rideTimerBegin = true;
|
||||
statusRide = 'Begin';
|
||||
isDriverInPassengerWay = false;
|
||||
isDriverArrivePassenger = false;
|
||||
update();
|
||||
// isCancelRidePageShown = true;
|
||||
rideIsBeginPassengerTimer();
|
||||
runWhenRideIsBegin();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Handle the error or perform any necessary actions
|
||||
@@ -1138,6 +1157,7 @@ class MapPassengerController extends GetxController {
|
||||
bool isDriversTokensSend = false;
|
||||
confirmRideForAllDriverAvailable() async {
|
||||
// isDriversTokensSend = true;
|
||||
|
||||
driversToken.remove(driverToken);
|
||||
PaymentController paymentController = Get.find<PaymentController>();
|
||||
rideConfirm = true;
|
||||
@@ -1195,7 +1215,7 @@ class MapPassengerController extends GetxController {
|
||||
polylineCoordinates.toString());
|
||||
}
|
||||
|
||||
delayAndFetchRideStatusForAllDriverAvailable(rideId);
|
||||
(rideId);
|
||||
|
||||
update();
|
||||
}
|
||||
@@ -1210,9 +1230,10 @@ class MapPassengerController extends GetxController {
|
||||
|
||||
Log.print('tick: $tick');
|
||||
|
||||
if (res.toString() == 'waiting' && tick == 15) {
|
||||
if (res.toString() == 'waiting' && tick >= 15) {
|
||||
timer.cancel(); // Stop the current timer
|
||||
delayAndFetchRideStatusForAllDriverAvailable(rideId);
|
||||
showAndResearchForCaptain();
|
||||
// delayAndFetchRideStatusForAllDriverAvailable(rideId);
|
||||
} else if (res.toString() == 'Apply') {
|
||||
timer.cancel(); // Stop the current timer
|
||||
shouldFetch = false; // Stop further fetches
|
||||
@@ -1227,10 +1248,11 @@ class MapPassengerController extends GetxController {
|
||||
confirmRideForAllDriverAvailable();
|
||||
isDriversTokensSend = true;
|
||||
} // Start 15-second timer
|
||||
} else if (isDriversTokensSend == false) {
|
||||
// No need to recall delayAndFetchRideStatus as Timer.periodic is already running
|
||||
update();
|
||||
}
|
||||
//else if (isDriversTokensSend == false) {
|
||||
// No need to recall delayAndFetchRideStatus as Timer.periodic is already running
|
||||
update();
|
||||
// }
|
||||
tick++;
|
||||
} else {
|
||||
timer
|
||||
@@ -1242,13 +1264,26 @@ class MapPassengerController extends GetxController {
|
||||
});
|
||||
}
|
||||
|
||||
void delayAndFetchRideStatusForAllDriverAvailable(String rideId) {
|
||||
showAndResearchForCaptain() {
|
||||
Get.snackbar(
|
||||
"No Captain Accepted Your Order".tr,
|
||||
"We are looking for a captain but the price may increase to let a captain accept"
|
||||
.tr,
|
||||
backgroundColor: AppColor.bronze,
|
||||
);
|
||||
}
|
||||
|
||||
void delayAndFetchRideStatusForAllDriverAvailable(String rideId) async {
|
||||
startCarLocationSearch(box.read(BoxName.carType));
|
||||
int attemptCounter = 0;
|
||||
const int maxAttempts = 15;
|
||||
tick = 0;
|
||||
Log.print('tick delayAndFetchRideStatusForAllDriverAvailable: ${tick}');
|
||||
|
||||
void fetchRideStatus() async {
|
||||
if (shouldFetch && attemptCounter < maxAttempts) {
|
||||
attemptCounter++;
|
||||
tick++;
|
||||
var res = await getRideStatus(rideId);
|
||||
|
||||
if (res.toString() == 'Apply') {
|
||||
@@ -1270,6 +1305,79 @@ class MapPassengerController extends GetxController {
|
||||
MyDialog().getDialog('upgrade price'.tr,
|
||||
'You can upgrade price to may driver accept your order'.tr, () {
|
||||
Get.back();
|
||||
Get.defaultDialog(
|
||||
barrierDismissible: false,
|
||||
title: "Increase Your Trip Fee (Optional)".tr,
|
||||
titleStyle: AppStyle.title,
|
||||
content: Column(
|
||||
children: [
|
||||
Text(
|
||||
"We haven't found any drivers yet. Consider increasing your trip fee to make your offer more attractive to drivers."
|
||||
.tr,
|
||||
style: AppStyle.title,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
increasFeeFromPassenger.text =
|
||||
(totalPassenger + 6).toStringAsFixed(1);
|
||||
// mapPassengerController.increasFeeFromPassenger.text =
|
||||
// mapPassengerController.totalPassenger
|
||||
// .toStringAsFixed(1);
|
||||
update();
|
||||
},
|
||||
icon: Column(
|
||||
children: [
|
||||
Text(
|
||||
'6',
|
||||
style: AppStyle.number,
|
||||
),
|
||||
Container(
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: AppColor.greenColor),
|
||||
child: const Icon(
|
||||
Icons.arrow_circle_up,
|
||||
size: 30,
|
||||
color: AppColor.secondaryColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 100,
|
||||
child: Form(
|
||||
key: increaseFeeFormKey,
|
||||
child: MyTextForm(
|
||||
controller: increasFeeFromPassenger,
|
||||
label: totalPassenger.toStringAsFixed(2),
|
||||
hint: totalPassenger.toStringAsFixed(2),
|
||||
type: TextInputType.number),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
MyElevatedButton(
|
||||
title: "No, thanks",
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
cancelRide();
|
||||
}),
|
||||
MyElevatedButton(
|
||||
title: "Increase Fee".tr,
|
||||
kolor: AppColor.greenColor,
|
||||
onPressed: () {
|
||||
increaseFeeByPassengerAndReOrder();
|
||||
})
|
||||
],
|
||||
);
|
||||
});
|
||||
update();
|
||||
print('Stopped fetching ride status after 30 seconds.');
|
||||
@@ -1470,27 +1578,48 @@ class MapPassengerController extends GetxController {
|
||||
|
||||
void startCarLocationSearch(String carType) {
|
||||
int searchInterval = 5; // Interval in seconds
|
||||
int boundIncreaseStep = 4500; // Initial bounds in meters
|
||||
int maxAttempts = 3; // Maximum attempts to increase bounds
|
||||
Log.print('searchInterval: ${searchInterval}');
|
||||
int boundIncreaseStep = 2500; // Initial bounds in meters
|
||||
Log.print('boundIncreaseStep: ${boundIncreaseStep}');
|
||||
int maxAttempts = 6; // Maximum attempts to increase bounds
|
||||
int maxBoundIncreaseStep = 6000; // Maximum bounds increase step
|
||||
int attempt = 0; // Current attempt
|
||||
Log.print('initial attempt: ${attempt}');
|
||||
|
||||
Timer.periodic(Duration(seconds: searchInterval), (Timer timer) async {
|
||||
Log.print('Current attempt: ${attempt}'); // Log current attempt
|
||||
bool foundCars = false;
|
||||
if (attempt >= maxAttempts) {
|
||||
timer.cancel();
|
||||
noCarString = true;
|
||||
dataCarsLocationByPassenger = 'failure';
|
||||
update();
|
||||
if (foundCars == false) {
|
||||
noCarString = true;
|
||||
dataCarsLocationByPassenger = 'failure';
|
||||
update();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool foundCars = await getCarsLocationByPassengerAndReloadMarker(
|
||||
carType, boundIncreaseStep);
|
||||
|
||||
if (foundCars) {
|
||||
timer.cancel();
|
||||
} else {
|
||||
attempt++;
|
||||
boundIncreaseStep = boundIncreaseStep + 1500; // Increase bounds
|
||||
foundCars = await getCarsLocationByPassengerAndReloadMarker(
|
||||
carType, boundIncreaseStep);
|
||||
Log.print('foundCars: ${foundCars}');
|
||||
|
||||
if (foundCars) {
|
||||
timer.cancel();
|
||||
} else {
|
||||
attempt++;
|
||||
Log.print(
|
||||
'Incrementing attempt to: ${attempt}'); // Log incremented attempt
|
||||
|
||||
if (boundIncreaseStep < maxBoundIncreaseStep) {
|
||||
boundIncreaseStep += 1500; // Increase bounds
|
||||
if (boundIncreaseStep > maxBoundIncreaseStep) {
|
||||
boundIncreaseStep =
|
||||
maxBoundIncreaseStep; // Ensure it does not exceed the maximum
|
||||
}
|
||||
Log.print(
|
||||
'New boundIncreaseStep: ${boundIncreaseStep}'); // Log new bounds
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1551,9 +1680,6 @@ class MapPassengerController extends GetxController {
|
||||
}
|
||||
|
||||
if (res == 'failure') {
|
||||
// noCarString = true;
|
||||
// dataCarsLocationByPassenger = res;
|
||||
// update();
|
||||
return false;
|
||||
} else {
|
||||
noCarString = false;
|
||||
@@ -1580,6 +1706,10 @@ class MapPassengerController extends GetxController {
|
||||
|
||||
driversToken.add(json['token']);
|
||||
}
|
||||
|
||||
// Add fake car markers
|
||||
_addFakeCarMarkers(passengerLocation, 2);
|
||||
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
@@ -1587,6 +1717,49 @@ class MapPassengerController extends GetxController {
|
||||
return false;
|
||||
}
|
||||
|
||||
final List<Map<String, dynamic>> fakeCarData = [];
|
||||
|
||||
void _addFakeCarMarkers(LatLng center, int count) {
|
||||
if (fakeCarData.isEmpty) {
|
||||
Random random = Random();
|
||||
double radiusInKm = 1.5; // 3 km diameter, so 1.5 km radius
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
// Generate a random angle and distance within the circle
|
||||
double angle = random.nextDouble() * 2 * pi;
|
||||
double distance = sqrt(random.nextDouble()) * radiusInKm;
|
||||
|
||||
// Convert distance to latitude and longitude offsets
|
||||
double latOffset = (distance / 111.32); // 1 degree lat ≈ 111.32 km
|
||||
double lonOffset =
|
||||
(distance / (111.32 * cos(radians(center.latitude))));
|
||||
|
||||
// Calculate new position
|
||||
double lat = center.latitude + (latOffset * cos(angle));
|
||||
double lon = center.longitude + (lonOffset * sin(angle));
|
||||
|
||||
double heading = random.nextDouble() * 360;
|
||||
|
||||
fakeCarData.add({
|
||||
'id': 'fake_$i',
|
||||
'latitude': lat,
|
||||
'longitude': lon,
|
||||
'heading': heading,
|
||||
'gender': 'Male', // Randomize gender
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (var carData in fakeCarData) {
|
||||
_updateOrCreateMarker(
|
||||
MarkerId(carData['id']).toString(),
|
||||
LatLng(carData['latitude'], carData['longitude']),
|
||||
carData['heading'],
|
||||
_getIconForCar(carData),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BitmapDescriptor _getIconForCar(Map<String, dynamic> carData) {
|
||||
if (carData['model'].toString().contains('دراجة')) {
|
||||
return motoIcon;
|
||||
@@ -1976,26 +2149,7 @@ class MapPassengerController extends GetxController {
|
||||
'cancel.wav',
|
||||
);
|
||||
}
|
||||
// rideConfirm = false;
|
||||
// shouldFetch = false;
|
||||
// isCashConfirmPageShown = false;
|
||||
// isSearchingWindow = false;
|
||||
// statusRide = 'Cancel';
|
||||
// isPassengerChosen = false;
|
||||
// isCashSelectedBeforeConfirmRide = false;
|
||||
// isPickerShown = false;
|
||||
// isMarkersShown = false;
|
||||
// haveSteps = false;
|
||||
// isMarkersShown = false;
|
||||
// driverToken = '';
|
||||
// driverId = '';
|
||||
// driverPhone = '';
|
||||
// driverName = '';
|
||||
// // totalStepDurations = 0;
|
||||
// timeToPassengerFromDriverAfterApplied = 0;
|
||||
// remainingTime = 0;
|
||||
// isWayPointStopsSheetUtilGetMap = false;
|
||||
// update();
|
||||
|
||||
Get.offAll(const MapPagePassenger());
|
||||
} else {
|
||||
clearPlacesDestination();
|
||||
@@ -2005,28 +2159,11 @@ class MapPassengerController extends GetxController {
|
||||
"order_id": rideId.toString(), // Convert to String
|
||||
"status": 'Cancel'
|
||||
});
|
||||
await CRUD().post(link: AppLink.updateRides, payload: {
|
||||
"id": rideId.toString(), // Convert to String
|
||||
"status": 'Cancel'
|
||||
});
|
||||
Get.offAll(const MapPagePassenger());
|
||||
// isPickerShown = false;
|
||||
// isWayPointStopsSheetUtilGetMap = false;
|
||||
// rideConfirm = false;
|
||||
// shouldFetch = false;
|
||||
// driverToken = '';
|
||||
// driverId = '';
|
||||
// driverPhone = '';
|
||||
// driverName = '';
|
||||
// isCashConfirmPageShown = false;
|
||||
// isSearchingWindow = false;
|
||||
// isPassengerChosen = false;
|
||||
// isCashSelectedBeforeConfirmRide = false;
|
||||
// statusRide = 'Cancel';
|
||||
// haveSteps = false;
|
||||
// isMarkersShown = false;
|
||||
// timeToPassengerFromDriverAfterApplied = 0;
|
||||
// changeCancelRidePageShow();
|
||||
// clearPolyline();
|
||||
// remainingTime = 0;
|
||||
// durationTimer = 0;
|
||||
// update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2430,31 +2567,28 @@ class MapPassengerController extends GetxController {
|
||||
startMarkerReloading() async {
|
||||
int reloadCount = 0;
|
||||
|
||||
Timer.periodic(const Duration(seconds: 5), (timer) {
|
||||
Timer.periodic(const Duration(seconds: 5), (timer) async {
|
||||
reloadCount++;
|
||||
Log.print('reloadCount: ${reloadCount}');
|
||||
|
||||
if (!rideConfirm) {
|
||||
reloadMarkers();
|
||||
clearMarkersExceptStartEnd();
|
||||
// _smoothlyUpdateMarker();
|
||||
// startCarLocationSearch(box.read(BoxName.carType));
|
||||
await getCarsLocationByPassengerAndReloadMarker(
|
||||
box.read(BoxName.carType), 6000);
|
||||
await getNearestDriverByPassengerLocation();
|
||||
Log.print('reloadMarkers: from startMarkerReloadin');
|
||||
} else {
|
||||
// runWhenRideIsBegin();
|
||||
}
|
||||
|
||||
if (reloadCount >= 35) {
|
||||
if (reloadCount >= 10) {
|
||||
timer.cancel(); // Stop the timer after 5 reloads
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reloadMarkers() async {
|
||||
// if (statusRide == 'wait') {
|
||||
clearMarkersExceptStartEnd();
|
||||
// _smoothlyUpdateMarker();
|
||||
startCarLocationSearch(box.read(BoxName.carType));
|
||||
// await getCarsLocationByPassengerAndReloadMarker();
|
||||
await getNearestDriverByPassengerLocation();
|
||||
// }
|
||||
}
|
||||
|
||||
String durationByPassenger = '';
|
||||
late DateTime newTime1 = DateTime.now();
|
||||
late DateTime timeFromDriverToPassenger = DateTime.now();
|
||||
@@ -3349,6 +3483,15 @@ class MapPassengerController extends GetxController {
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
uploadPassengerLocation() async {
|
||||
await CRUD().post(link: AppLink.addpassengerLocation, payload: {
|
||||
"passengerId": box.read(BoxName.passengerID),
|
||||
"lat": passengerLocation.latitude,
|
||||
"lng": passengerLocation.longitude,
|
||||
"rideId": rideId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class CarLocation {
|
||||
|
||||
@@ -49,9 +49,15 @@ class MyTranslation extends Translations {
|
||||
"We will look for a new driver.\nPlease wait.":
|
||||
"سنبحث عن سائق جديد.\nمن فضلك انتظر.",
|
||||
"upgrade price": "رفع السعر",
|
||||
'airport': 'مطار',
|
||||
"Best choice for a comfortable car with a flexible route and stop points. This airport offers visa entry at this price.":
|
||||
"أفضل اختيار لسيارة مريحة مع طريق ونقاط توقف مرنة. يقدم هذا المطار تأشيرة دخول بهذا السعر.",
|
||||
"You can upgrade price to may driver accept your order":
|
||||
"يمكنك رفع السعر حتى يقبل السائق طلبك",
|
||||
|
||||
"Change Route": "تغيير المسار",
|
||||
"No Captain Accepted Your Order": "لا يوجد كابتن قبل الطلب الخاص بك",
|
||||
"We are looking for a captain but the price may increase to let a captain accept":
|
||||
"نحن نبحث عن كابتن ولكن قد يرتفع السعر للسماح لكابتن بقبول الطلب",
|
||||
"No, I want to cancel this trip": "لا، أريد إلغاء هذه الرحلة",
|
||||
'Trip Cancelled. The cost of the trip will be added to your wallet.':
|
||||
"تم إلغاء الرحلة. سيتم إضافة تكلفة الرحلة إلى محفظتك.",
|
||||
@@ -154,6 +160,8 @@ iOS [https://getapp.cc/app/6458734951]
|
||||
'The driver waiting you in picked location .':
|
||||
"السائق ينتظرك في موقع الركوب.",
|
||||
'About Us': "نبذة عنا",
|
||||
"You can change the vibration feedback for all buttons":
|
||||
"يمكنك تغيير اهتزاز الرج لجميع الأزرار",
|
||||
"Most Secure Methods": "أساليب الأمان الأكثر فاعلية",
|
||||
"In-App VOIP Calls": "مكالمات VOIP داخل التطبيق",
|
||||
"Recorded Trips for Safety": "تسجيل الرحلات من أجل السلامة",
|
||||
|
||||
Reference in New Issue
Block a user