Fixes & Updates - 2026-06-01: Integrate Back-End v3 updates, fix call/connection issues across apps

This commit is contained in:
Hamza-Ayed
2026-06-01 23:36:27 +03:00
parent 118781fd66
commit 97945aa362
76 changed files with 19806 additions and 10822 deletions

View File

@@ -3,8 +3,13 @@ import 'package:get/get.dart';
import '../../constant/box_name.dart';
import '../../constant/colors.dart';
import '../../controller/functions/crud.dart';
import '../../controller/functions/package_info.dart';
import '../../controller/home/map_passenger_controller.dart';
import '../../controller/home/map/map_socket_controller.dart';
import '../../controller/home/map/map_engine_controller.dart';
import '../../controller/home/map/location_search_controller.dart';
import '../../controller/home/map/nearby_drivers_controller.dart';
import '../../controller/home/map/ride_lifecycle_controller.dart';
import '../../controller/home/map/ui_interactions_controller.dart';
import '../../controller/home/map/ride_state.dart';
import '../../main.dart';
import '../../views/home/map_widget.dart/ride_begin_passenger.dart';
@@ -17,7 +22,7 @@ import 'map_widget.dart/google_map_passenger_widget.dart';
import 'map_widget.dart/left_main_menu_icons.dart';
import 'map_widget.dart/main_bottom_menu_map.dart';
import 'map_widget.dart/map_menu_widget.dart';
import 'map_widget.dart/menu_map_page.dart';
import '../../controller/functions/package_info.dart';
import 'map_widget.dart/passengerRideLoctionWidget.dart';
import 'map_widget.dart/payment_method.page.dart';
import 'map_widget.dart/points_page_for_rider.dart';
@@ -30,9 +35,14 @@ class MapPagePassenger extends StatelessWidget {
@override
Widget build(BuildContext context) {
Get.put(MapPassengerController());
Get.put(MyMenuController());
Get.put(CRUD());
Get.find<MapSocketController>();
Get.find<MapEngineController>();
Get.find<LocationSearchController>();
Get.find<NearbyDriversController>();
Get.find<RideLifecycleController>();
Get.find<UiInteractionsController>();
Get.find<MyMenuController>();
Get.find<CRUD>();
WidgetsBinding.instance.addPostFrameCallback((_) {
checkForUpdate(context);
});
@@ -118,7 +128,7 @@ class CancelRidePageShow extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(
return GetBuilder<RideLifecycleController>(
builder: (controller) {
// نستخدم RideState Enum لأنه أدق، أو نصلح المنطق النصي
// الشرط:
@@ -175,7 +185,7 @@ class PickerIconOnMap extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(
return GetBuilder<RideLifecycleController>(
builder: (controller) => controller.isPickerShown
? Positioned(
bottom: Get.height * .2,

View File

@@ -1,7 +1,9 @@
import 'package:Intaleq/constant/colors.dart';
import 'package:Intaleq/constant/links.dart';
import 'package:Intaleq/constant/style.dart';
import 'package:Intaleq/controller/home/map_passenger_controller.dart';
import 'package:Intaleq/controller/home/map/ride_lifecycle_controller.dart';
import 'package:Intaleq/controller/home/map/ride_state.dart';
import 'package:Intaleq/controller/voice_call_controller.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
@@ -10,6 +12,7 @@ import 'package:intl/intl.dart';
import '../../../constant/box_name.dart';
import '../../../controller/firebase/notification_service.dart';
import '../../../controller/functions/launch.dart';
import '../../../controller/functions/crud.dart';
import '../../../main.dart';
class ApplyOrderWidget extends StatelessWidget {
@@ -29,7 +32,7 @@ class ApplyOrderWidget extends StatelessWidget {
}
return Obx(() {
final controller = Get.find<MapPassengerController>();
final controller = Get.find<RideLifecycleController>();
final bool isVisible =
controller.currentRideState.value == RideState.driverApplied ||
@@ -57,7 +60,7 @@ class ApplyOrderWidget extends StatelessWidget {
),
// تغيير: تقليل الحواف الخارجية بشكل كبير
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
child: GetBuilder<MapPassengerController>(
child: GetBuilder<RideLifecycleController>(
builder: (c) {
return Column(
mainAxisSize:
@@ -106,15 +109,18 @@ class ApplyOrderWidget extends StatelessWidget {
// [NEW] 1. صف الرأس المضغوط (يحتوي الحالة + الإحصائيات + السعر)
// ---------------------------------------------------------------------------
Widget _buildCompactHeaderRow(
BuildContext context, MapPassengerController controller) {
BuildContext context, RideLifecycleController controller) {
// تنسيق السعر
final formatter = NumberFormat("#,###");
String formattedPrice = formatter.format(controller.totalPassenger);
// حساب الدقائق
int minutes =
(controller.timeToPassengerFromDriverAfterApplied / 60).ceil();
if (minutes < 1) minutes = 1;
// حساب الدقائق من الوقت المتبقي الحي، وليس ETA الأصلي فقط.
final int secondsToPassenger =
controller.remainingTimeToPassengerFromDriverAfterApplied > 0
? controller.remainingTimeToPassengerFromDriverAfterApplied
: controller.timeToPassengerFromDriverAfterApplied;
final int minutes =
secondsToPassenger <= 0 ? 0 : (secondsToPassenger / 60).ceil();
// تنسيق المسافة
String distanceDisplay = "";
@@ -151,7 +157,7 @@ class ApplyOrderWidget extends StatelessWidget {
children: [
_buildMiniStatChip(
icon: Icons.access_time_filled_rounded,
text: "$minutes ${'min'.tr}",
text: minutes > 0 ? "$minutes ${'min'.tr}" : "--",
color: AppColor.primaryColor,
bgColor: AppColor.primaryColor.withOpacity(0.1),
),
@@ -229,7 +235,7 @@ class ApplyOrderWidget extends StatelessWidget {
// [MODIFIED] 2. كرت المعلومات المضغوط جداً
// ---------------------------------------------------------------------------
Widget _buildCompactInfoCard(BuildContext context,
MapPassengerController controller, Color Function(String) parseColor) {
RideLifecycleController controller, Color Function(String) parseColor) {
return Container(
// تقليل الحواف الداخلية للكرت
padding: const EdgeInsets.all(10),
@@ -312,7 +318,7 @@ class ApplyOrderWidget extends StatelessWidget {
}
Widget _buildMicroCarIcon(
MapPassengerController controller, Color Function(String) parseColor) {
RideLifecycleController controller, Color Function(String) parseColor) {
Color carColor = parseColor(controller.colorHex);
return Container(
height: 40, // تصغير من 50
@@ -343,9 +349,8 @@ class ApplyOrderWidget extends StatelessWidget {
color: Get.isDarkMode ? Colors.grey[850] : const Color(0xFFF5F5F5),
borderRadius: BorderRadius.circular(6),
border: Border.all(
color: Get.isDarkMode
? Colors.white10
: Colors.grey.withOpacity(0.3)),
color:
Get.isDarkMode ? Colors.white10 : Colors.grey.withOpacity(0.3)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -374,7 +379,7 @@ class ApplyOrderWidget extends StatelessWidget {
// [MODIFIED] 3. أزرار الاتصال (Slim Buttons)
// ---------------------------------------------------------------------------
Widget _buildCompactButtonsRow(
BuildContext context, MapPassengerController controller) {
BuildContext context, RideLifecycleController controller) {
return SizedBox(
height: 40, // تحديد ارتفاع ثابت وصغير للأزرار
child: Row(
@@ -397,7 +402,7 @@ class ApplyOrderWidget extends StatelessWidget {
bgColor: AppColor.greenColor,
onTap: () {
HapticFeedback.heavyImpact();
makePhoneCall(controller.driverPhone);
_showCallSelectionDialog(context, controller);
},
isPrimary: true,
),
@@ -407,6 +412,73 @@ class ApplyOrderWidget extends StatelessWidget {
);
}
void _showCallSelectionDialog(
BuildContext context, RideLifecycleController controller) {
Get.dialog(
Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Call Options'.tr,
style: AppStyle.title
.copyWith(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
Text(
'Choose how you want to call the driver'.tr,
style: const TextStyle(color: Colors.grey, fontSize: 14),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
ListTile(
leading: CircleAvatar(
backgroundColor: AppColor.greenColor.withOpacity(0.1),
child: Icon(Icons.phone_android_rounded,
color: AppColor.greenColor),
),
title: Text('Standard Call'.tr,
style: const TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text('Uses cellular network'.tr,
style: const TextStyle(fontSize: 12)),
onTap: () {
Get.back();
makePhoneCall(controller.driverPhone);
},
),
const Divider(),
ListTile(
leading: CircleAvatar(
backgroundColor: AppColor.primaryColor.withOpacity(0.1),
child: Icon(Icons.wifi_calling_3_rounded,
color: AppColor.primaryColor),
),
title: Text('Free Call'.tr,
style: const TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text('Voice call over internet'.tr,
style: const TextStyle(fontSize: 12)),
onTap: () {
Get.back();
final voiceCtrl = Get.find<VoiceCallController>();
final passengerId = box.read(BoxName.passengerID).toString();
voiceCtrl.startCall(
rideIdVal: controller.rideId,
driverId: controller.driverId,
passengerId: passengerId,
remoteNameVal: controller.driverName,
);
},
),
],
),
),
),
);
}
Widget _buildSlimButton({
required String label,
required IconData icon,
@@ -444,7 +516,7 @@ class ApplyOrderWidget extends StatelessWidget {
// --- النوافذ المنبثقة للرسائل (نفس الكود السابق مع تحسين بسيط) ---
void _showContactOptionsDialog(
BuildContext context, MapPassengerController controller) {
BuildContext context, RideLifecycleController controller) {
Get.bottomSheet(
Container(
padding: const EdgeInsets.all(20),
@@ -470,7 +542,7 @@ class ApplyOrderWidget extends StatelessWidget {
);
}
List<Widget> _buildPredefinedMessages(MapPassengerController controller) {
List<Widget> _buildPredefinedMessages(RideLifecycleController controller) {
const messages = [
'Hello, I\'m at the agreed-upon location',
'I\'m waiting for you',
@@ -510,7 +582,7 @@ class ApplyOrderWidget extends StatelessWidget {
}
Widget _buildCustomMessageInput(
MapPassengerController controller, BuildContext context) {
RideLifecycleController controller, BuildContext context) {
return Row(
children: [
Expanded(
@@ -555,7 +627,22 @@ class ApplyOrderWidget extends StatelessWidget {
);
}
void _sendMessage(MapPassengerController controller, String text) {
void _sendMessage(RideLifecycleController controller, String text) async {
try {
await CRUD().post(
link: AppLink.sendChatMessage,
payload: {
'ride_id': controller.rideId.toString(),
'sender_id': box.read(BoxName.passengerID).toString(),
'receiver_id': controller.driverId.toString(),
'sender_type': 'passenger',
'message_content': text.tr,
},
);
} catch (e) {
// Ignore or log error
}
NotificationService.sendNotification(
category: 'MSG_FROM_PASSENGER',
target: controller.driverToken.toString(),
@@ -577,7 +664,7 @@ class DriverArrivePassengerAndWaitMinute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(builder: (controller) {
return GetBuilder<RideLifecycleController>(builder: (controller) {
return Column(
children: [
Row(
@@ -619,7 +706,7 @@ class TimeDriverToPassenger extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(builder: (controller) {
return GetBuilder<RideLifecycleController>(builder: (controller) {
if (controller.timeToPassengerFromDriverAfterApplied <= 0) {
return const SizedBox();
}

View File

@@ -3,11 +3,11 @@ import 'package:get/get.dart';
import 'package:Intaleq/controller/payment/payment_controller.dart';
import '../../../constant/style.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
GetBuilder<MapPassengerController> buttomSheetMapPage() {
GetBuilder<RideLifecycleController> buttomSheetMapPage() {
Get.put(PaymentController());
return GetBuilder<MapPassengerController>(
return GetBuilder<RideLifecycleController>(
builder: (controller) =>
controller.isBottomSheetShown && controller.rideConfirm == false
? const Positioned(
@@ -508,7 +508,7 @@ class Details extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(
return GetBuilder<RideLifecycleController>(
builder: (controller) => Column(
children: [
Row(

View File

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:Intaleq/constant/colors.dart';
import 'package:Intaleq/constant/style.dart';
import 'package:Intaleq/controller/home/map_passenger_controller.dart';
import 'package:Intaleq/controller/home/map/ride_lifecycle_controller.dart';
import '../../widgets/elevated_btn.dart';
// دالة لإظهار الشيت
@@ -21,7 +21,7 @@ class CancelRidePageWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// تأكد من وجود الكنترولر
final controller = Get.find<MapPassengerController>();
final controller = Get.find<RideLifecycleController>();
final List<String> reasons = [
"Changed my mind".tr,
@@ -39,7 +39,7 @@ class CancelRidePageWidget extends StatelessWidget {
color: AppColor.secondaryColor,
borderRadius: const BorderRadius.vertical(top: Radius.circular(25)),
),
child: GetBuilder<MapPassengerController>(
child: GetBuilder<RideLifecycleController>(
builder: (controller) => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [

View File

@@ -12,7 +12,7 @@ import 'dart:ui';
import '../../../constant/info.dart';
import '../../../controller/functions/tts.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import '../../widgets/mydialoug.dart';
// ─────────────────────────────────────────────────────────────────────────────
@@ -62,7 +62,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
CarDetailsTypeToChoose({super.key});
final textToSpeechController = Get.find<TextToSpeechController>();
void _prepareCarTypes(MapPassengerController controller) {
void _prepareCarTypes(RideLifecycleController controller) {
if (controller.distance > 23) {
if (!carTypes.any((car) => car.carType == 'Rayeh Gai')) {
carTypes.add(CarType(
@@ -77,7 +77,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(builder: (controller) {
return GetBuilder<RideLifecycleController>(builder: (controller) {
_prepareCarTypes(controller);
if (!(controller.isBottomSheetShown) && controller.rideConfirm == false) {
@@ -170,7 +170,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
// ═══════════════════════════════════════════════════════════════════════════
// HEADER
// ═══════════════════════════════════════════════════════════════════════════
Widget _buildHeader(MapPassengerController controller) {
Widget _buildHeader(RideLifecycleController controller) {
return Padding(
padding: const EdgeInsets.fromLTRB(22, 4, 22, 8),
child: Column(
@@ -290,7 +290,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
// ═══════════════════════════════════════════════════════════════════════════
// CAR CARD
// ═══════════════════════════════════════════════════════════════════════════
Widget _buildCarCard(BuildContext context, MapPassengerController controller,
Widget _buildCarCard(BuildContext context, RideLifecycleController controller,
CarType carType, bool isSelected, int index) {
return GestureDetector(
onTap: () {
@@ -437,7 +437,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
// PROMO BUTTON
// ═══════════════════════════════════════════════════════════════════════════
Widget _buildPromoButton(
BuildContext context, MapPassengerController controller) {
BuildContext context, RideLifecycleController controller) {
if (controller.promoTaken) return const SizedBox.shrink();
return Padding(
@@ -511,7 +511,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
// ═══════════════════════════════════════════════════════════════════════════
// NEGATIVE BALANCE WARNING
// ═══════════════════════════════════════════════════════════════════════════
Widget _buildNegativeBalanceWarning(MapPassengerController controller) {
Widget _buildNegativeBalanceWarning(RideLifecycleController controller) {
final passengerWallet =
double.tryParse(box.read(BoxName.passengerWalletTotal) ?? '0.0') ?? 0.0;
if (passengerWallet < 0.0) {
@@ -556,7 +556,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
// PRICING HELPERS (Unchanged logic)
// ═══════════════════════════════════════════════════════════════════════════
String _getPassengerPriceText(
CarType carType, MapPassengerController mapPassengerController) {
CarType carType, RideLifecycleController mapPassengerController) {
double rawPrice;
switch (carType.carType) {
case 'Comfort':
@@ -596,7 +596,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
// DIALOGS
// ═══════════════════════════════════════════════════════════════════════════
void _showPromoCodeDialog(
BuildContext context, MapPassengerController controller) {
BuildContext context, RideLifecycleController controller) {
Get.dialog(
Dialog(
shape:
@@ -671,7 +671,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
void _showCarDetailsDialog(
BuildContext context,
MapPassengerController mapPassengerController,
RideLifecycleController mapPassengerController,
CarType carType,
TextToSpeechController textToSpeechController) {
Get.dialog(
@@ -843,7 +843,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
// LOGIC HELPERS (Unchanged)
// ═══════════════════════════════════════════════════════════════════════════
String _getCarDescription(
MapPassengerController mapPassengerController, CarType carType) {
RideLifecycleController mapPassengerController, CarType carType) {
switch (carType.carType) {
case 'Comfort':
return mapPassengerController.endNameAddress
@@ -881,7 +881,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
}
void _handleCarSelection(BuildContext context,
MapPassengerController mapPassengerController, CarType carType) {
RideLifecycleController mapPassengerController, CarType carType) {
box.write(BoxName.carType, carType.carType);
mapPassengerController.totalPassenger =
_getOriginalPrice(carType, mapPassengerController);
@@ -932,7 +932,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
}
double _getOriginalPrice(
CarType carType, MapPassengerController mapPassengerController) {
CarType carType, RideLifecycleController mapPassengerController) {
switch (carType.carType) {
case 'Comfort':
return mapPassengerController.totalPassengerComfort;
@@ -953,7 +953,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
Widget _buildRayehGaiOption(
BuildContext context,
MapPassengerController mapPassengerController,
RideLifecycleController mapPassengerController,
String carTypeName,
double price) {
return GestureDetector(
@@ -983,7 +983,7 @@ class BurcMoney extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(
return GetBuilder<RideLifecycleController>(
builder: (mapPassengerController) {
final passengerWallet =
double.tryParse(box.read(BoxName.passengerWalletTotal) ?? '0.0') ??

View File

@@ -6,7 +6,7 @@ import 'package:Intaleq/views/home/my_wallet/passenger_wallet.dart';
import '../../../constant/colors.dart';
import '../../../constant/info.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import '../../../controller/payment/payment_controller.dart';
import '../../../main.dart';
import '../../widgets/elevated_btn.dart';
@@ -17,7 +17,7 @@ class CashConfirmPageShown extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(builder: (controller) {
return GetBuilder<RideLifecycleController>(builder: (controller) {
// شرط الإظهار الرئيسي لم يتغير
return Positioned(
bottom: 0,

View File

@@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../constant/style.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import 'hexegone_clipper.dart';
GetBuilder<MapPassengerController> hexagonClipper() {
return GetBuilder<MapPassengerController>(
GetBuilder<RideLifecycleController> hexagonClipper() {
return GetBuilder<RideLifecycleController>(
builder: ((controller) => controller.rideConfirm
? Positioned(
top: Get.height * .1,

View File

@@ -4,14 +4,14 @@ import 'package:intl/intl.dart';
// import 'package:intl/intl.dart';
import '../../../constant/style.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
class DriverTimeArrivePassengerPage extends StatelessWidget {
const DriverTimeArrivePassengerPage({super.key});
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(
return GetBuilder<RideLifecycleController>(
builder: (controller) {
return controller.remainingTime == 0
? Positioned(

View File

@@ -12,54 +12,51 @@ import 'package:Intaleq/views/widgets/elevated_btn.dart';
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
import '../../../controller/functions/toast.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/location_search_controller.dart';
import '../../../controller/home/map/map_engine_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import '../../../controller/home/map/ride_state.dart';
import '../../../main.dart';
// ---------------------------------------------------
// -- Widget for Destination Point Search (Optimized) --
// ---------------------------------------------------
/// A more optimized and cleaner implementation of the destination search form.
///
/// Improvements:
/// 1. **Widget Refactoring**: The UI is broken down into smaller, focused widgets
/// (_SearchField, _QuickActions, _SearchResults) to prevent unnecessary rebuilds.
/// 2. **State Management Scoping**: `GetBuilder` is used only on widgets that
/// actually need to update, not the entire form.
/// 3. **Reduced Build Logic**: Logic like reading from `box` is done once.
/// 4. **Readability**: Code is cleaner and easier to follow.
GetBuilder<MapPassengerController> formSearchPlacesDestenation() {
// --- [تحسين] قراءة القيم مرة واحدة في بداية البناء ---
// Store box values in local variables to avoid repeated calls inside the build method.
GetBuilder<LocationSearchController> formSearchPlacesDestenation() {
final String addWorkValue =
box.read(BoxName.addWork)?.toString() ?? 'addWork';
final String addHomeValue =
box.read(BoxName.addHome)?.toString() ?? 'addHome';
// --- [ملاحظة] تأكد من أن القيم الأولية موجودة ---
// This initialization can be moved to your app's startup logic or a splash screen controller.
if (addWorkValue.isEmpty || addHomeValue.isEmpty) {
box.write(BoxName.addWork, 'addWork');
box.write(BoxName.addHome, 'addHome');
}
return GetBuilder<MapPassengerController>(
id: 'destination_form', // Use an ID to allow targeted updates
return GetBuilder<LocationSearchController>(
id: 'destination_form',
builder: (controller) {
final mapEngine = Get.find<MapEngineController>();
final rideLifecycle = Get.find<RideLifecycleController>();
return Column(
children: [
// --- Widget for the search text field ---
_SearchField(controller: controller),
// --- Widget for "Add Work" and "Add Home" buttons ---
_SearchField(
controller: controller,
mapEngine: mapEngine,
rideLifecycle: rideLifecycle,
),
_QuickActions(
controller: controller,
mapEngine: mapEngine,
rideLifecycle: rideLifecycle,
addWorkValue: addWorkValue,
addHomeValue: addHomeValue,
),
// --- Widget for displaying search results, wrapped in its own GetBuilder ---
_SearchResults(),
_SearchResults(
controller: controller,
mapEngine: mapEngine,
rideLifecycle: rideLifecycle,
),
],
);
},
@@ -70,11 +67,16 @@ GetBuilder<MapPassengerController> formSearchPlacesDestenation() {
// -- Private Helper Widgets for Cleaner Code --
// ---------------------------------------------------
/// A dedicated widget for the search input field.
class _SearchField extends StatefulWidget {
final MapPassengerController controller;
final LocationSearchController controller;
final MapEngineController mapEngine;
final RideLifecycleController rideLifecycle;
const _SearchField({required this.controller});
const _SearchField({
required this.controller,
required this.mapEngine,
required this.rideLifecycle,
});
@override
State<_SearchField> createState() => _SearchFieldState();
@@ -83,7 +85,6 @@ class _SearchField extends StatefulWidget {
class _SearchFieldState extends State<_SearchField> {
Timer? _debounce;
// --- [إصلاح] Listener لتحديث الواجهة عند تغيير النص لإظهار/إخفاء زر المسح ---
void _onTextChanged() {
if (mounted) {
setState(() {});
@@ -93,20 +94,18 @@ class _SearchFieldState extends State<_SearchField> {
@override
void initState() {
super.initState();
// Add listener to update the suffix icon when text changes
widget.controller.placeDestinationController.addListener(_onTextChanged);
}
// --- [تحسين] إضافة Debouncer لتأخير البحث أثناء الكتابة ---
void _onSearchChanged(String query) {
if (_debounce?.isActive ?? false) _debounce!.cancel();
_debounce = Timer(const Duration(milliseconds: 500), () {
if (query.length > 2) {
widget.controller.getPlaces();
widget.controller.changeHeightPlaces();
widget.mapEngine.changeHeightPlaces();
} else if (query.isEmpty) {
widget.controller.clearPlacesDestination();
widget.controller.changeHeightPlaces();
widget.mapEngine.changeHeightPlaces();
}
});
}
@@ -114,7 +113,6 @@ class _SearchFieldState extends State<_SearchField> {
@override
void dispose() {
_debounce?.cancel();
// Remove the listener to prevent memory leaks
widget.controller.placeDestinationController.removeListener(_onTextChanged);
super.dispose();
}
@@ -133,18 +131,15 @@ class _SearchFieldState extends State<_SearchField> {
hintText: widget.controller.hintTextDestinationPoint,
hintStyle: AppStyle.subtitle.copyWith(color: Colors.grey[600]),
prefixIcon: Icon(Icons.search, color: AppColor.primaryColor),
// --- [إصلاح] تم استبدال Obx بشرط بسيط لأن `setState` يعيد بناء الواجهة الآن ---
suffixIcon: widget
.controller.placeDestinationController.text.isNotEmpty
? IconButton(
icon: Icon(Icons.clear, color: Colors.grey[400]),
onPressed: () {
widget.controller.placeDestinationController.clear();
// The listener will automatically handle the UI update
// And _onSearchChanged will handle clearing the results
},
)
: null, // Use null instead of SizedBox for better practice
: null,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 10.0),
border: OutlineInputBorder(
@@ -163,12 +158,12 @@ class _SearchFieldState extends State<_SearchField> {
const SizedBox(width: 8.0),
IconButton(
onPressed: () {
widget.controller.changeMainBottomMenuMap();
widget.controller.changePickerShown();
widget.mapEngine.changeMainBottomMenuMap();
widget.mapEngine.changePickerShown();
},
icon: Icon(Icons.location_on_outlined,
color: AppColor.accentColor, size: 30),
tooltip: widget.controller.isAnotherOreder
tooltip: widget.rideLifecycle.isAnotherOreder
? 'Pick destination on map'.tr
: 'Pick on map'.tr,
),
@@ -178,14 +173,17 @@ class _SearchFieldState extends State<_SearchField> {
}
}
/// A dedicated widget for the quick action buttons (Work/Home).
class _QuickActions extends StatelessWidget {
final MapPassengerController controller;
final LocationSearchController controller;
final MapEngineController mapEngine;
final RideLifecycleController rideLifecycle;
final String addWorkValue;
final String addHomeValue;
const _QuickActions({
required this.controller,
required this.mapEngine,
required this.rideLifecycle,
required this.addWorkValue,
required this.addHomeValue,
});
@@ -203,13 +201,20 @@ class _QuickActions extends StatelessWidget {
onTap: () {
if (addWorkValue == 'addWork') {
controller.workLocationFromMap = true;
controller.changeMainBottomMenuMap();
controller.changePickerShown();
mapEngine.changeMainBottomMenuMap();
mapEngine.changePickerShown();
} else {
_handleQuickAction(controller, BoxName.addWork, 'To Work');
_handleQuickAction(
controller,
mapEngine,
rideLifecycle,
BoxName.addWork,
'To Work',
);
}
},
onLongPress: () => _showChangeLocationDialog(controller, 'Work'),
onLongPress: () =>
_showChangeLocationDialog(controller, mapEngine, 'Work'),
),
_buildQuickActionButton(
icon: Icons.home_outlined,
@@ -217,13 +222,20 @@ class _QuickActions extends StatelessWidget {
onTap: () {
if (addHomeValue == 'addHome') {
controller.homeLocationFromMap = true;
controller.changeMainBottomMenuMap();
controller.changePickerShown();
mapEngine.changeMainBottomMenuMap();
mapEngine.changePickerShown();
} else {
_handleQuickAction(controller, BoxName.addHome, 'To Home');
_handleQuickAction(
controller,
mapEngine,
rideLifecycle,
BoxName.addHome,
'To Home',
);
}
},
onLongPress: () => _showChangeLocationDialog(controller, 'Home'),
onLongPress: () =>
_showChangeLocationDialog(controller, mapEngine, 'Home'),
),
],
),
@@ -231,17 +243,25 @@ class _QuickActions extends StatelessWidget {
}
}
/// A dedicated widget for the search results list.
/// It uses its own `GetBuilder` to only rebuild when the list of places changes.
class _SearchResults extends StatelessWidget {
final LocationSearchController controller;
final MapEngineController mapEngine;
final RideLifecycleController rideLifecycle;
const _SearchResults({
required this.controller,
required this.mapEngine,
required this.rideLifecycle,
});
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(
id: 'places_list', // Use a specific ID for targeted updates
builder: (controller) {
return GetBuilder<LocationSearchController>(
id: 'places_list',
builder: (locCtrl) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
height: controller.placesDestination.isNotEmpty ? 300 : 0,
height: locCtrl.placesDestination.isNotEmpty ? 300 : 0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.0),
@@ -250,11 +270,11 @@ class _SearchResults extends StatelessWidget {
child: ListView.separated(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
itemCount: controller.placesDestination.length,
itemCount: locCtrl.placesDestination.length,
separatorBuilder: (context, index) =>
const Divider(height: 1, color: Colors.grey),
itemBuilder: (BuildContext context, int index) {
final res = controller.placesDestination[index];
final res = locCtrl.placesDestination[index];
final title = res['name_ar'] ?? res['name'] ?? 'Unknown Place';
final address = res['address'] ?? 'Details not available';
final latitude = res['latitude'];
@@ -277,7 +297,14 @@ class _SearchResults extends StatelessWidget {
context, latitude, longitude, title),
),
onTap: () => _handlePlaceSelection(
controller, latitude, longitude, title, index),
controller,
mapEngine,
rideLifecycle,
latitude,
longitude,
title,
index,
),
);
},
),
@@ -286,7 +313,6 @@ class _SearchResults extends StatelessWidget {
);
}
// --- [تحسين] استخراج المنطق المعقد إلى دوال مساعدة ---
Future<void> _handleAddToFavorites(BuildContext context, dynamic latitude,
dynamic longitude, String title) async {
if (latitude != null && longitude != null) {
@@ -311,14 +337,19 @@ class _SearchResults extends StatelessWidget {
}
}
Future<void> _handlePlaceSelection(MapPassengerController controller,
dynamic latitude, dynamic longitude, String title, int index) async {
Future<void> _handlePlaceSelection(
LocationSearchController controller,
MapEngineController mapEngine,
RideLifecycleController rideLifecycle,
dynamic latitude,
dynamic longitude,
String title,
int index) async {
if (latitude == null || longitude == null) {
Toast.show(Get.context!, 'Invalid location data', AppColor.redColor);
return;
}
// Save to recent locations
await sql.insertMapLocation({
'latitude': latitude,
'longitude': longitude,
@@ -330,53 +361,55 @@ class _SearchResults extends StatelessWidget {
final destLatLng = LatLng(
double.parse(latitude.toString()), double.parse(longitude.toString()));
if (controller.isAnotherOreder) {
// **Another Order Flow**
await _handleAnotherOrderSelection(controller, destLatLng);
if (rideLifecycle.isAnotherOreder) {
await _handleAnotherOrderSelection(
controller, mapEngine, rideLifecycle, destLatLng);
} else {
// **Regular Order Flow**
_handleRegularOrderSelection(controller, destLatLng, index);
_handleRegularOrderSelection(
controller, mapEngine, rideLifecycle, destLatLng, index);
}
}
Future<void> _handleAnotherOrderSelection(
MapPassengerController controller, LatLng destination) async {
LocationSearchController controller,
MapEngineController mapEngine,
RideLifecycleController rideLifecycle,
LatLng destination) async {
controller.myDestination = destination;
controller.clearPlacesDestination(); // Helper method in controller
controller.clearPlacesDestination();
await controller.getDirectionMap(
await rideLifecycle.getDirectionMap(
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
'${controller.myDestination.latitude},${controller.myDestination.longitude}');
controller.isPickerShown = false;
mapEngine.isPickerShown = false;
controller.passengerStartLocationFromMap = false;
controller.changeMainBottomMenuMap();
controller.showBottomSheet1();
mapEngine.changeMainBottomMenuMap();
rideLifecycle.showBottomSheet1();
}
void _handleRegularOrderSelection(
MapPassengerController controller, LatLng destination, int index) {
LocationSearchController controller,
MapEngineController mapEngine,
RideLifecycleController rideLifecycle,
LatLng destination,
int index) {
controller.passengerLocation = controller.newMyLocation;
controller.myDestination = destination;
controller.convertHintTextDestinationNewPlaces(index);
controller.clearPlacesDestination(); // Helper method in controller
controller.clearPlacesDestination();
controller.changeMainBottomMenuMap();
mapEngine.changeMainBottomMenuMap();
controller.passengerStartLocationFromMap = true;
controller.isPickerShown = true;
mapEngine.isPickerShown = true;
// ✅ FIX: Draw the route after setting destination (matching the "Another Order" flow)
controller.getDirectionMap(
rideLifecycle.getDirectionMap(
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
'${controller.myDestination.latitude},${controller.myDestination.longitude}');
}
}
// ---------------------------------------------------
// -- Helper Functions (kept from original code) --
// ---------------------------------------------------
Widget _buildQuickActionButton({
required IconData icon,
required String text,
@@ -410,10 +443,12 @@ Widget _buildQuickActionButton({
);
}
void _showChangeLocationDialog(
MapPassengerController controller, String locationType) {
void _showChangeLocationDialog(LocationSearchController controller,
MapEngineController mapEngine, String locationType) {
MyDialog().getDialog(
locationType == 'Work' ? 'Change Work location ?'.tr : 'Change Home location ?'.tr,
locationType == 'Work'
? 'Change Work location ?'.tr
: 'Change Home location ?'.tr,
'',
() {
if (locationType == 'Work') {
@@ -421,15 +456,18 @@ void _showChangeLocationDialog(
} else {
controller.homeLocationFromMap = true;
}
controller.changeMainBottomMenuMap();
controller.changePickerShown();
mapEngine.changeMainBottomMenuMap();
mapEngine.changePickerShown();
},
);
}
void _handleQuickAction(
MapPassengerController controller, String boxName, String hintText) async {
// --- [تحسين] قراءة وتحويل الإحداثيات بأمان أكبر ---
LocationSearchController controller,
MapEngineController mapEngine,
RideLifecycleController rideLifecycle,
String boxName,
String hintText) async {
try {
final locationString = box.read(boxName).toString();
final parts = locationString.split(',');
@@ -439,20 +477,19 @@ void _handleQuickAction(
);
controller.hintTextDestinationPoint = hintText;
controller.changeMainBottomMenuMap();
mapEngine.changeMainBottomMenuMap();
await controller.getDirectionMap(
await rideLifecycle.getDirectionMap(
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
'${latLng.latitude},${latLng.longitude}',
);
controller.currentLocationToFormPlaces = false;
controller.clearPlacesDestination(); // Helper method in controller
controller.clearPlacesDestination();
controller.passengerStartLocationFromMap = false;
controller.isPickerShown = false;
controller.showBottomSheet1();
mapEngine.isPickerShown = false;
rideLifecycle.showBottomSheet1();
} catch (e) {
// Handle error if parsing fails
Log.print("Error handling quick action: $e");
Toast.show(Get.context!, "Failed to get location".tr, AppColor.redColor);
}

View File

@@ -4,135 +4,122 @@ import 'package:intaleq_maps/intaleq_maps.dart';
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/location_search_controller.dart';
import '../../../controller/home/map/map_engine_controller.dart';
// ---------------------------------------------------
// -- Widget for Start Point Search (Updated) --
// ---------------------------------------------------
GetBuilder<MapPassengerController> formSearchPlacesStart() {
return GetBuilder<MapPassengerController>(
id: 'start_point_form', // إضافة معرف لتحديث هذا الجزء فقط عند الحاجة
builder: (controller) => Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Row(
children: [
// --- حقل البحث النصي ---
Expanded(
child: TextFormField(
controller: controller.placeStartController,
onChanged: (value) {
if (controller.placeStartController.text.length > 2) {
controller.getPlacesStart();
} else if (controller.placeStartController.text.isEmpty) {
controller.clearPlacesStart();
}
},
decoration: InputDecoration(
hintText: 'Search for a starting point'.tr,
hintStyle:
AppStyle.subtitle.copyWith(color: Colors.grey[600]),
prefixIcon:
Icon(Icons.search, color: AppColor.primaryColor),
suffixIcon: controller.placeStartController.text.isNotEmpty
? IconButton(
icon: Icon(Icons.clear, color: Colors.grey[400]),
onPressed: () {
controller.placeStartController.clear();
controller.clearPlacesStart();
},
)
: null,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide.none,
GetBuilder<LocationSearchController> formSearchPlacesStart() {
return GetBuilder<LocationSearchController>(
id: 'start_point_form',
builder: (controller) {
final mapEngine = Get.find<MapEngineController>();
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Row(
children: [
Expanded(
child: TextFormField(
controller: controller.placeStartController,
onChanged: (value) {
if (controller.placeStartController.text.length > 2) {
controller.getPlacesStart();
} else if (controller.placeStartController.text.isEmpty) {
controller.clearPlacesStart();
}
},
decoration: InputDecoration(
hintText: 'Search for a starting point'.tr,
hintStyle:
AppStyle.subtitle.copyWith(color: Colors.grey[600]),
prefixIcon:
Icon(Icons.search, color: AppColor.primaryColor),
suffixIcon: controller.placeStartController.text.isNotEmpty
? IconButton(
icon: Icon(Icons.clear, color: Colors.grey[400]),
onPressed: () {
controller.placeStartController.clear();
controller.clearPlacesStart();
},
)
: null,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide(color: AppColor.primaryColor),
),
filled: true,
fillColor: Colors.grey[50],
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide(color: AppColor.primaryColor),
),
filled: true,
fillColor: Colors.grey[50],
),
),
),
const SizedBox(width: 8.0),
// --- أيقونة اختيار الموقع من الخريطة (الجزء المضاف) ---
IconButton(
onPressed: () {
// هذا السطر مهم جداً: نخبر الكونترولر أننا نحدد نقطة البداية الآن
controller.passengerStartLocationFromMap = true;
// إخفاء القائمة السفلية وفتح مؤشر الخريطة (Picker)
controller.changeMainBottomMenuMap();
controller.changePickerShown();
},
icon: Icon(Icons.location_on_outlined,
color: AppColor.accentColor, size: 30),
tooltip: 'Pick start point on map'.tr,
),
],
const SizedBox(width: 8.0),
IconButton(
onPressed: () {
controller.passengerStartLocationFromMap = true;
mapEngine.changeMainBottomMenuMap();
mapEngine.changePickerShown();
},
icon: Icon(Icons.location_on_outlined,
color: AppColor.accentColor, size: 30),
tooltip: 'Pick start point on map'.tr,
),
],
),
),
),
AnimatedContainer(
duration: const Duration(milliseconds: 200),
height: controller.placesStart.isNotEmpty ? 300 : 0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.0),
),
margin: const EdgeInsets.symmetric(horizontal: 16.0),
child: ListView.separated(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
itemCount: controller.placesStart.length,
separatorBuilder: (context, index) =>
const Divider(height: 1, color: Colors.grey),
itemBuilder: (BuildContext context, int index) {
var res = controller.placesStart[index];
var title = res['name_ar'] ?? res['name'] ?? 'Unknown Place';
var address = res['address'] ?? 'Details not available';
// --- قائمة نتائج البحث ---
AnimatedContainer(
duration: const Duration(milliseconds: 200),
height: controller.placesStart.isNotEmpty ? 300 : 0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.0),
return ListTile(
leading: const Icon(Icons.place, size: 30, color: Colors.grey),
title: Text(title,
style: AppStyle.subtitle
.copyWith(fontWeight: FontWeight.w500)),
subtitle: Text(address,
style: TextStyle(color: Colors.grey[600], fontSize: 12)),
onTap: () {
var latitude = res['latitude'];
var longitude = res['longitude'];
if (latitude != null && longitude != null) {
controller.passengerLocation =
LatLng(double.parse(latitude), double.parse(longitude));
controller.placeStartController.text = title;
controller.clearPlacesStart();
mapEngine.changeMainBottomMenuMap();
controller.update();
}
},
);
},
),
),
margin: const EdgeInsets.symmetric(horizontal: 16.0),
child: ListView.separated(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
itemCount: controller.placesStart.length,
separatorBuilder: (context, index) =>
const Divider(height: 1, color: Colors.grey),
itemBuilder: (BuildContext context, int index) {
var res = controller.placesStart[index];
var title = res['name_ar'] ?? res['name'] ?? 'Unknown Place';
var address = res['address'] ?? 'Details not available';
return ListTile(
leading: const Icon(Icons.place, size: 30, color: Colors.grey),
title: Text(title,
style: AppStyle.subtitle
.copyWith(fontWeight: FontWeight.w500)),
subtitle: Text(address,
style: TextStyle(color: Colors.grey[600], fontSize: 12)),
onTap: () {
var latitude = res['latitude'];
var longitude = res['longitude'];
if (latitude != null && longitude != null) {
// تحديث موقع الراكب (نقطة الانطلاق) بناءً على الاختيار
controller.passengerLocation =
LatLng(double.parse(latitude), double.parse(longitude));
// تحديث النص في الحقل
controller.placeStartController.text = title;
// مسح النتائج
controller.clearPlacesStart();
// إغلاق القائمة والعودة للخريطة لرؤية النتيجة (اختياري حسب منطق تطبيقك)
controller.changeMainBottomMenuMap();
controller.update();
}
},
);
},
),
),
],
),
],
);
},
);
}

View File

@@ -6,183 +6,181 @@ import 'package:intaleq_maps/intaleq_maps.dart';
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
import '../../../controller/functions/toast.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/location_search_controller.dart';
import '../../../controller/home/map/map_engine_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import '../../../main.dart';
GetBuilder<MapPassengerController> formSearchPlaces(int index) {
// DbSql sql = DbSql.instance;
return GetBuilder<MapPassengerController>(
builder: (controller) => Column(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Container(
decoration: BoxDecoration(color: AppColor.secondaryColor),
child: TextField(
decoration: InputDecoration(
border: const OutlineInputBorder(
borderRadius: BorderRadius.only(),
gapPadding: 4,
borderSide: BorderSide(
color: AppColor.redColor,
width: 2,
)),
suffixIcon: const Icon(Icons.search),
hintText: controller.hintTextwayPoint0.tr,
hintStyle: AppStyle.title,
hintMaxLines: 1,
prefixIcon: IconButton(
onPressed: () {
controller.allTextEditingPlaces[index].clear();
controller.clearPlaces(index);
},
icon: Icon(
Icons.clear,
color: Colors.red[300],
),
),
),
controller: controller.allTextEditingPlaces[index],
onChanged: (value) {
if (controller.allTextEditingPlaces[index].text.length >
5) {
controller.getPlacesListsWayPoint(index);
controller.changeHeightPlacesAll(index);
}
GetBuilder<LocationSearchController> formSearchPlaces(int index) {
return GetBuilder<LocationSearchController>(
builder: (controller) {
final mapEngine = Get.find<MapEngineController>();
final rideLifecycle = Get.find<RideLifecycleController>();
return Column(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Container(
decoration: BoxDecoration(color: AppColor.secondaryColor),
child: TextField(
decoration: InputDecoration(
border: const OutlineInputBorder(
borderRadius: BorderRadius.only(),
gapPadding: 4,
borderSide: BorderSide(
color: AppColor.redColor,
width: 2,
)),
suffixIcon: const Icon(Icons.search),
hintText: controller.hintTextwayPoint0.tr,
hintStyle: AppStyle.title,
hintMaxLines: 1,
prefixIcon: IconButton(
onPressed: () {
controller.allTextEditingPlaces[index].clear();
controller.clearPlaces(index);
},
// onEditingComplete: () => controller.changeHeight(),
icon: Icon(
Icons.clear,
color: Colors.red[300],
),
),
),
controller: controller.allTextEditingPlaces[index],
onChanged: (value) {
if (controller.allTextEditingPlaces[index].text.length > 5) {
controller.getPlacesListsWayPoint(index);
mapEngine.changeHeightPlacesAll(index);
}
},
),
controller.placeListResponseAll[index].isEmpty
? InkWell(
onTap: () {
controller.startLocationFromMapAll[index] = true;
controller.wayPointIndex = index;
Get.back();
// controller.changeMainBottomMenuMap();
controller.changeWayPointStopsSheet();
controller.changePickerShown();
},
child: Text(
'Choose from Map'.tr + ' $index'.tr,
style:
AppStyle.title.copyWith(color: AppColor.blueColor),
),
)
: const SizedBox(),
Container(
height: controller.placeListResponseAll[index].isNotEmpty
? controller.height
: 0,
color: AppColor.secondaryColor,
child: ListView.builder(
itemCount: controller.placeListResponseAll[index].length,
itemBuilder: (BuildContext context, int i) {
var res = controller.placeListResponseAll[index][i];
return InkWell(
onTap: () async {
// ── Extract selected location ──
final double lat = res['geometry']['location']['lat'];
final double lng = res['geometry']['location']['lng'];
final String placeName = res['name'].toString();
final selectedLatLng = LatLng(lat, lng);
),
),
controller.placeListResponseAll[index].isEmpty
? InkWell(
onTap: () {
controller.startLocationFromMapAll[index] = true;
controller.wayPointIndex = index;
Get.back();
mapEngine.changeWayPointStopsSheet();
mapEngine.changePickerShown();
},
child: Text(
'Choose from Map'.tr + ' $index'.tr,
style:
AppStyle.title.copyWith(color: AppColor.blueColor),
),
)
: const SizedBox(),
Container(
height: controller.placeListResponseAll[index].isNotEmpty
? mapEngine.height
: 0,
color: AppColor.secondaryColor,
child: ListView.builder(
itemCount: controller.placeListResponseAll[index].length,
itemBuilder: (BuildContext context, int i) {
var res = controller.placeListResponseAll[index][i];
return InkWell(
onTap: () async {
final double lat = res['geometry']['location']['lat'];
final double lng = res['geometry']['location']['lng'];
final String placeName = res['name'].toString();
final selectedLatLng = LatLng(lat, lng);
controller.changeHeightPlaces();
mapEngine.changeHeightPlaces();
// ── Update start/end based on context ──
if (controller.currentLocationToFormPlacesAll[index] ==
true) {
controller.newStartPointLocation =
controller.passengerLocation;
} else {
controller.passengerLocation =
controller.newStartPointLocation;
}
if (controller.currentLocationToFormPlacesAll[index] ==
true) {
controller.newStartPointLocation =
rideLifecycle.passengerLocation;
} else {
rideLifecycle.passengerLocation =
controller.newStartPointLocation;
}
// ✅ FIX: Set the waypoint to the selected location
controller.menuWaypoints[index] = selectedLatLng;
controller.menuWaypointNames[index] = placeName;
controller.menuWaypoints[index] = selectedLatLng;
controller.menuWaypointNames[index] = placeName;
// ✅ FIX: Update hint text and coordinates
controller.convertHintTextPlaces(index, res);
controller.convertHintTextPlaces(index, res);
// ✅ FIX: Draw the route with the updated waypoint
final String start =
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}';
final String dest =
'${controller.myDestination.latitude},${controller.myDestination.longitude}';
final String start =
'${rideLifecycle.passengerLocation.latitude},${rideLifecycle.passengerLocation.longitude}';
final String dest =
'${rideLifecycle.myDestination.latitude},${rideLifecycle.myDestination.longitude}';
await controller.getDirectionMap(start, dest);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Column(
await rideLifecycle.getDirectionMap(start, dest);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
Column(
children: [
Column(
children: [
Image.network(
res['icon'],
width: 20,
),
IconButton(
onPressed: () async {
await sql.insertMapLocation({
'latitude': res['geometry']
['location']['lat'],
'longitude': res['geometry']
['location']['lng'],
'name': res['name'].toString(),
'rate': res['rating'].toString(),
}, TableName.placesFavorite);
Toast.show(
context,
'${res['name']} ${'Saved Sucssefully'.tr}',
AppColor.primaryColor);
},
icon: const Icon(Icons.favorite_border),
),
],
Image.network(
res['icon'],
width: 20,
),
Column(
children: [
Text(
res['name'].toString(),
style: AppStyle.title,
),
Text(
res['vicinity'].toString(),
style: AppStyle.subtitle,
),
],
),
Column(
children: [
Text(
'rate',
style: AppStyle.subtitle,
),
Text(
res['rating'].toString(),
style: AppStyle.subtitle,
),
],
IconButton(
onPressed: () async {
await sql.insertMapLocation({
'latitude': res['geometry']
['location']['lat'],
'longitude': res['geometry']
['location']['lng'],
'name': res['name'].toString(),
'rate': res['rating'].toString(),
}, TableName.placesFavorite);
Toast.show(
context,
'${res['name']} ${'Saved Sucssefully'.tr}',
AppColor.primaryColor);
},
icon: const Icon(Icons.favorite_border),
),
],
),
Column(
children: [
Text(
res['name'].toString(),
style: AppStyle.title,
),
Text(
res['vicinity'].toString(),
style: AppStyle.subtitle,
),
],
),
Column(
children: [
Text(
'rate',
style: AppStyle.subtitle,
),
Text(
res['rating'].toString(),
style: AppStyle.subtitle,
),
],
),
const Divider(
thickness: 1,
)
],
),
),
);
},
),
)
],
));
const Divider(
thickness: 1,
)
],
),
),
);
},
),
)
],
);
},
);
}

View File

@@ -6,19 +6,26 @@ import 'package:intaleq_maps/intaleq_maps.dart';
import 'package:Intaleq/controller/home/points_for_rider_controller.dart';
import 'package:Intaleq/services/offline_map_service.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/location_search_controller.dart';
import '../../../controller/home/map/map_engine_controller.dart';
import '../../../controller/home/map/nearby_drivers_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import '../../widgets/mycircular.dart';
import '../../widgets/mydialoug.dart';
class GoogleMapPassengerWidget extends StatelessWidget {
GoogleMapPassengerWidget({super.key});
final WayPointController wayPointController = Get.put(WayPointController());
final WayPointController wayPointController = Get.find<WayPointController>();
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(
builder: (controller) => controller.isLoading
final locationSearch = Get.find<LocationSearchController>();
final rideLifecycle = Get.find<RideLifecycleController>();
final nearbyDrivers = Get.find<NearbyDriversController>();
return GetBuilder<MapEngineController>(
builder: (controller) => rideLifecycle.isLoading
? const MyCircularProgressIndicator()
: Positioned(
bottom: Get.height * .2,
@@ -32,13 +39,13 @@ class GoogleMapPassengerWidget extends StatelessWidget {
: 'assets/style.json',
onMapCreated: controller.onMapCreated,
onStyleLoaded: controller.onStyleLoaded,
onCameraMove: controller.onCameraMoveThrottled,
onCameraMove: locationSearch.onCameraMoveThrottled,
onCameraIdle: () {
if (controller.mapController != null) {
final position = controller.mapController!.cameraPosition;
if (position != null) {
Log.print('✅ onCameraIdle targeted: ${position.target}');
controller
locationSearch
.updateCurrentLocationFromCamera(position.target);
OfflineMapService.instance
.downloadRegion(position.target, radiusKm: 1.0);
@@ -54,8 +61,8 @@ class GoogleMapPassengerWidget extends StatelessWidget {
polygons: controller.polygons,
circles: controller.circles,
initialCameraPosition: CameraPosition(
target: controller.passengerLocation,
zoom: controller.lowPerf ? 14.5 : 15,
target: locationSearch.passengerLocation,
zoom: nearbyDrivers.lowPerf ? 14.5 : 15,
),
myLocationEnabled: true,
onTap: (latlng) => controller.hidePlaces(),
@@ -63,11 +70,11 @@ class GoogleMapPassengerWidget extends StatelessWidget {
MyDialog().getDialog('Are you want to go to this site'.tr, '',
() async {
controller.clearPolyline();
controller.getDirectionMap(
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
rideLifecycle.getDirectionMap(
'${locationSearch.passengerLocation.latitude},${locationSearch.passengerLocation.longitude}',
'${latlng.latitude},${latlng.longitude}',
);
controller.showBottomSheet1();
rideLifecycle.showBottomSheet1();
});
},
),

View File

@@ -1,95 +1,82 @@
import 'dart:math';
import 'package:Intaleq/views/widgets/elevated_btn.dart';
import 'package:Intaleq/views/widgets/error_snakbar.dart';
import 'package:Intaleq/views/widgets/mycircular.dart';
import 'package:flutter/material.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'dart:ui'; // مهم لإضافة تأثير الضبابية
import 'dart:ui';
import '../../../constant/colors.dart';
import '../../../controller/functions/tts.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/location_search_controller.dart';
import '../../../controller/home/map/map_engine_controller.dart';
import '../../../controller/home/vip_waitting_page.dart';
import '../navigation/navigation_view.dart';
// --- الدالة الرئيسية بالتصميم الجديد ---
GetBuilder<MapPassengerController> leftMainMenuIcons() {
return GetBuilder<MapPassengerController>(
builder: (controller) => Positioned(
// تم تعديل الموضع ليتناسب مع التصميم الجديد
top: Get.height * .01,
left: 0,
right: 0,
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(50.0), // لإنشاء شكل الكبسولة
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 8.0, sigmaY: 8.0), // تأثير الزجاج المصنفر
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: AppColor.secondaryColor.withOpacity(0.4), // لون شبه شفاف
borderRadius: BorderRadius.circular(50.0),
border: Border.all(color: AppColor.secondaryColor),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min, // ليأخذ الشريط حجم الأزرار فقط
children: [
// --- تم استخدام دالة مساعدة جديدة للزر ---
_buildMapActionButton(
icon: Icons.near_me_outlined,
tooltip: 'Toggle Map Type',
onPressed: () => Get.to(() => NavigationView()),
),
// _buildVerticalDivider(),
// _buildMapActionButton(
// icon: Icons.traffic_outlined,
// tooltip: 'Toggle Traffic',
// onPressed: () => controller.changeMapTraffic(),
// ),
_buildVerticalDivider(),
_buildMapActionButton(
icon: Icons.my_location_rounded,
tooltip: 'Go to My Location',
onPressed: () {
controller.mapController?.animateCamera(
CameraUpdate.newLatLng(
LatLng(
controller.passengerLocation.latitude,
controller.passengerLocation.longitude,
GetBuilder<MapEngineController> leftMainMenuIcons() {
return GetBuilder<MapEngineController>(
builder: (controller) {
final locationSearch = Get.find<LocationSearchController>();
return Positioned(
top: Get.height * .01,
left: 0,
right: 0,
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(50.0),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0),
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: AppColor.secondaryColor.withValues(alpha: 0.4),
borderRadius: BorderRadius.circular(50.0),
border: Border.all(color: AppColor.secondaryColor),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
_buildMapActionButton(
icon: Icons.near_me_outlined,
tooltip: 'Toggle Map Type',
onPressed: () => Get.to(() => NavigationView()),
),
_buildVerticalDivider(),
_buildMapActionButton(
icon: Icons.my_location_rounded,
tooltip: 'Go to My Location',
onPressed: () {
controller.mapController?.animateCamera(
CameraUpdate.newLatLng(
LatLng(
locationSearch.passengerLocation.latitude,
locationSearch.passengerLocation.longitude,
),
),
),
);
},
),
_buildVerticalDivider(),
_buildMapActionButton(
icon: Octicons.watch,
tooltip: 'VIP Waiting Page',
onPressed: () => Get.to(() => VipWaittingPage()),
),
// _buildMapActionButton(
// icon: Octicons.ellipsis,
// tooltip: 'test',
// onPressed: () => Get.to(() => TestPage()),
// ),
],
);
},
),
_buildVerticalDivider(),
_buildMapActionButton(
icon: Octicons.watch,
tooltip: 'VIP Waiting Page',
onPressed: () => Get.to(() => VipWaittingPage()),
),
],
),
),
),
),
),
),
),
);
},
);
}
// --- دالة مساعدة جديدة لإنشاء الأزرار بشكل أنيق ---
Widget _buildMapActionButton({
required IconData icon,
required String tooltip,
@@ -101,28 +88,23 @@ Widget _buildMapActionButton({
tooltip: tooltip,
splashRadius: 22,
padding: const EdgeInsets.all(12),
constraints: const BoxConstraints(), // لإزالة المساحات الافتراضية
constraints: const BoxConstraints(),
);
}
// --- ويدجت للفاصل الرأسي بين الأزرار ---
Widget _buildVerticalDivider() {
return Container(
height: 20,
width: 1,
color: AppColor.writeColor.withOpacity(0.2),
color: AppColor.writeColor.withValues(alpha: 0.2),
);
}
// --- باقي الكود الخاص بك يبقى كما هو بدون تغيير ---
class TestPage extends StatelessWidget {
const TestPage({super.key});
@override
Widget build(BuildContext context) {
final random = Random();
return Scaffold(
appBar: AppBar(
title: const Text('iOS Live Activity Test'),
@@ -137,7 +119,6 @@ class TestPage extends StatelessWidget {
title: 'title',
onPressed: () {},
),
// زر الإنهاء
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,7 @@ import 'package:url_launcher/url_launcher.dart';
import '../../../constant/colors.dart';
import '../../../constant/links.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/map_engine_controller.dart';
import '../../notification/notification_page.dart';
import '../HomePage/contact_us.dart';
import '../HomePage/share_app_page.dart';
@@ -28,9 +28,8 @@ Color get _kBg =>
Get.isDarkMode ? const Color(0xFF060B18) : AppColor.secondaryColor;
Color get _kBgSurface => Get.isDarkMode
? const Color(0xFF0D1525)
: AppColor.secondaryColor.withOpacity(0.9);
: AppColor.secondaryColor.withValues(alpha: 0.9);
const _kAmber = Color(0xFFFFB700);
Color get _kBorder => _kCyan.withOpacity(0.15);
Color get _kText => AppColor.writeColor;
Color get _kTextMuted => AppColor.grayColor;
@@ -39,16 +38,14 @@ class MapMenuWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
Get.lazyPut(() => MapPassengerController());
return GetBuilder<MapPassengerController>(
return GetBuilder<MapEngineController>(
builder: (controller) => Stack(
children: [
// ── تعتيم الخلفية ───────────────────────────────────────────────
if (controller.widthMenu > 0)
GestureDetector(
onTap: controller.getDrawerMenu,
child: Container(color: Colors.black.withOpacity(0.55)),
child: Container(color: Colors.black.withValues(alpha: 0.55)),
),
_buildSideMenu(controller),
@@ -59,7 +56,7 @@ class MapMenuWidget extends StatelessWidget {
}
// ── زر القائمة العائم ────────────────────────────────────────────────────
Widget _buildMenuButton(MapPassengerController controller) {
Widget _buildMenuButton(MapEngineController controller) {
return Positioned(
top: 45,
left: 16,
@@ -76,12 +73,12 @@ class MapMenuWidget extends StatelessWidget {
width: 48,
height: 48,
decoration: BoxDecoration(
color: _kBg.withOpacity(0.88),
color: _kBg.withValues(alpha: 0.88),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: _kCyan.withOpacity(0.25), width: 1),
border: Border.all(color: _kCyan.withValues(alpha: 0.25), width: 1),
boxShadow: [
BoxShadow(
color: _kCyan.withOpacity(0.12),
color: _kCyan.withValues(alpha: 0.12),
blurRadius: 16,
),
],
@@ -106,7 +103,7 @@ class MapMenuWidget extends StatelessWidget {
}
// ── القائمة الجانبية ─────────────────────────────────────────────────────
Widget _buildSideMenu(MapPassengerController controller) {
Widget _buildSideMenu(MapEngineController controller) {
return AnimatedPositioned(
duration: const Duration(milliseconds: 420),
curve: Curves.fastOutSlowIn,
@@ -120,13 +117,13 @@ class MapMenuWidget extends StatelessWidget {
width: Get.width * 0.8,
constraints: const BoxConstraints(maxWidth: 320),
decoration: BoxDecoration(
color: _kBg.withOpacity(0.97),
color: _kBg.withValues(alpha: 0.97),
border: Border(
right: BorderSide(color: _kCyan.withOpacity(0.12), width: 1),
right: BorderSide(color: _kCyan.withValues(alpha: 0.12), width: 1),
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.5),
color: Colors.black.withValues(alpha: 0.5),
blurRadius: 32,
),
],
@@ -239,7 +236,7 @@ class MapMenuWidget extends StatelessWidget {
decoration: BoxDecoration(
color: _kBgSurface,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: _kCyan.withOpacity(0.15), width: 1),
border: Border.all(color: _kCyan.withValues(alpha: 0.15), width: 1),
),
child: Row(
children: [
@@ -255,12 +252,12 @@ class MapMenuWidget extends StatelessWidget {
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
_kCyan.withOpacity(0.2),
_kAmber.withOpacity(0.12),
_kCyan.withValues(alpha: 0.2),
_kAmber.withValues(alpha: 0.12),
],
),
border:
Border.all(color: _kCyan.withOpacity(0.35), width: 1.5),
Border.all(color: _kCyan.withValues(alpha: 0.35), width: 1.5),
),
child: Icon(Icons.person_rounded, color: _kCyan, size: 28),
),
@@ -277,7 +274,7 @@ class MapMenuWidget extends StatelessWidget {
border: Border.all(color: _kBg, width: 2),
boxShadow: [
BoxShadow(
color: const Color(0xFF00E676).withOpacity(0.5),
color: const Color(0xFF00E676).withValues(alpha: 0.5),
blurRadius: 6,
),
],
@@ -365,7 +362,7 @@ class MapMenuWidget extends StatelessWidget {
gradient: LinearGradient(
colors: [
Colors.transparent,
_kCyan.withOpacity(0.15),
_kCyan.withValues(alpha: 0.15),
Colors.transparent,
],
),
@@ -419,7 +416,7 @@ class _QuickBtn extends StatelessWidget {
decoration: BoxDecoration(
color: _kBgSurface,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: _kCyan.withOpacity(0.12), width: 1),
border: Border.all(color: _kCyan.withValues(alpha: 0.12), width: 1),
),
child: Column(
mainAxisSize: MainAxisSize.min,
@@ -463,7 +460,7 @@ class MenuListItem extends StatelessWidget {
Widget build(BuildContext context) {
final iconColor = isDestructive
? const Color(0xFFFF5252)
: (color ?? _kCyan.withOpacity(0.80));
: (color ?? _kCyan.withValues(alpha: 0.80));
final textColor =
isDestructive ? const Color(0xFFFF5252) : (color ?? _kText);
@@ -472,8 +469,8 @@ class MenuListItem extends StatelessWidget {
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
splashColor: _kCyan.withOpacity(0.07),
highlightColor: _kCyan.withOpacity(0.04),
splashColor: _kCyan.withValues(alpha: 0.07),
highlightColor: _kCyan.withValues(alpha: 0.04),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
child: Row(
@@ -484,8 +481,8 @@ class MenuListItem extends StatelessWidget {
height: 36,
decoration: BoxDecoration(
color: isDestructive
? const Color(0xFFFF5252).withOpacity(0.08)
: _kCyan.withOpacity(0.07),
? const Color(0xFFFF5252).withValues(alpha: 0.08)
: _kCyan.withValues(alpha: 0.07),
borderRadius: BorderRadius.circular(10),
),
child: Icon(icon, size: 19, color: iconColor),
@@ -504,7 +501,7 @@ class MenuListItem extends StatelessWidget {
),
Icon(
Icons.chevron_right_rounded,
color: _kTextMuted.withOpacity(0.4),
color: _kTextMuted.withValues(alpha: 0.4),
size: 18,
),
],
@@ -520,7 +517,7 @@ class _MenuGridPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = AppColor.cyanBlue.withOpacity(0.04)
..color = AppColor.cyanBlue.withValues(alpha: 0.04)
..strokeWidth = 0.5;
const spacing = 36.0;
for (double y = 0; y < size.height; y += spacing) {

View File

@@ -3,7 +3,7 @@ import 'package:get/get.dart';
import '../../../constant/box_name.dart';
import '../../../constant/colors.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/map_engine_controller.dart';
import '../../../main.dart';
class MenuIconMapPageWidget extends StatelessWidget {
@@ -13,7 +13,7 @@ class MenuIconMapPageWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(
return GetBuilder<MapEngineController>(
builder: (controller) => Positioned(
top: Get.height * .008,
left: box.read(BoxName.lang) != 'ar' ? 5 : null,

View File

@@ -4,7 +4,7 @@ import 'dart:ui'; // مهم لإضافة تأثير الضبابية
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/location_search_controller.dart';
// --- الويدجت الرئيسية بالتصميم الجديد ---
class PassengerRideLocationWidget extends StatefulWidget {
@@ -43,7 +43,7 @@ class _PassengerRideLocationWidgetState
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(builder: (controller) {
return GetBuilder<LocationSearchController>(builder: (controller) {
// --- نفس شرط الإظهار الخاص بك ---
return AnimatedPositioned(
duration: const Duration(milliseconds: 300),
@@ -60,9 +60,9 @@ class _PassengerRideLocationWidgetState
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14),
decoration: BoxDecoration(
color: AppColor.secondaryColor.withOpacity(0.85),
color: AppColor.secondaryColor.withValues(alpha: 0.85),
borderRadius: BorderRadius.circular(50.0),
border: Border.all(color: AppColor.writeColor.withOpacity(0.2)),
border: Border.all(color: AppColor.writeColor.withValues(alpha: 0.2)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
@@ -89,7 +89,7 @@ class _PassengerRideLocationWidgetState
Text(
"Move the map to adjust the pin".tr,
style: AppStyle.subtitle.copyWith(
color: AppColor.writeColor.withOpacity(0.7),
color: AppColor.writeColor.withValues(alpha: 0.7),
),
),
],

View File

@@ -8,8 +8,7 @@ import 'package:Intaleq/views/widgets/elevated_btn.dart';
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
import '../../../controller/functions/digit_obsecur_formate.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/map_engine_controller.dart';
class PaymentMethodPage extends StatelessWidget {
const PaymentMethodPage({
@@ -18,7 +17,7 @@ class PaymentMethodPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(
return GetBuilder<MapEngineController>(
builder: (controller) => Positioned(
right: 5,
bottom: 5,

View File

@@ -4,20 +4,23 @@ import 'package:Intaleq/constant/table_names.dart';
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/location_search_controller.dart';
import '../../../controller/home/map/map_engine_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import '../../../main.dart';
import '../../widgets/elevated_btn.dart';
import 'form_search_places_destenation.dart';
class PickerAnimtionContainerFormPlaces extends StatelessWidget {
PickerAnimtionContainerFormPlaces({
super.key,
});
final controller = MapPassengerController();
const PickerAnimtionContainerFormPlaces({super.key});
@override
Widget build(BuildContext context) {
// DbSql sql = DbSql.instance;
return GetBuilder<MapPassengerController>(
final mapEngine = Get.find<MapEngineController>();
final locationSearch = Get.find<LocationSearchController>();
final rideLifecycle = Get.find<RideLifecycleController>();
return GetBuilder<MapEngineController>(
builder: (controller) => Positioned(
bottom: 0,
left: 0,
@@ -101,8 +104,7 @@ class PickerAnimtionContainerFormPlaces extends StatelessWidget {
? Center(
child: Column(
mainAxisAlignment:
MainAxisAlignment
.center,
MainAxisAlignment.center,
children: [
const Icon(
Icons
@@ -132,9 +134,9 @@ class PickerAnimtionContainerFormPlaces extends StatelessWidget {
children: [
TextButton(
onPressed: () async {
await controller
await rideLifecycle
.getDirectionMap(
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
'${locationSearch.passengerLocation.latitude},${locationSearch.passengerLocation.longitude}',
'${favoritePlaces[index]['latitude']},${favoritePlaces[index]['longitude']}',
);
controller
@@ -143,7 +145,7 @@ class PickerAnimtionContainerFormPlaces extends StatelessWidget {
.changeBottomSheetShown(
forceValue:
true);
controller
rideLifecycle
.bottomSheet();
Get.back();
},
@@ -189,24 +191,22 @@ class PickerAnimtionContainerFormPlaces extends StatelessWidget {
],
),
if (controller.isPickerShown &&
controller.placesDestination.isEmpty)
locationSearch.placesDestination.isEmpty)
MyElevatedButton(
title: 'Go to this Target'.tr,
onPressed: () async {
await controller.getDirectionMap(
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
'${controller.newMyLocation.latitude},${controller.newMyLocation.longitude}',
await rideLifecycle.getDirectionMap(
'${locationSearch.passengerLocation.latitude},${locationSearch.passengerLocation.longitude}',
'${locationSearch.newMyLocation.latitude},${locationSearch.newMyLocation.longitude}',
);
controller.changePickerShown();
controller.changeBottomSheetShown(
forceValue: true);
controller.bottomSheet();
// await sql
// .getAllData(TableName.placesFavorite)
rideLifecycle.bottomSheet();
},
),
if (controller.isPickerShown &&
controller.placesDestination.isEmpty)
locationSearch.placesDestination.isEmpty)
const SizedBox(),
],
),

View File

@@ -3,21 +3,25 @@ import 'package:get/get.dart';
import 'package:Intaleq/constant/style.dart';
import '../../../constant/colors.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/location_search_controller.dart';
import '../../../controller/home/map/map_engine_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import '../../../controller/home/points_for_rider_controller.dart';
class PointsPageForRider extends StatelessWidget {
PointsPageForRider({
super.key,
});
MapPassengerController mapPassengerController =
Get.put(MapPassengerController());
final locationSearch = Get.find<LocationSearchController>();
final mapEngine = Get.find<MapEngineController>();
final rideLifecycle = Get.find<RideLifecycleController>();
@override
Widget build(BuildContext context) {
Get.put(WayPointController());
Get.find<WayPointController>();
return GetBuilder<MapPassengerController>(builder: (controller) {
return GetBuilder<RideLifecycleController>(builder: (controller) {
return Positioned(
bottom: 2,
left: 2,
@@ -34,7 +38,7 @@ class PointsPageForRider extends StatelessWidget {
children: [
IconButton(
onPressed: () {
mapPassengerController.downPoints();
mapEngine.downPoints();
},
icon: const Icon(Icons.arrow_drop_down_circle_outlined),
),
@@ -52,7 +56,7 @@ class PointsPageForRider extends StatelessWidget {
wayPointController.wayPoints.length > 1
? ElevatedButton(
onPressed: () async {
mapPassengerController
locationSearch
.getMapPointsForAllMethods();
},
child: const Text('Get Direction'),
@@ -74,7 +78,6 @@ class PointsPageForRider extends StatelessWidget {
.entries
.map((entry) {
final index = entry.key;
final wayPoint = entry.value;
return Padding(
key: ValueKey(index),
padding: const EdgeInsets.all(1),
@@ -98,7 +101,7 @@ class PointsPageForRider extends StatelessWidget {
content: SizedBox(
width: Get.width,
height: 400,
child: mapPassengerController
child: locationSearch
.placeListResponse[index]),
);
},
@@ -106,13 +109,13 @@ class PointsPageForRider extends StatelessWidget {
decoration: BoxDecoration(
border: Border.all(),
color:
AppColor.accentColor.withOpacity(.5)),
AppColor.accentColor.withValues(alpha: 0.5)),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(index > 0
? mapPassengerController
? locationSearch
.currentLocationStringAll[index]
.toString()
: ''),
@@ -239,7 +242,6 @@ class PointsPageForRider extends StatelessWidget {
}
void showAddLocationDialog(BuildContext context, int index) {
final TextEditingController locationController = TextEditingController();
// Get.put(WayPointController());
showDialog(
context: context,
@@ -298,26 +300,24 @@ class AppBarPointsPageForRider extends StatelessWidget {
color: AppColor.primaryColor,
),
),
Container(
child: Row(
children: [
CircleAvatar(
backgroundColor: AppColor.primaryColor,
maxRadius: 15,
child: Icon(
Icons.person,
color: AppColor.secondaryColor,
),
Row(
children: [
CircleAvatar(
backgroundColor: AppColor.primaryColor,
maxRadius: 15,
child: Icon(
Icons.person,
color: AppColor.secondaryColor,
),
TextButton(
onPressed: () {},
child: Text(
"Switch Rider".tr,
style: AppStyle.title,
),
),
TextButton(
onPressed: () {},
child: Text(
"Switch Rider".tr,
style: AppStyle.title,
),
],
),
),
],
),
Icon(
Icons.clear,

View File

@@ -11,7 +11,9 @@ import '../../../constant/style.dart';
import '../../../controller/functions/audio_record1.dart';
import '../../../controller/functions/launch.dart';
import '../../../controller/functions/toast.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import '../../../controller/home/map/ui_interactions_controller.dart';
import '../../../controller/home/map/ride_state.dart';
import '../../../controller/profile/profile_controller.dart';
import '../../../main.dart';
import '../../../views/home/profile/complaint_page.dart';
@@ -24,9 +26,10 @@ class RideBeginPassenger extends StatelessWidget {
final ProfileController profileController = Get.put(ProfileController());
final AudioRecorderController audioController =
Get.put(AudioRecorderController());
final uiController = Get.find<UiInteractionsController>();
return Obx(() {
final controller = Get.find<MapPassengerController>();
final controller = Get.find<RideLifecycleController>();
// شرط الإظهار
final bool isVisible =
@@ -50,8 +53,8 @@ class RideBeginPassenger extends StatelessWidget {
boxShadow: [
BoxShadow(
color: Get.isDarkMode
? Colors.black.withOpacity(0.4)
: Colors.black.withOpacity(0.1),
? Colors.black.withValues(alpha: 0.4)
: Colors.black.withValues(alpha: 0.1),
blurRadius: 20,
spreadRadius: 2,
offset: const Offset(0, -3),
@@ -69,7 +72,7 @@ class RideBeginPassenger extends StatelessWidget {
width: 40,
height: 4,
decoration: BoxDecoration(
color: AppColor.grayColor.withOpacity(0.3),
color: AppColor.grayColor.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(10),
),
),
@@ -85,7 +88,7 @@ class RideBeginPassenger extends StatelessWidget {
Divider(
height: 1,
thickness: 0.5,
color: AppColor.grayColor.withOpacity(0.2)),
color: AppColor.grayColor.withValues(alpha: 0.2)),
const SizedBox(height: 12),
@@ -104,7 +107,7 @@ class RideBeginPassenger extends StatelessWidget {
}
// --- الهيدر (بدون تغيير، ممتاز) ---
Widget _buildCompactHeader(MapPassengerController controller) {
Widget _buildCompactHeader(RideLifecycleController controller) {
return Row(
children: [
// صورة السائق
@@ -112,7 +115,7 @@ class RideBeginPassenger extends StatelessWidget {
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: AppColor.primaryColor.withOpacity(0.5), width: 1.5),
color: AppColor.primaryColor.withValues(alpha: 0.5), width: 1.5),
),
child: CircleAvatar(
radius: 24,
@@ -166,9 +169,9 @@ class RideBeginPassenger extends StatelessWidget {
padding:
const EdgeInsets.symmetric(horizontal: 4, vertical: 1),
decoration: BoxDecoration(
color: AppColor.writeColor.withOpacity(0.05),
color: AppColor.writeColor.withValues(alpha: 0.05),
border: Border.all(
color: AppColor.grayColor.withOpacity(0.2)),
color: AppColor.grayColor.withValues(alpha: 0.2)),
borderRadius: BorderRadius.circular(4),
),
child: Text(
@@ -190,7 +193,7 @@ class RideBeginPassenger extends StatelessWidget {
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
decoration: BoxDecoration(
color: AppColor.primaryColor.withOpacity(0.08),
color: AppColor.primaryColor.withValues(alpha: 0.08),
borderRadius: BorderRadius.circular(8),
),
child: Column(
@@ -216,9 +219,10 @@ class RideBeginPassenger extends StatelessWidget {
// --- الأزرار (بدون تغيير) ---
Widget _buildCompactActionButtons(
BuildContext context,
MapPassengerController controller,
RideLifecycleController controller,
ProfileController profileController,
AudioRecorderController audioController) {
final uiController = Get.find<UiInteractionsController>();
return SizedBox(
height: 60,
child: Row(
@@ -228,7 +232,7 @@ class RideBeginPassenger extends StatelessWidget {
icon: Icons.sos_rounded,
label: 'SOS'.tr,
color: AppColor.redColor,
bgColor: AppColor.redColor.withOpacity(0.1),
bgColor: AppColor.redColor.withValues(alpha: 0.1),
onTap: () async {
if (box.read(BoxName.sosPhonePassenger) == null) {
await profileController.updatField(
@@ -244,24 +248,26 @@ class RideBeginPassenger extends StatelessWidget {
icon: FontAwesome.whatsapp,
label: 'WhatsApp'.tr,
color: const Color(0xFF25D366),
bgColor: const Color(0xFF25D366).withOpacity(0.1),
bgColor: const Color(0xFF25D366).withValues(alpha: 0.1),
onTap: () async {
if (box.read(BoxName.sosPhonePassenger) == null) {
await profileController.updatField(
'sosPhone', TextInputType.phone);
final phone = box.read(BoxName.sosPhonePassenger);
if (phone == null || phone.toString().isEmpty) {
// لا يوجد رقم طوارئ — نعرض الديالوج لإدخاله
await uiController.shareTripWithFamily();
} else {
final phone = controller.formatSyrianPhoneNumber(
box.read(BoxName.sosPhonePassenger).toString());
controller.sendWhatsapp(phone);
final formattedPhone = uiController.formatSyrianPhoneNumber(
phone.toString());
uiController.sendWhatsapp(formattedPhone);
}
},
),
_compactBtn(
icon: Icons.share,
label: 'Share'.tr,
color: AppColor.primaryColor,
bgColor: AppColor.primaryColor.withOpacity(0.1),
onTap: () async => await controller.shareTripWithFamily(),
bgColor: AppColor.primaryColor.withValues(alpha: 0.1),
onTap: () async => await uiController.shareTripWithFamily(),
),
GetBuilder<AudioRecorderController>(
init: audioController,
@@ -275,15 +281,19 @@ class RideBeginPassenger extends StatelessWidget {
? AppColor.redColor
: AppColor.primaryColor,
bgColor: audioCtx.isRecording
? AppColor.redColor.withOpacity(0.1)
: AppColor.primaryColor.withOpacity(0.1),
? AppColor.redColor.withValues(alpha: 0.1)
: AppColor.primaryColor.withValues(alpha: 0.1),
onTap: () async {
if (!audioCtx.isRecording) {
await audioCtx.startRecording();
Toast.show(context, 'Start Record'.tr, AppColor.greenColor);
await audioCtx.startRecording(rideId: controller.rideId);
if (context.mounted) {
Toast.show(context, 'Start Record'.tr, AppColor.greenColor);
}
} else {
await audioCtx.stopRecording();
Toast.show(context, 'Record saved'.tr, AppColor.greenColor);
if (context.mounted) {
Toast.show(context, 'Record saved'.tr, AppColor.greenColor);
}
}
},
);
@@ -293,7 +303,7 @@ class RideBeginPassenger extends StatelessWidget {
icon: Icons.info_outline_rounded,
label: 'Report'.tr,
color: AppColor.grayColor,
bgColor: AppColor.writeColor.withOpacity(0.1),
bgColor: AppColor.writeColor.withValues(alpha: 0.1),
onTap: () => Get.to(() => ComplaintPage()),
),
],

View File

@@ -8,7 +8,9 @@ import '../../../constant/box_name.dart';
import '../../../constant/colors.dart';
import '../../../constant/links.dart';
import '../../../constant/style.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import '../../../controller/home/map/ui_interactions_controller.dart';
import '../../../controller/home/map/ride_state.dart';
import '../../../controller/profile/profile_controller.dart';
import '../../../main.dart';
@@ -18,8 +20,10 @@ class RideFromStartApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final profileController = Get.put(ProfileController());
final MapPassengerController controller =
Get.find<MapPassengerController>();
final RideLifecycleController controller =
Get.find<RideLifecycleController>();
final UiInteractionsController uiController =
Get.find<UiInteractionsController>();
return Obx(() {
final bool isRideActive =
@@ -59,7 +63,7 @@ class RideFromStartApp extends StatelessWidget {
boxShadow: [
BoxShadow(
color: Get.isDarkMode
? Colors.black.withOpacity(0.4)
? Colors.black.withValues(alpha: 0.4)
: Colors.black12,
blurRadius: 15.0,
spreadRadius: 5.0,
@@ -78,7 +82,7 @@ class RideFromStartApp extends StatelessWidget {
height: 4,
margin: const EdgeInsets.only(bottom: 15),
decoration: BoxDecoration(
color: AppColor.grayColor.withOpacity(0.3),
color: AppColor.grayColor.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(10),
),
),
@@ -134,7 +138,7 @@ class RideFromStartApp extends StatelessWidget {
Container(
width: 1,
height: 12,
color: AppColor.grayColor.withOpacity(0.3)),
color: AppColor.grayColor.withValues(alpha: 0.3)),
const SizedBox(width: 8),
Text(
"$carType - $carModel",
@@ -160,7 +164,7 @@ class RideFromStartApp extends StatelessWidget {
const EdgeInsets.symmetric(vertical: 12, horizontal: 10),
decoration: BoxDecoration(
color: AppColor.grayColor
.withOpacity(0.1), // خلفية رمادية خفيفة جداً
.withValues(alpha: 0.1), // خلفية رمادية خفيفة جداً
borderRadius: BorderRadius.circular(15),
),
child: Row(
@@ -188,7 +192,7 @@ class RideFromStartApp extends StatelessWidget {
flex: 2,
child: ElevatedButton.icon(
onPressed: () => _checkAndCall(
controller.sendWhatsapp, profileController),
uiController.sendWhatsapp, profileController),
icon:
const Icon(FontAwesome.whatsapp, color: Colors.white),
label: Text("Share Trip".tr,
@@ -252,9 +256,9 @@ class RideFromStartApp extends StatelessWidget {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
color: color.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: color.withOpacity(0.5)),
border: Border.all(color: color.withValues(alpha: 0.5)),
),
child: Text(
text,
@@ -297,7 +301,7 @@ class RideFromStartApp extends StatelessWidget {
return Container(
height: 30,
width: 1,
color: AppColor.grayColor.withOpacity(0.2),
color: AppColor.grayColor.withValues(alpha: 0.2),
);
}

View File

@@ -2,7 +2,8 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:Intaleq/constant/colors.dart';
import 'package:Intaleq/constant/style.dart';
import 'package:Intaleq/controller/home/map_passenger_controller.dart';
import 'package:Intaleq/controller/home/map/ride_lifecycle_controller.dart';
import 'package:Intaleq/controller/home/map/ride_state.dart';
// --- الويدجت الرئيسية بالتصميم الجديد ---
class SearchingCaptainWindow extends StatefulWidget {
@@ -36,7 +37,7 @@ class _SearchingCaptainWindowState extends State<SearchingCaptainWindow>
// [تعديل 1] نستخدم Obx للاستماع إلى التغييرات في حالة الرحلة
return Obx(() {
// ابحث عن الكنترولر مرة واحدة
final controller = Get.find<MapPassengerController>();
final controller = Get.find<RideLifecycleController>();
// [تعديل 2] شرط الإظهار يعتمد الآن على حالة الرحلة مباشرة
final bool isVisible =
@@ -58,7 +59,7 @@ class _SearchingCaptainWindowState extends State<SearchingCaptainWindow>
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
color: Colors.black.withValues(alpha: 0.2),
blurRadius: 20,
offset: const Offset(0, -5),
),
@@ -83,7 +84,7 @@ class _SearchingCaptainWindowState extends State<SearchingCaptainWindow>
style: OutlinedButton.styleFrom(
foregroundColor: AppColor.writeColor,
side:
BorderSide(color: AppColor.writeColor.withOpacity(0.3)),
BorderSide(color: AppColor.writeColor.withValues(alpha: 0.3)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
padding: const EdgeInsets.symmetric(vertical: 12),
@@ -99,7 +100,7 @@ class _SearchingCaptainWindowState extends State<SearchingCaptainWindow>
}
// --- ويدجت بناء أنيميشن الرادار ---
Widget _buildRadarAnimation(MapPassengerController controller) {
Widget _buildRadarAnimation(RideLifecycleController controller) {
return SizedBox(
height: 180, // ارتفاع ثابت لمنطقة الأنيميشن
child: Stack(
@@ -125,7 +126,7 @@ class _SearchingCaptainWindowState extends State<SearchingCaptainWindow>
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: AppColor.primaryColor.withOpacity(0.7),
color: AppColor.primaryColor.withValues(alpha: 0.7),
width: 2,
),
),
@@ -147,7 +148,7 @@ class _SearchingCaptainWindowState extends State<SearchingCaptainWindow>
Text(
'Searching for the nearest captain...'.tr,
style: AppStyle.subtitle
.copyWith(color: AppColor.writeColor.withOpacity(0.7)),
.copyWith(color: AppColor.writeColor.withValues(alpha: 0.7)),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
@@ -166,12 +167,12 @@ class _SearchingCaptainWindowState extends State<SearchingCaptainWindow>
CircularProgressIndicator(
strokeWidth: 3,
color: AppColor.primaryColor,
backgroundColor: AppColor.primaryColor.withOpacity(0.2),
backgroundColor: AppColor.primaryColor.withValues(alpha: 0.2),
),
Center(
child: Icon(
Icons.search,
color: AppColor.writeColor.withOpacity(0.8),
color: AppColor.writeColor.withValues(alpha: 0.8),
),
),
],

View File

@@ -1,6 +1,6 @@
import 'package:Intaleq/constant/colors.dart';
import 'package:Intaleq/constant/style.dart';
import 'package:Intaleq/controller/home/map_passenger_controller.dart';
import 'package:Intaleq/controller/home/map/ride_lifecycle_controller.dart';
import 'package:Intaleq/views/widgets/elevated_btn.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -10,8 +10,10 @@ import '../../../constant/links.dart';
import '../../../print.dart';
class CupertinoDriverListWidget extends StatelessWidget {
MapPassengerController mapPassengerController =
Get.put(MapPassengerController());
CupertinoDriverListWidget({super.key});
final RideLifecycleController mapPassengerController =
Get.find<RideLifecycleController>();
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
@@ -158,7 +160,7 @@ class CupertinoDriverListWidget extends StatelessWidget {
),
onTap: () {
Log.print(' driver["id"]: ${driver['driver_id']}');
Get.find<MapPassengerController>().driverIdVip =
Get.find<RideLifecycleController>().driverIdVip =
driver['driver_id'];
// Handle driver selection
@@ -266,8 +268,6 @@ class CupertinoDriverListWidget extends StatelessWidget {
}
void showDateTimePickerDialog(Map<String, dynamic> driver) {
DateTime selectedDateTime = DateTime.now();
Get.defaultDialog(
barrierDismissible: false,
title: "Select date and time of trip".tr,
@@ -302,7 +302,9 @@ class CupertinoDriverListWidget extends StatelessWidget {
}
class DateTimePickerWidget extends StatelessWidget {
final MapPassengerController controller = Get.put(MapPassengerController());
DateTimePickerWidget({super.key});
final RideLifecycleController controller = Get.find<RideLifecycleController>();
@override
Widget build(BuildContext context) {

View File

@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../constant/style.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
GetBuilder<MapPassengerController> timerForCancelTripFromPassenger() {
return GetBuilder<MapPassengerController>(
GetBuilder<RideLifecycleController> timerForCancelTripFromPassenger() {
return GetBuilder<RideLifecycleController>(
builder: (controller) {
final isNearEnd =
controller.remainingTime <= 5; // Define a threshold for "near end"

View File

@@ -4,7 +4,7 @@ import 'package:Intaleq/views/widgets/elevated_btn.dart';
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import 'ride_begin_passenger.dart';
class TimerToPassengerFromDriver extends StatelessWidget {
@@ -14,7 +14,7 @@ class TimerToPassengerFromDriver extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(builder: (controller) {
return GetBuilder<RideLifecycleController>(builder: (controller) {
if (controller.remainingTime == 0 &&
(controller.isDriverInPassengerWay == true ||
controller.timeToPassengerFromDriverAfterApplied > 0)) {

View File

@@ -12,7 +12,8 @@ import '../../../constant/style.dart';
import '../../../controller/functions/audio_record1.dart';
import '../../../controller/functions/launch.dart';
import '../../../controller/functions/toast.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import '../../../controller/home/map/ui_interactions_controller.dart';
class VipRideBeginPassenger extends StatelessWidget {
const VipRideBeginPassenger({
@@ -24,8 +25,8 @@ class VipRideBeginPassenger extends StatelessWidget {
ProfileController profileController = Get.put(ProfileController());
AudioRecorderController audioController =
Get.put(AudioRecorderController());
// Get.put(MapPassengerController());
return GetBuilder<MapPassengerController>(builder: (controller) {
final uiController = Get.find<UiInteractionsController>();
return GetBuilder<RideLifecycleController>(builder: (controller) {
if (controller.statusRideVip == 'Begin' ||
!controller.statusRideFromStart) {
return Positioned(
@@ -148,9 +149,11 @@ class VipRideBeginPassenger extends StatelessWidget {
child: audioController.isRecording == false
? IconButton(
onPressed: () async {
await audioController.startRecording();
Toast.show(context, 'Start Record'.tr,
AppColor.greenColor);
await audioController.startRecording(rideId: controller.rideId);
if (context.mounted) {
Toast.show(context, 'Start Record'.tr,
AppColor.greenColor);
}
},
icon: const Icon(
Icons.play_circle_fill_outlined,
@@ -162,8 +165,10 @@ class VipRideBeginPassenger extends StatelessWidget {
: IconButton(
onPressed: () async {
await audioController.stopRecording();
Toast.show(context, 'Record saved'.tr,
AppColor.greenColor);
if (context.mounted) {
Toast.show(context, 'Record saved'.tr,
AppColor.greenColor);
}
},
icon: const Icon(
Icons.stop_circle,
@@ -215,15 +220,11 @@ class VipRideBeginPassenger extends StatelessWidget {
profileController.prfoileData['sosPhone']);
}
} else {
String phoneNumber = box
.read(BoxName.sosPhonePassenger)
.toString();
// phoneNumber = phoneNumber.replaceAll('0', '');
var phone = box.read(BoxName.countryCode) ==
'Egypt'
? '+2${box.read(BoxName.sosPhonePassenger)}'
: '+962${box.read(BoxName.sosPhonePassenger)}';
controller.sendWhatsapp(phone);
uiController.sendWhatsapp(phone);
}
},
icon: const Icon(
@@ -237,7 +238,7 @@ class VipRideBeginPassenger extends StatelessWidget {
width: Get.width * .15,
child: IconButton(
onPressed: () async {
await controller.shareTripWithFamily();
await uiController.shareTripWithFamily();
},
icon: const Icon(
AntDesign.Safety,
@@ -283,13 +284,12 @@ class VipRideBeginPassenger extends StatelessWidget {
}
class StreamCounter extends StatelessWidget {
const StreamCounter({Key? key}) : super(key: key);
const StreamCounter({super.key});
@override
// Build the UI based on the timer value
Widget build(BuildContext context) {
Get.put(MapPassengerController());
return GetBuilder<MapPassengerController>(builder: (controller) {
return GetBuilder<RideLifecycleController>(builder: (controller) {
return StreamBuilder<int>(
initialData: 0,
stream: controller.timerController.stream,

View File

@@ -268,9 +268,6 @@ class NavigationController extends GetxController
},
];
static final String _routeApiBaseUrl =
"${AppLink.routesOsm}/route/v1/driving";
IconData get currentManeuverIcon {
switch (currentManeuverModifier) {
case 4: // Arrive
@@ -378,7 +375,6 @@ class NavigationController extends GetxController
void onMapCreated(IntaleqMapController controller) async {
Log.print("DEBUG: NavigationController.onMapCreated called");
mapController = controller;
await onStyleLoaded();
}
Future<void> onStyleLoaded() async {
@@ -577,7 +573,7 @@ class NavigationController extends GetxController
}
void _checkOffRoute(LatLng pos) {
if (_autoRecalcInProgress || isLoading) return;
if (!isNavigating || _autoRecalcInProgress || isLoading) return;
if (_fullRouteCoordinates.isEmpty) return;
const int searchWindow = 80;
@@ -604,7 +600,6 @@ class NavigationController extends GetxController
if (elapsed >= _offRouteTriggerSeconds) {
_offRouteStartTime = null;
_autoRecalcInProgress = true;
// Smart reroute: check if we have alternative routes available
_smartRecalculateRoute(pos);
}
}
@@ -613,40 +608,11 @@ class NavigationController extends GetxController
}
}
/// الحل الذكي: إذا كان هناك مسارات بديلة متاحة، اختر الأقرب.
/// وإلا فاطلب مسار جديد من الموقع الحالي إلى الوجهة.
/// Recalculate immediately from the latest GPS point to the destination.
Future<void> _smartRecalculateRoute(LatLng currentPos) async {
try {
// Check if we have alternative routes
if (routes.isNotEmpty && selectedRouteIndex < routes.length - 1) {
// Try using the next alternative route
final nextIndex = selectedRouteIndex + 1;
final nextRoute = routes[nextIndex];
// Calculate distance from current position to this alternative route's start
double minDist = double.infinity;
for (var coord in nextRoute.coordinates) {
final d = Geolocator.distanceBetween(
currentPos.latitude,
currentPos.longitude,
coord.latitude,
coord.longitude,
);
if (d < minDist) minDist = d;
}
// If this alternative is reasonable, switch to it
if (minDist < 100) {
selectRoute(nextIndex);
Log.print("DEBUG: Switched to alternative route due to deviation");
_autoRecalcInProgress = false;
return;
}
}
// No good alternative, recalculate from current position to destination
if (_finalDestination != null) {
await recalculateRoute();
await recalculateRoute(origin: currentPos, keepNavigationActive: true);
}
_autoRecalcInProgress = false;
} catch (e) {
@@ -906,7 +872,8 @@ class NavigationController extends GetxController
return const LatLng(31.7225, 35.9933); // Queen Alia Airport (JO)
}
Future<void> getRoute(LatLng origin, LatLng destination) async {
Future<void> getRoute(LatLng origin, LatLng destination,
{bool keepNavigationActive = false}) async {
isLoading = true;
update();
@@ -1007,9 +974,8 @@ class NavigationController extends GetxController
currentStepIndex = 0;
_nextInstructionSpoken = false;
// Don't start navigating immediately, wait for user to press Start
isNavigating = false;
_cameraLockedToUser = false;
isNavigating = keepNavigationActive;
_cameraLockedToUser = keepNavigationActive;
_offRouteStartTime = null;
isLoading = false;
@@ -1032,7 +998,10 @@ class NavigationController extends GetxController
// Re-add car marker after polyline updates (ensures it stays on top)
if (isStyleLoaded) _updateCarMarker();
if (_fullRouteCoordinates.length >= 2) {
if (keepNavigationActive && myLocation != null) {
animateCameraToPosition(myLocation!,
bearing: _smoothedHeading, zoom: _targetZoom, tilt: _targetTilt);
} else if (_fullRouteCoordinates.length >= 2) {
final bounds =
data['bbox'] != null && (data['bbox'] as List).length == 4
? LatLngBounds(
@@ -1117,12 +1086,23 @@ class NavigationController extends GetxController
}
}
Future<void> recalculateRoute() async {
if (myLocation == null || _finalDestination == null || isLoading) return;
Future<void> recalculateRoute(
{LatLng? origin, bool keepNavigationActive = false}) async {
final LatLng? routeOrigin = origin ?? myLocation;
if (routeOrigin == null || _finalDestination == null || isLoading) return;
isLoading = true;
update();
mySnackbarInfo('جاري حساب مسار جديد...');
await getRoute(myLocation!, _finalDestination!);
markers = markers.where((m) => m.markerId.value != 'origin').toSet();
markers.add(Marker(
markerId: const MarkerId('origin'),
position: routeOrigin,
icon: InlqBitmap.fromStyleImage('start_icon'),
));
await getRoute(routeOrigin, _finalDestination!,
keepNavigationActive: keepNavigationActive);
isLoading = false;
update();
}
@@ -1290,17 +1270,19 @@ class NavigationController extends GetxController
try {
// ✅ Use searchPlaces from intaleq_maps SDK
final results = await mapController!.searchPlaces(q);
if (myLocation != null) {
for (final p in results) {
final plat = double.tryParse(p['latitude']?.toString() ?? '0') ?? 0.0;
final plng = double.tryParse(p['longitude']?.toString() ?? '0') ?? 0.0;
p['distanceKm'] = _haversineKm(myLocation!.latitude, myLocation!.longitude, plat, plng);
final plng =
double.tryParse(p['longitude']?.toString() ?? '0') ?? 0.0;
p['distanceKm'] = _haversineKm(
myLocation!.latitude, myLocation!.longitude, plat, plng);
}
results.sort((a, b) =>
(a['distanceKm'] as double).compareTo(b['distanceKm'] as double));
}
placesDestination = results;
update();
} catch (e) {

View File

@@ -41,6 +41,7 @@ class NavigationView extends StatelessWidget {
IntaleqMap(
apiKey: Env.mapSaasKey,
onMapCreated: c.onMapCreated,
onStyleLoaded: c.onStyleLoaded,
onLongPress: (pos) => c.onMapLongPressed(Point(0, 0), pos),
onTap: (pos) => c.onMapTapped(Point(0, 0), pos),
markers: c.markers,

File diff suppressed because it is too large Load Diff