import 'package:Intaleq/print.dart'; import 'package:Intaleq/views/widgets/my_textField.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:Intaleq/constant/box_name.dart'; import 'package:Intaleq/constant/style.dart'; import 'package:Intaleq/controller/home/map/map_engine_controller.dart'; import 'package:Intaleq/controller/home/map/location_search_controller.dart'; import 'package:Intaleq/controller/home/map/ride_lifecycle_controller.dart'; import 'package:Intaleq/main.dart'; import 'package:Intaleq/views/home/map_widget.dart/form_search_places_destenation.dart'; import 'package:Intaleq/views/widgets/elevated_btn.dart'; import 'package:intaleq_maps/intaleq_maps.dart'; import '../../../constant/colors.dart'; import '../../../constant/table_names.dart'; import '../../widgets/error_snakbar.dart'; import '../../widgets/mydialoug.dart'; import 'form_search_start.dart'; // ─── Design Tokens (Modern & Dynamic) ──────────────────────────────────────── class _D { static const double radiusCard = 28; static const double radiusChip = 20; static const double radiusInner = 14; static const double radiusPill = 50; static List get cardShadow => [ BoxShadow( color: Colors.black.withValues(alpha: 0.08), blurRadius: 40, spreadRadius: -8, offset: const Offset(0, 12), ), BoxShadow( color: Colors.black.withValues(alpha: 0.04), blurRadius: 16, spreadRadius: -4, offset: const Offset(0, 4), ), ]; static List glowShadow(Color c, {double intensity = 0.4}) => [ BoxShadow( color: c.withValues(alpha: intensity), blurRadius: 24, spreadRadius: -4, offset: const Offset(0, 8), ), BoxShadow( color: c.withValues(alpha: intensity * 0.5), blurRadius: 12, spreadRadius: -2, offset: const Offset(0, 3), ), ]; static const Duration fast = Duration(milliseconds: 180); static const Duration medium = Duration(milliseconds: 420); static LinearGradient primaryGradient({ Alignment begin = Alignment.topLeft, Alignment end = Alignment.bottomRight, }) => LinearGradient( begin: begin, end: end, colors: [ AppColor.primaryColor, AppColor.primaryColor.withValues(alpha: 0.85), AppColor.primaryColor.withValues(alpha: 0.7), ], stops: const [0.0, 0.5, 1.0], ); static LinearGradient cardGradient() => LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ AppColor.secondaryColor.withValues(alpha: 0.98), AppColor.secondaryColor .withBlue( ((AppColor.secondaryColor.b * 255.0).round() + 12).clamp(0, 255), ) .withValues(alpha: 0.95), ], ); } // ───────────────────────────────────────────────────────────────────────────── // MAIN BOTTOM MENU MAP - Scrollable Redesign // ───────────────────────────────────────────────────────────────────────────── class MainBottomMenuMap extends StatelessWidget { const MainBottomMenuMap({super.key}); @override Widget build(BuildContext context) { return GetBuilder( builder: (controller) { if (controller.isPickerShown) { return const _MapPickerOverlay(); } return Positioned( bottom: Get.height * .035, left: 16, right: 16, child: AnimatedContainer( duration: _D.medium, curve: Curves.easeOutQuint, constraints: BoxConstraints( maxHeight: controller.isMainBottomMenuMap ? Get.height * 0.4 : Get.height * 0.75, // الحد الأقصى للشاشة المفتوحة ), decoration: BoxDecoration( gradient: _D.cardGradient(), borderRadius: BorderRadius.circular(_D.radiusCard), boxShadow: _D.cardShadow, border: Border.all( color: Get.isDarkMode ? Colors.white.withValues(alpha: 0.15) : Colors.white.withValues(alpha: 0.65), width: 1.2, ), ), child: ClipRRect( borderRadius: BorderRadius.circular(_D.radiusCard), child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: controller.isMainBottomMenuMap ? const _CollapsedView() : const _ExpandedView(), ), ), ), ); }, ); } } // ───────────────────────────────────────────────────────────────────────────── // COLLAPSED VIEW // ───────────────────────────────────────────────────────────────────────────── class _CollapsedView extends StatelessWidget { const _CollapsedView(); @override Widget build(BuildContext context) { final String firstName = box.read(BoxName.name).toString().split(' ').first; final mapEngine = Get.find(); final rideLifecycle = Get.find(); return GetBuilder( builder: (locationSearch) { return Column( mainAxisSize: MainAxisSize.min, children: [ const SizedBox(height: 14), AnimatedContainer( duration: _D.fast, width: 44, height: 5, decoration: BoxDecoration( gradient: LinearGradient( colors: [ Colors.grey.shade400.withValues(alpha: 0.6), Colors.grey.shade300, Colors.grey.shade400.withValues(alpha: 0.6), ], ), borderRadius: BorderRadius.circular(3), ), ), const SizedBox(height: 16), Semantics( button: true, label: 'Open destination search'.tr, child: Material( color: Colors.transparent, child: InkWell( onTap: mapEngine.changeMainBottomMenuMap, borderRadius: BorderRadius.circular(_D.radiusInner), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 8), child: Row( children: [ AnimatedContainer( duration: _D.medium, width: 48, height: 48, decoration: BoxDecoration( gradient: _D.primaryGradient(), borderRadius: BorderRadius.circular(_D.radiusPill), boxShadow: _D.glowShadow(AppColor.primaryColor), ), child: const Icon(Icons.search_rounded, color: Colors.white, size: 22), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text.rich( TextSpan( children: [ TextSpan( text: '${'Where to'.tr} ', style: AppStyle.title.copyWith( fontWeight: FontWeight.w600, fontSize: 16, color: Colors.grey.shade700, ), ), TextSpan( text: firstName, style: AppStyle.title.copyWith( fontWeight: FontWeight.w800, fontSize: 16.5, color: AppColor.primaryColor, letterSpacing: -0.3, ), ), const TextSpan(text: '؟'), ], ), ), const SizedBox(height: 2), if (!rideLifecycle.noCarString) Text( 'Tap to search your destination'.tr, style: AppStyle.subtitle.copyWith( fontSize: 12, color: Colors.grey.shade500, fontWeight: FontWeight.w400, ), ), ], ), ), ], ), ), ), ), ), if (locationSearch.recentPlaces.isNotEmpty) ...[ const SizedBox(height: 12), Container( height: 40, padding: const EdgeInsets.symmetric(horizontal: 18), child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: locationSearch.recentPlaces.length, separatorBuilder: (_, __) => const SizedBox(width: 10), itemBuilder: (context, index) => _RecentPlaceChip(locationSearch: locationSearch, index: index), ), ), const SizedBox(height: 16), ] else const SizedBox(height: 20), ], ); }, ); } } // ───────────────────────────────────────────────────────────────────────────── // EXPANDED VIEW - Grouped Layout // ───────────────────────────────────────────────────────────────────────────── class _ExpandedView extends StatelessWidget { const _ExpandedView(); @override Widget build(BuildContext context) { final mapEngine = Get.find(); final rideLifecycle = Get.find(); return GetBuilder( builder: (locationSearch) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 14), Center( child: AnimatedContainer( duration: _D.fast, width: 44, height: 5, decoration: BoxDecoration( gradient: LinearGradient( colors: [ Colors.grey.shade400.withValues(alpha: 0.6), Colors.grey.shade300, Colors.grey.shade400.withValues(alpha: 0.6), ], ), borderRadius: BorderRadius.circular(3), ), ), ), // ── Header ── Container( padding: const EdgeInsets.fromLTRB(20, 18, 16, 14), child: Row( children: [ Text( 'Plan Your Route'.tr, style: AppStyle.title.copyWith( fontWeight: FontWeight.w800, fontSize: 18, letterSpacing: -0.5, ), ), const Spacer(), Semantics( button: true, label: 'Close panel'.tr, child: Material( color: Colors.transparent, child: InkWell( onTap: mapEngine.changeMainBottomMenuMap, borderRadius: BorderRadius.circular(_D.radiusPill), child: Container( width: 38, height: 38, decoration: BoxDecoration( color: Colors.grey.shade100, shape: BoxShape.circle, ), child: Icon(Icons.keyboard_arrow_down_rounded, size: 24, color: Colors.grey.shade600), ), ), ), ), ], ), ), // ── Group 1: Core Routing ── _buildSectionTitle('Route'.tr), _buildTimelineItem( dotColor: AppColor.primaryColor, showTopLine: false, showBottomLine: true, isStart: true, child: !rideLifecycle.isAnotherOreder ? _TimelineRow( icon: Icons.my_location_rounded, iconColor: AppColor.primaryColor, bgColor: AppColor.primaryColor, label: locationSearch.currentLocationString, ) : Padding( padding: const EdgeInsets.only(right: 16), child: formSearchPlacesStart(), ), ), ...List.generate(locationSearch.activeMenuWaypointCount, (index) { final wpName = locationSearch.menuWaypointNames[index]; final isSet = locationSearch.menuWaypoints[index] != null; final Color accent = index == 0 ? Colors.amber.shade600 : Colors.deepPurple.shade400; final Color soft = index == 0 ? Colors.amber.shade50 : Colors.deepPurple.shade50; return _buildTimelineItem( dotColor: accent, showTopLine: true, showBottomLine: true, child: Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), decoration: BoxDecoration( gradient: LinearGradient( colors: [soft.withValues(alpha: 0.9), soft.withValues(alpha: 0.6)]), borderRadius: BorderRadius.circular(_D.radiusInner), border: Border.all( color: isSet ? accent.withValues(alpha: 0.35) : Colors.grey.shade200), ), child: Row( children: [ Container( width: 26, height: 26, decoration: BoxDecoration(color: accent, shape: BoxShape.circle), child: Center( child: Text('${index + 1}', style: const TextStyle( color: Colors.white, fontSize: 11, fontWeight: FontWeight.w800))), ), const SizedBox(width: 12), Expanded( child: GestureDetector( onTap: () { mapEngine.changeMainBottomMenuMap(); locationSearch.startPickingWaypointOnMap(index); }, child: Text( isSet ? wpName : '${'Stop'.tr} ${index + 1}', style: TextStyle( fontSize: 13.5, color: isSet ? accent.withValues(alpha: 0.9) : Colors.grey.shade400, fontWeight: isSet ? FontWeight.w600 : FontWeight.w400, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), )), GestureDetector( onTap: () => locationSearch.removeMenuWaypoint(index), child: Container( width: 28, height: 28, decoration: BoxDecoration( color: Colors.red.shade50, shape: BoxShape.circle), child: Icon(Icons.close_rounded, color: Colors.red.shade400, size: 15), ), ), ], ), ), ); }), if (locationSearch.activeMenuWaypointCount < 2) _buildTimelineItem( dotColor: Colors.orange.shade300, isDotDashed: true, showTopLine: true, showBottomLine: true, child: InkWell( onTap: () => locationSearch.addMenuWaypoint(), borderRadius: BorderRadius.circular(_D.radiusInner), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( borderRadius: BorderRadius.circular(_D.radiusInner), border: Border.all(color: Colors.orange.shade200, width: 1.5), color: Colors.orange.shade50.withValues(alpha: 0.6), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.add_location_alt_outlined, color: Colors.orange.shade500, size: 18), const SizedBox(width: 10), Text('Add a Stop'.tr, style: TextStyle( color: Colors.orange.shade700, fontSize: 13.5, fontWeight: FontWeight.w600)), ], ), ), ), ), _buildTimelineItem( dotColor: Colors.red.shade500, showTopLine: true, showBottomLine: false, isEnd: true, child: Padding( padding: const EdgeInsets.only(right: 16), child: formSearchPlacesDestenation(), ), ), const SizedBox(height: 16), // ── Group 2: Quick Access ── _buildSectionDivider(), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _buildSectionTitle('Quick Access'.tr), const FaviouratePlacesDialog(), // تم نقلها هنا لتكون جزء من الوصول السريع ], ), if (locationSearch.recentPlaces.isNotEmpty) Container( height: 40, margin: const EdgeInsets.only(bottom: 16), child: ListView.separated( padding: const EdgeInsets.symmetric(horizontal: 20), scrollDirection: Axis.horizontal, itemCount: locationSearch.recentPlaces.length, separatorBuilder: (_, __) => const SizedBox(width: 10), itemBuilder: (context, index) => _RecentPlaceChip(locationSearch: locationSearch, index: index), ), ), // ── Group 3: Advanced Tools ── _buildSectionDivider(), _buildSectionTitle('Advanced Tools'.tr), Padding( padding: const EdgeInsets.symmetric(horizontal: 18), child: _WhatsAppLinkButton(locationSearch: locationSearch), ), const SizedBox(height: 12), Padding( padding: const EdgeInsets.symmetric(horizontal: 18), child: _OrderTypeButton(mapEngine: mapEngine), ), const SizedBox(height: 24), // مساحة سفلية لضمان راحة السحب ], ); }, ); } Widget _buildSectionTitle(String title) { return Padding( padding: const EdgeInsets.only(left: 20, right: 20, bottom: 12), child: Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Colors.grey.shade400, letterSpacing: 0.5, ), ), ); } Widget _buildSectionDivider() { return Container( height: 1, margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), color: Colors.grey.shade200, ); } Widget _buildTimelineItem({ required Color dotColor, required bool showTopLine, required bool showBottomLine, required Widget child, bool isDotDashed = false, bool isStart = false, bool isEnd = false, }) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 24, child: Column( children: [ if (showTopLine) Container( width: 2.5, height: 12, color: Colors.grey.shade300), Container( width: 15, height: 15, decoration: BoxDecoration( color: isDotDashed ? Colors.transparent : dotColor, shape: BoxShape.circle, border: Border.all(color: dotColor, width: isDotDashed ? 2 : 3), ), ), if (showBottomLine) Container( width: 2.5, height: 12, color: Colors.grey.shade300), ], ), ), const SizedBox(width: 14), Expanded(child: child), ], ), ); } } // ───────────────────────────────────────────────────────────────────────────── // MAP PICKER OVERLAY // ───────────────────────────────────────────────────────────────────────────── class _MapPickerOverlay extends StatelessWidget { const _MapPickerOverlay(); String _getModeTitle(LocationSearchController locationSearch, BuildContext context) { if (locationSearch.isPickingWaypoint) { return 'Move map to set stop'.tr + ' ${locationSearch.pickingWaypointIndex + 1}'.tr; } if (locationSearch.passengerStartLocationFromMap) { final rideLifecycle = Get.find(); return rideLifecycle.isAnotherOreder ? 'Now set the pickup point for the other person'.tr : 'Move map to your pickup point'.tr; } if (locationSearch.startLocationFromMap) { return 'Move map to set start location'.tr; } if (locationSearch.workLocationFromMap) { return 'Move map to your work location'.tr; } if (locationSearch.homeLocationFromMap) { return 'Move map to your home location'.tr; } return 'Move map to select destination'.tr; } String _getConfirmLabel(LocationSearchController locationSearch, BuildContext context) { if (locationSearch.isPickingWaypoint) return 'Set as Stop'.tr; if (locationSearch.passengerStartLocationFromMap) { return 'Confirm Pickup Location'.tr; } if (locationSearch.workLocationFromMap) return 'Set as Work'.tr; if (locationSearch.homeLocationFromMap) return 'Set as Home'.tr; return 'Set Destination'.tr; } IconData _getModeIcon(LocationSearchController locationSearch) { if (locationSearch.isPickingWaypoint) return Icons.add_location_alt_rounded; if (locationSearch.passengerStartLocationFromMap) { return Icons.person_pin_circle_rounded; } if (locationSearch.workLocationFromMap) return Icons.work_rounded; if (locationSearch.homeLocationFromMap) return Icons.home_rounded; return Icons.location_on_rounded; } Color _getModeColor(LocationSearchController locationSearch) { if (locationSearch.isPickingWaypoint) return Colors.orange.shade600; if (locationSearch.passengerStartLocationFromMap) return Colors.green.shade600; if (locationSearch.workLocationFromMap) return Colors.blue.shade600; if (locationSearch.homeLocationFromMap) return Colors.orange.shade600; return AppColor.primaryColor; } @override Widget build(BuildContext context) { final mapEngine = Get.find(); return GetBuilder( builder: (locationSearch) { final modeColor = _getModeColor(locationSearch); return Positioned( bottom: Get.height * .035, left: 16, right: 16, child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14), decoration: BoxDecoration( color: modeColor, borderRadius: BorderRadius.circular(_D.radiusCard), ), child: Row( children: [ Icon(_getModeIcon(locationSearch), color: Colors.white, size: 19), const SizedBox(width: 14), Expanded( child: Text( _getModeTitle(locationSearch, context), style: const TextStyle( color: Colors.white, fontWeight: FontWeight.w700, fontSize: 14), ), ), ], ), ), const SizedBox(height: 12), Container( decoration: BoxDecoration( color: AppColor.secondaryColor, borderRadius: BorderRadius.circular(_D.radiusCard), boxShadow: _D.cardShadow, ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.fromLTRB(20, 18, 20, 2), child: Row( children: [ Icon(Icons.gps_fixed_rounded, color: modeColor, size: 16), const SizedBox(width: 14), Expanded( child: Text( '${locationSearch.newMyLocation.latitude.toStringAsFixed(5)}, ${locationSearch.newMyLocation.longitude.toStringAsFixed(5)}', style: TextStyle( fontSize: 12, color: Colors.grey.shade700, fontWeight: FontWeight.w500), ), ), ], ), ), const SizedBox(height: 16), Padding( padding: const EdgeInsets.fromLTRB(16, 14, 16, 18), child: Row( children: [ Expanded( flex: 2, child: OutlinedButton( onPressed: () { mapEngine.isPickerShown = false; locationSearch.passengerStartLocationFromMap = false; locationSearch.startLocationFromMap = false; locationSearch.workLocationFromMap = false; locationSearch.homeLocationFromMap = false; locationSearch.isPickingWaypoint = false; locationSearch.pickingWaypointIndex = -1; if (!mapEngine.isMainBottomMenuMap) { mapEngine.isMainBottomMenuMap = true; mapEngine.mainBottomMenuMapHeight = Get.height * .22; } mapEngine.update(); locationSearch.update(); }, child: Text('Cancel'.tr), ), ), const SizedBox(width: 12), Expanded( flex: 3, child: ElevatedButton( onPressed: () => _onConfirmTap(mapEngine, locationSearch, context), style: ElevatedButton.styleFrom( backgroundColor: modeColor), child: Text(_getConfirmLabel(locationSearch, context), style: const TextStyle(color: Colors.white)), ), ), ], ), ), ], ), ), ], ), ); }, ); } Future _onConfirmTap( MapEngineController mapEngine, LocationSearchController locationSearch, BuildContext context) async { final rideLifecycle = Get.find(); Log.print( '🔘 _onConfirmTap: isPickingWaypoint=${locationSearch.isPickingWaypoint}, newMyLocation=${locationSearch.newMyLocation}'); await Future.delayed(const Duration(milliseconds: 280)); final LatLng currentCameraPosition = LatLng( locationSearch.newMyLocation.latitude, locationSearch.newMyLocation.longitude); if (locationSearch.isPickingWaypoint && locationSearch.pickingWaypointIndex >= 0) { locationSearch.setMenuWaypointFromMap( locationSearch.pickingWaypointIndex, currentCameraPosition); mySnackbarSuccess('Waypoint has been set successfully'.tr); return; } mapEngine.clearPolyline(); rideLifecycle.data = []; if (locationSearch.passengerStartLocationFromMap) { final LatLng start = currentCameraPosition; locationSearch.newStartPointLocation = start; locationSearch.passengerStartLocationFromMap = false; mapEngine.isPickerShown = false; locationSearch.currentLocationToFormPlaces = false; locationSearch.placesDestination = []; locationSearch.clearPlacesStart(); locationSearch.clearPlacesDestination(); mapEngine.isMainBottomMenuMap = true; mapEngine.mainBottomMenuMapHeight = Get.height * .22; mapEngine.update(); locationSearch.update(); await rideLifecycle.getDirectionMap('${start.latitude},${start.longitude}', '${locationSearch.myDestination.latitude},${locationSearch.myDestination.longitude}'); rideLifecycle.showBottomSheet1(); return; } if (locationSearch.startLocationFromMap) { final LatLng start = currentCameraPosition; locationSearch.newMyLocation = start; locationSearch.newStartPointLocation = start; locationSearch.hintTextStartPoint = '${start.latitude.toStringAsFixed(4)} , ${start.longitude.toStringAsFixed(4)}'; locationSearch.startLocationFromMap = false; mapEngine.isPickerShown = false; locationSearch.update(); mapEngine.update(); return; } if (locationSearch.workLocationFromMap) { box.write(BoxName.addWork, '${currentCameraPosition.latitude.toStringAsFixed(4)} , ${currentCameraPosition.longitude.toStringAsFixed(4)}'); locationSearch.hintTextDestinationPoint = 'To Work'.tr; locationSearch.workLocationFromMap = false; mapEngine.isPickerShown = false; locationSearch.update(); mapEngine.update(); mySnackbarSuccess('Work Saved'.tr); return; } if (locationSearch.homeLocationFromMap) { box.write(BoxName.addHome, '${currentCameraPosition.latitude.toStringAsFixed(4)} , ${currentCameraPosition.longitude.toStringAsFixed(4)}'); locationSearch.hintTextDestinationPoint = 'To Home'.tr; locationSearch.homeLocationFromMap = false; mapEngine.isPickerShown = false; locationSearch.update(); mapEngine.update(); mySnackbarSuccess('Home Saved'.tr); return; } locationSearch.myDestination = currentCameraPosition; locationSearch.hintTextDestinationPoint = '${currentCameraPosition.latitude.toStringAsFixed(4)} , ${currentCameraPosition.longitude.toStringAsFixed(4)}'; locationSearch.placesDestination = []; locationSearch.placeDestinationController.clear(); locationSearch.passengerStartLocationFromMap = true; mapEngine.isPickerShown = true; locationSearch.update(); mapEngine.update(); try { if (rideLifecycle.isAnotherOreder) { await mapEngine.mapController?.animateCamera(CameraUpdate.newLatLng( LatLng(locationSearch.newStartPointLocation.latitude, locationSearch.newStartPointLocation.longitude))); } else { await mapEngine.mapController?.animateCamera(CameraUpdate.newLatLng( LatLng(locationSearch.passengerLocation.latitude, locationSearch.passengerLocation.longitude))); } } catch (e) { Log.print("Error occurred: $e"); } } } // ───────────────────────────────────────────────────────────────────────────── // HELPER WIDGETS // ───────────────────────────────────────────────────────────────────────────── class _TimelineRow extends StatelessWidget { final IconData icon; final Color iconColor; final Color bgColor; final String label; const _TimelineRow( {required this.icon, required this.iconColor, required this.bgColor, required this.label}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 11), decoration: BoxDecoration( color: bgColor.withValues(alpha: 0.06), borderRadius: BorderRadius.circular(_D.radiusInner)), child: Row( children: [ Icon(icon, color: iconColor, size: 15), const SizedBox(width: 12), Expanded( child: Text(label, style: AppStyle.subtitle .copyWith(fontSize: 13, fontWeight: FontWeight.w500), maxLines: 1, overflow: TextOverflow.ellipsis)), ], ), ); } } class _RecentPlaceChip extends StatelessWidget { final LocationSearchController locationSearch; final int index; const _RecentPlaceChip({required this.locationSearch, required this.index}); @override Widget build(BuildContext context) { final place = locationSearch.recentPlaces[index]; final rideLifecycle = Get.find(); return Material( color: Colors.transparent, child: InkWell( onTap: () { MyDialog().getDialog( 'Are you want to go this site'.tr, ' ', () async { await locationSearch.getLocation(); await rideLifecycle.getDirectionMap( '${locationSearch.passengerLocation.latitude},${locationSearch.passengerLocation.longitude}', '${place['latitude']},${place['longitude']}'); rideLifecycle.showBottomSheet1(); }, ); }, borderRadius: BorderRadius.circular(_D.radiusChip), child: Container( padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 7), decoration: BoxDecoration( color: AppColor.primaryColor.withValues(alpha: 0.08), borderRadius: BorderRadius.circular(_D.radiusChip), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.history_rounded, size: 14, color: AppColor.primaryColor.withValues(alpha: 0.7)), const SizedBox(width: 7), Text(place['name'] ?? '', style: TextStyle( fontSize: 12.5, color: AppColor.primaryColor.withValues(alpha: 0.9), fontWeight: FontWeight.w600)), ], ), ), ), ); } } class _WhatsAppLinkButton extends StatelessWidget { final LocationSearchController locationSearch; const _WhatsAppLinkButton({required this.locationSearch}); @override Widget build(BuildContext context) { return Material( color: Colors.transparent, child: InkWell( onTap: () { Get.dialog( AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(22)), title: Text('WhatsApp Location Extractor'.tr), content: Form( key: locationSearch.sosFormKey, child: Column( mainAxisSize: MainAxisSize.min, children: [ MyTextForm( controller: locationSearch.whatsAppLocationText, label: 'Location Link'.tr, type: TextInputType.url, hint: 'https://maps.app.goo.gl/...'), const SizedBox(height: 16), MyElevatedButton( title: 'Go to this location'.tr, onPressed: () => locationSearch.goToWhatappLocation()), ], ), ), ), ); }, borderRadius: BorderRadius.circular(_D.radiusInner), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration( color: Colors.green.shade50, borderRadius: BorderRadius.circular(_D.radiusInner)), child: Row( children: [ Icon(Icons.link_rounded, color: Colors.green.shade700, size: 18), const SizedBox(width: 14), Expanded( child: Text('Paste WhatsApp location link'.tr, style: TextStyle( color: Colors.green.shade800, fontSize: 13.5, fontWeight: FontWeight.w600))), ], ), ), ), ); } } class _OrderTypeButton extends StatelessWidget { final MapEngineController mapEngine; const _OrderTypeButton({required this.mapEngine}); @override Widget build(BuildContext context) { final rideLifecycle = Get.find(); final bool isOther = mapEngine.isAnotherOreder; final Color accent = isOther ? Colors.indigo.shade500 : AppColor.primaryColor; return Material( color: Colors.transparent, child: InkWell( onTap: () { showCupertinoModalPopup( context: context, builder: (ctx) => CupertinoActionSheet( title: Text('Select Order Type'.tr), actions: [ CupertinoActionSheetAction( child: Text('I want to order for myself'.tr), onPressed: () { mapEngine.changeisAnotherOreder(false); rideLifecycle.isAnotherOreder = false; Navigator.pop(ctx); }, ), CupertinoActionSheetAction( child: Text('I want to order for someone else'.tr), onPressed: () { mapEngine.changeisAnotherOreder(true); rideLifecycle.isAnotherOreder = true; Navigator.pop(ctx); }, ), ], cancelButton: CupertinoActionSheetAction( isDefaultAction: true, onPressed: () => Navigator.pop(ctx), child: Text('Cancel'.tr)), ), ); }, borderRadius: BorderRadius.circular(_D.radiusInner), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration( color: accent.withValues(alpha: 0.08), borderRadius: BorderRadius.circular(_D.radiusInner)), child: Row( children: [ Icon(isOther ? Icons.person_rounded : Icons.group_rounded, color: accent, size: 17), const SizedBox(width: 14), Expanded( child: Text( isOther ? 'Order for myself'.tr : 'Order for someone else'.tr, style: TextStyle( color: accent, fontSize: 13.5, fontWeight: FontWeight.w600))), ], ), ), ), ); } } class FaviouratePlacesDialog extends StatelessWidget { const FaviouratePlacesDialog({super.key}); @override Widget build(BuildContext context) { return GetBuilder( builder: (locationSearch) { final rideLifecycle = Get.find(); return InkWell( borderRadius: BorderRadius.circular(14), onTap: () async { final List favoritePlaces = await sql.getAllData(TableName.placesFavorite); Get.defaultDialog( title: 'Favorite Places'.tr, content: SizedBox( width: Get.width * .85, height: 300, child: favoritePlaces.isEmpty ? Center(child: Text('No favorite places yet!'.tr)) : ListView.separated( itemCount: favoritePlaces.length, separatorBuilder: (_, __) => Divider(height: 1, color: Colors.grey.shade100), itemBuilder: (context, index) => ListTile( leading: const Icon(Icons.star, color: Colors.amber, size: 19), title: Text(favoritePlaces[index]['name']), trailing: IconButton( icon: const Icon(Icons.delete_outline, color: Colors.redAccent), onPressed: () async { await sql.deleteData(TableName.placesFavorite, favoritePlaces[index]['id']); Get.back(); }, ), onTap: () async { Get.back(); await locationSearch.getLocation(); await rideLifecycle.getDirectionMap( '${locationSearch.passengerLocation.latitude},${locationSearch.passengerLocation.longitude}', '${favoritePlaces[index]['latitude']},${favoritePlaces[index]['longitude']}'); rideLifecycle.showBottomSheet1(); }, ), ), ), confirm: MyElevatedButton(title: 'Back'.tr, onPressed: () => Get.back()), ); }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.star_border_rounded, color: AppColor.accentColor, size: 21), const SizedBox(width: 10), Text('Favorite Places'.tr, style: AppStyle.title .copyWith(fontWeight: FontWeight.w600, fontSize: 14)), ], ), ), ); }, ); } }