Files
intaleq/lib/views/home/map_widget.dart/main_bottom_Menu_map.dart
2026-04-16 19:45:03 +03:00

1140 lines
42 KiB
Dart

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_passenger_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:maplibre_gl/maplibre_gl.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 radiusBtn = 16;
static const double radiusInner = 14;
static const double radiusPill = 50;
static List<BoxShadow> get cardShadow => [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 40,
spreadRadius: -8,
offset: const Offset(0, 12),
),
BoxShadow(
color: Colors.black.withOpacity(0.04),
blurRadius: 16,
spreadRadius: -4,
offset: const Offset(0, 4),
),
];
static List<BoxShadow> glowShadow(Color c, {double intensity = 0.4}) => [
BoxShadow(
color: c.withOpacity(intensity),
blurRadius: 24,
spreadRadius: -4,
offset: const Offset(0, 8),
),
BoxShadow(
color: c.withOpacity(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 const Duration slow = Duration(milliseconds: 600);
static LinearGradient primaryGradient({
Alignment begin = Alignment.topLeft,
Alignment end = Alignment.bottomRight,
}) =>
LinearGradient(
begin: begin,
end: end,
colors: [
AppColor.primaryColor,
AppColor.primaryColor.withOpacity(0.85),
AppColor.primaryColor.withOpacity(0.7),
],
stops: const [0.0, 0.5, 1.0],
);
static LinearGradient cardGradient() => LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
AppColor.secondaryColor.withOpacity(0.98),
AppColor.secondaryColor
.withBlue(
(AppColor.secondaryColor.blue + 12).clamp(0, 255),
)
.withOpacity(0.95),
],
);
}
// ─────────────────────────────────────────────────────────────────────────────
// MAIN BOTTOM MENU MAP - Scrollable Redesign
// ─────────────────────────────────────────────────────────────────────────────
class MainBottomMenuMap extends StatelessWidget {
const MainBottomMenuMap({super.key});
@override
Widget build(BuildContext context) {
Get.put(MapPassengerController());
return GetBuilder<MapPassengerController>(
builder: (controller) {
if (controller.isPickerShown) {
return _MapPickerOverlay(controller: controller);
}
return Positioned(
bottom: Get.height * .035,
left: 16,
right: 16,
child: AnimatedContainer(
duration: _D.medium,
curve: Curves.easeOutQuint,
// تم استبدال الارتفاع الثابت بـ BoxConstraints للسماح بالتمدد الديناميكي
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.withOpacity(0.15)
: Colors.white.withOpacity(0.65),
width: 1.2,
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(_D.radiusCard),
// تفعيل السحب والنزول
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: controller.isMainBottomMenuMap
? _CollapsedView(controller: controller)
: _ExpandedView(controller: controller, context: context),
),
),
),
);
},
);
}
}
// ─────────────────────────────────────────────────────────────────────────────
// COLLAPSED VIEW
// ─────────────────────────────────────────────────────────────────────────────
class _CollapsedView extends StatelessWidget {
final MapPassengerController controller;
const _CollapsedView({required this.controller});
@override
Widget build(BuildContext context) {
final String firstName = box.read(BoxName.name).toString().split(' ').first;
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.withOpacity(0.6),
Colors.grey.shade300,
Colors.grey.shade400.withOpacity(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: controller.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 (!controller.noCarString)
Text(
'Tap to search your destination'.tr,
style: AppStyle.subtitle.copyWith(
fontSize: 12,
color: Colors.grey.shade500,
fontWeight: FontWeight.w400,
),
),
],
),
),
],
),
),
),
),
),
if (controller.recentPlaces.isNotEmpty) ...[
const SizedBox(height: 12),
Container(
height: 40,
padding: const EdgeInsets.symmetric(horizontal: 18),
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: controller.recentPlaces.length,
separatorBuilder: (_, __) => const SizedBox(width: 10),
itemBuilder: (context, index) =>
_RecentPlaceChip(controller: controller, index: index),
),
),
const SizedBox(height: 16),
] else
const SizedBox(height: 20),
],
);
}
}
// ─────────────────────────────────────────────────────────────────────────────
// EXPANDED VIEW - Grouped Layout
// ─────────────────────────────────────────────────────────────────────────────
class _ExpandedView extends StatelessWidget {
final MapPassengerController controller;
final BuildContext context;
const _ExpandedView({required this.controller, required this.context});
@override
Widget build(BuildContext context) {
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.withOpacity(0.6),
Colors.grey.shade300,
Colors.grey.shade400.withOpacity(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: controller.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: !controller.isAnotherOreder
? _TimelineRow(
icon: Icons.my_location_rounded,
iconColor: AppColor.primaryColor,
bgColor: AppColor.primaryColor,
label: controller.currentLocationString,
)
: Padding(
padding: const EdgeInsets.only(right: 16),
child: formSearchPlacesStart(),
),
),
...List.generate(controller.activeMenuWaypointCount, (index) {
final wpName = controller.menuWaypointNames[index];
final isSet = controller.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.withOpacity(0.9), soft.withOpacity(0.6)]),
borderRadius: BorderRadius.circular(_D.radiusInner),
border: Border.all(
color: isSet
? accent.withOpacity(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: () {
controller.changeMainBottomMenuMap();
controller.startPickingWaypointOnMap(index);
},
child: Text(
isSet ? wpName : '${'Stop'.tr} ${index + 1}',
style: TextStyle(
fontSize: 13.5,
color: isSet
? accent.withOpacity(0.9)
: Colors.grey.shade400,
fontWeight: isSet ? FontWeight.w600 : FontWeight.w400,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
)),
GestureDetector(
onTap: () => controller.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 (controller.activeMenuWaypointCount < 2)
_buildTimelineItem(
dotColor: Colors.orange.shade300,
isDotDashed: true,
showTopLine: true,
showBottomLine: true,
child: InkWell(
onTap: () => controller.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.withOpacity(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 (controller.recentPlaces.isNotEmpty)
Container(
height: 40,
margin: const EdgeInsets.only(bottom: 16),
child: ListView.separated(
padding: const EdgeInsets.symmetric(horizontal: 20),
scrollDirection: Axis.horizontal,
itemCount: controller.recentPlaces.length,
separatorBuilder: (_, __) => const SizedBox(width: 10),
itemBuilder: (context, index) =>
_RecentPlaceChip(controller: controller, index: index),
),
),
// ── Group 3: Advanced Tools ──
_buildSectionDivider(),
_buildSectionTitle('Advanced Tools'.tr),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: _WhatsAppLinkButton(controller: controller),
),
const SizedBox(height: 12),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: _OrderTypeButton(controller: controller),
),
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 {
final MapPassengerController controller;
const _MapPickerOverlay({required this.controller});
String _getModeTitle(BuildContext context) {
if (controller.isPickingWaypoint)
return 'Move map to set stop'.tr +
' ${controller.pickingWaypointIndex + 1}'.tr;
if (controller.passengerStartLocationFromMap)
return controller.isAnotherOreder
? 'Now set the pickup point for the other person'.tr
: 'Move map to your pickup point'.tr;
if (controller.startLocationFromMap)
return 'Move map to set start location'.tr;
if (controller.workLocationFromMap)
return 'Move map to your work location'.tr;
if (controller.homeLocationFromMap)
return 'Move map to your home location'.tr;
return 'Move map to select destination'.tr;
}
String _getConfirmLabel(BuildContext context) {
if (controller.isPickingWaypoint) return 'Set as Stop'.tr;
if (controller.passengerStartLocationFromMap)
return 'Confirm Pickup Location'.tr;
if (controller.workLocationFromMap) return 'Set as Work'.tr;
if (controller.homeLocationFromMap) return 'Set as Home'.tr;
return 'Set Destination'.tr;
}
IconData _getModeIcon() {
if (controller.isPickingWaypoint) return Icons.add_location_alt_rounded;
if (controller.passengerStartLocationFromMap)
return Icons.person_pin_circle_rounded;
if (controller.workLocationFromMap) return Icons.work_rounded;
if (controller.homeLocationFromMap) return Icons.home_rounded;
return Icons.location_on_rounded;
}
Color _getModeColor() {
if (controller.isPickingWaypoint) return Colors.orange.shade600;
if (controller.passengerStartLocationFromMap) return Colors.green.shade600;
if (controller.workLocationFromMap) return Colors.blue.shade600;
if (controller.homeLocationFromMap) return Colors.orange.shade600;
return AppColor.primaryColor;
}
@override
Widget build(BuildContext context) {
final modeColor = _getModeColor();
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(), color: Colors.white, size: 19),
const SizedBox(width: 14),
Expanded(
child: Text(
_getModeTitle(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(
'${controller.newMyLocation.latitude.toStringAsFixed(5)}, ${controller.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: () {
controller.isPickerShown = false;
controller.passengerStartLocationFromMap = false;
controller.startLocationFromMap = false;
controller.workLocationFromMap = false;
controller.homeLocationFromMap = false;
controller.isPickingWaypoint = false;
controller.pickingWaypointIndex = -1;
if (!controller.isMainBottomMenuMap) {
controller.isMainBottomMenuMap = true;
controller.mainBottomMenuMapHeight =
Get.height * .22;
}
controller.update();
},
child: Text('Cancel'.tr),
),
),
const SizedBox(width: 12),
Expanded(
flex: 3,
child: ElevatedButton(
onPressed: () => _onConfirmTap(controller, context),
style: ElevatedButton.styleFrom(
backgroundColor: modeColor),
child: Text(_getConfirmLabel(context),
style: const TextStyle(color: Colors.white)),
),
),
],
),
),
],
),
),
],
),
);
}
Future<void> _onConfirmTap(
MapPassengerController controller, BuildContext context) async {
await Future.delayed(const Duration(milliseconds: 280));
final LatLng currentCameraPosition = LatLng(
controller.newMyLocation.latitude, controller.newMyLocation.longitude);
if (controller.isPickingWaypoint && controller.pickingWaypointIndex >= 0) {
controller.setMenuWaypointFromMap(
controller.pickingWaypointIndex, currentCameraPosition);
mySnackbarSuccess('Waypoint has been set successfully'.tr);
return;
}
controller.clearPolyline();
controller.data = [];
if (controller.passengerStartLocationFromMap) {
final LatLng start = currentCameraPosition;
controller.newStartPointLocation = start;
controller.passengerStartLocationFromMap = false;
controller.isPickerShown = false;
controller.currentLocationToFormPlaces = false;
controller.placesDestination = [];
controller.clearPlacesStart();
controller.clearPlacesDestination();
controller.isMainBottomMenuMap = true;
controller.mainBottomMenuMapHeight = Get.height * .22;
controller.update();
await controller.getDirectionMap('${start.latitude},${start.longitude}',
'${controller.myDestination.latitude},${controller.myDestination.longitude}');
controller.showBottomSheet1();
return;
}
if (controller.startLocationFromMap) {
final LatLng start = currentCameraPosition;
controller.newMyLocation = start;
controller.newStartPointLocation = start;
controller.hintTextStartPoint =
'${start.latitude.toStringAsFixed(4)} , ${start.longitude.toStringAsFixed(4)}';
controller.startLocationFromMap = false;
controller.isPickerShown = false;
controller.update();
return;
}
if (controller.workLocationFromMap) {
box.write(BoxName.addWork,
'${currentCameraPosition.latitude.toStringAsFixed(4)} , ${currentCameraPosition.longitude.toStringAsFixed(4)}');
controller.hintTextDestinationPoint = 'To Work'.tr;
controller.workLocationFromMap = false;
controller.isPickerShown = false;
controller.update();
mySnackbarSuccess('Work Saved'.tr);
return;
}
if (controller.homeLocationFromMap) {
box.write(BoxName.addHome,
'${currentCameraPosition.latitude.toStringAsFixed(4)} , ${currentCameraPosition.longitude.toStringAsFixed(4)}');
controller.hintTextDestinationPoint = 'To Home'.tr;
controller.homeLocationFromMap = false;
controller.isPickerShown = false;
controller.update();
mySnackbarSuccess('Home Saved'.tr);
return;
}
controller.myDestination = currentCameraPosition;
controller.hintTextDestinationPoint =
'${currentCameraPosition.latitude.toStringAsFixed(4)} , ${currentCameraPosition.longitude.toStringAsFixed(4)}';
controller.placesDestination = [];
controller.placeDestinationController.clear();
controller.passengerStartLocationFromMap = true;
controller.isPickerShown = true;
controller.update();
try {
if (controller.isAnotherOreder) {
await controller.mapController?.animateCamera(CameraUpdate.newLatLng(
LatLng(controller.newStartPointLocation.latitude,
controller.newStartPointLocation.longitude)));
} else {
await controller.mapController?.animateCamera(CameraUpdate.newLatLng(
LatLng(controller.passengerLocation.latitude,
controller.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.withAlpha(15),
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 MapPassengerController controller;
final int index;
const _RecentPlaceChip({required this.controller, required this.index});
@override
Widget build(BuildContext context) {
final place = controller.recentPlaces[index];
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
MyDialog().getDialog(
'Are you want to go this site'.tr,
' ',
() async {
Get.back();
await controller.getLocation();
await controller.getDirectionMap(
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
'${place['latitude']},${place['longitude']}');
controller.showBottomSheet1();
},
);
},
borderRadius: BorderRadius.circular(_D.radiusChip),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 7),
decoration: BoxDecoration(
color: AppColor.primaryColor.withOpacity(0.08),
borderRadius: BorderRadius.circular(_D.radiusChip),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.history_rounded,
size: 14, color: AppColor.primaryColor.withOpacity(0.7)),
const SizedBox(width: 7),
Text(place['name'] ?? '',
style: TextStyle(
fontSize: 12.5,
color: AppColor.primaryColor.withOpacity(0.9),
fontWeight: FontWeight.w600)),
],
),
),
),
);
}
}
class _WhatsAppLinkButton extends StatelessWidget {
final MapPassengerController controller;
const _WhatsAppLinkButton({required this.controller});
@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: controller.sosFormKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
MyTextForm(
controller: controller.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: () => controller.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 MapPassengerController controller;
const _OrderTypeButton({required this.controller});
@override
Widget build(BuildContext context) {
final bool isOther = controller.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: () {
controller.changeisAnotherOreder(false);
Navigator.pop(ctx);
},
),
CupertinoActionSheetAction(
child: Text('I want to order for someone else'.tr),
onPressed: () {
controller.changeisAnotherOreder(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.withOpacity(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) {
Get.put(MapPassengerController());
return GetBuilder<MapPassengerController>(
builder: (controller) => 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 controller.getLocation();
await controller.getDirectionMap(
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
'${favoritePlaces[index]['latitude']},${favoritePlaces[index]['longitude']}');
controller.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)),
],
),
),
),
);
}
}