25-7-26-1
This commit is contained in:
408
lib/views/home/map_widget.dart/apply_order_widget.dart
Normal file
408
lib/views/home/map_widget.dart/apply_order_widget.dart
Normal file
@@ -0,0 +1,408 @@
|
||||
import 'package:Intaleq/constant/colors.dart';
|
||||
import 'package:Intaleq/constant/links.dart';
|
||||
import 'package:Intaleq/constant/style.dart';
|
||||
import 'package:Intaleq/controller/firebase/firbase_messge.dart';
|
||||
import 'package:Intaleq/controller/home/map_passenger_controller.dart';
|
||||
import 'package:Intaleq/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../constant/box_name.dart';
|
||||
import '../../../controller/functions/launch.dart';
|
||||
import '../../widgets/my_textField.dart';
|
||||
|
||||
class ApplyOrderWidget extends StatelessWidget {
|
||||
ApplyOrderWidget({super.key});
|
||||
final firebaseMessagesController =
|
||||
Get.isRegistered<FirebaseMessagesController>()
|
||||
? Get.find<FirebaseMessagesController>()
|
||||
: Get.put(FirebaseMessagesController());
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Color _parseColor(String colorHex) {
|
||||
if (colorHex.isEmpty) return Colors.grey;
|
||||
String processedHex = colorHex.replaceFirst('#', '0xff').trim();
|
||||
return Color(int.parse(processedHex.startsWith('0xff')
|
||||
? processedHex
|
||||
: '0xff$processedHex'));
|
||||
}
|
||||
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
Get.put(
|
||||
FirebaseMessagesController()); // Ensure FirebaseMessagesController is initialized
|
||||
if (controller.statusRide == 'Apply' && !controller.isSearchingWindow) {
|
||||
return Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
// More modern BoxDecoration
|
||||
color: Theme.of(context).cardColor,
|
||||
borderRadius:
|
||||
const BorderRadius.vertical(top: Radius.circular(20)),
|
||||
boxShadow: [BoxShadow(blurRadius: 10, color: Colors.black12)],
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_buildPriceInfo(context, controller),
|
||||
const SizedBox(height: 16),
|
||||
_buildDriverInfoCard(context, controller, _parseColor),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const SizedBox();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildPriceInfo(
|
||||
BuildContext context, MapPassengerController controller) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
String message;
|
||||
if (box.read(BoxName.carType) == 'Speed' ||
|
||||
box.read(BoxName.carType) == 'Awfar Car' ||
|
||||
box.read(BoxName.carType) == 'Delivery') {
|
||||
message =
|
||||
'This ride type does not allow changes to the destination or additional stops'
|
||||
.tr;
|
||||
} else {
|
||||
message =
|
||||
'This ride type allows changes, but the price may increase'.tr;
|
||||
}
|
||||
Get.snackbar(
|
||||
'This price is'.tr +
|
||||
' ${controller.totalPassenger.toStringAsFixed(2)}'.tr,
|
||||
message,
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
duration: const Duration(seconds: 2),
|
||||
backgroundColor:
|
||||
AppColor.yellowColor.withOpacity(0.8), // More subtle background
|
||||
);
|
||||
},
|
||||
child: Center(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${'The driver accepted your order for'.tr} ',
|
||||
style: AppStyle.title),
|
||||
TextSpan(
|
||||
text: controller.totalPassenger.toStringAsFixed(2),
|
||||
style: AppStyle.title.copyWith(
|
||||
fontWeight: FontWeight.bold, color: AppColor.redColor),
|
||||
),
|
||||
TextSpan(text: ' ${'LE'.tr}', style: AppStyle.title),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDriverInfoCard(BuildContext context,
|
||||
MapPassengerController controller, Color Function(String) parseColor) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).canvasColor,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: Colors.grey.shade200),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(box.read(BoxName.carType.toString()),
|
||||
style:
|
||||
AppStyle.title.copyWith(fontWeight: FontWeight.w500)),
|
||||
Row(
|
||||
children: [
|
||||
_buildCarDetails(context, controller),
|
||||
const SizedBox(width: 10),
|
||||
_buildCarImage(controller, parseColor),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(height: 1, thickness: 1, color: Colors.grey),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
_buildDriverAvatarAndInfo(controller),
|
||||
_buildContactButtons(context, controller),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 12.0, right: 12.0, bottom: 12.0),
|
||||
child: controller.isDriverArrivePassenger
|
||||
? const DriverArrivePassengerAndWaitMinute()
|
||||
: const TimeDriverToPassenger(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCarDetails(
|
||||
BuildContext context, MapPassengerController controller) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(controller.model.toString(), style: AppStyle.title),
|
||||
Text(controller.licensePlate.toString(),
|
||||
style: Theme.of(context).textTheme.bodyMedium),
|
||||
Text(controller.carColor.toString(),
|
||||
style: Theme.of(context).textTheme.bodyMedium),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCarImage(
|
||||
MapPassengerController controller, Color Function(String) parseColor) {
|
||||
return ColorFiltered(
|
||||
colorFilter:
|
||||
ColorFilter.mode(parseColor(controller.colorHex), BlendMode.srcIn),
|
||||
child: Image.asset(
|
||||
box.read(BoxName.carType) == 'Scooter' ||
|
||||
box.read(BoxName.carType) == 'Pink Bike'
|
||||
? 'assets/images/moto.png'
|
||||
: 'assets/images/car3.png',
|
||||
height: 60,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDriverAvatarAndInfo(MapPassengerController controller) {
|
||||
return Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 30,
|
||||
backgroundImage: NetworkImage(
|
||||
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg'),
|
||||
onBackgroundImageError: (exception, stackTrace) =>
|
||||
const Icon(Icons.person, size: 30, color: AppColor.blueColor),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(controller.driverName,
|
||||
style: AppStyle.title.copyWith(fontWeight: FontWeight.w500)),
|
||||
Text('⭐ ${controller.driverRate}',
|
||||
style: const TextStyle(fontSize: 16, color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildContactButtons(
|
||||
BuildContext context, MapPassengerController controller) {
|
||||
return Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => _showContactOptionsDialog(context, controller),
|
||||
icon: const Icon(Icons.message, color: AppColor.blueColor, size: 28),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
HapticFeedback.heavyImpact();
|
||||
makePhoneCall(controller.driverPhone);
|
||||
},
|
||||
icon: const Icon(Icons.call, color: AppColor.greenColor, size: 28),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _showContactOptionsDialog(
|
||||
BuildContext context, MapPassengerController controller) {
|
||||
Get.defaultDialog(
|
||||
title: 'Contact Options'.tr,
|
||||
content: SizedBox(
|
||||
width: 300,
|
||||
height: Get.height * .4,
|
||||
child: ListView(
|
||||
// shrinkWrap: true,
|
||||
children: [
|
||||
..._buildPredefinedMessages(controller),
|
||||
const SizedBox(height: 8),
|
||||
_buildCustomMessageInput(controller, context),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildPredefinedMessages(MapPassengerController controller) {
|
||||
const messages = [
|
||||
'Hello, I\'m at the agreed-upon location',
|
||||
'My location is correct. You can search for me using the navigation app',
|
||||
'I\'m waiting for you',
|
||||
"How much longer will you be?",
|
||||
];
|
||||
|
||||
return messages
|
||||
.map((message) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
firebaseMessagesController.sendNotificationToDriverMAP(
|
||||
'message From passenger',
|
||||
message.tr,
|
||||
controller.driverToken.toString(),
|
||||
[],
|
||||
'ding.wav',
|
||||
);
|
||||
Get.back();
|
||||
},
|
||||
child: Text(message.tr),
|
||||
),
|
||||
))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Widget _buildCustomMessageInput(
|
||||
MapPassengerController controller, BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Form(
|
||||
key: controller.messagesFormKey,
|
||||
child: MyTextForm(
|
||||
controller: controller.messageToDriver,
|
||||
label: 'Send a custom message'.tr,
|
||||
hint: 'Type your message'.tr,
|
||||
type: TextInputType.text,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
if (controller.messagesFormKey.currentState!.validate()) {
|
||||
firebaseMessagesController.sendNotificationToDriverMAP(
|
||||
'message From passenger',
|
||||
controller.messageToDriver.text,
|
||||
controller.driverToken,
|
||||
[],
|
||||
'ding.wav',
|
||||
);
|
||||
controller.messageToDriver.clear();
|
||||
Get.back();
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.send),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DriverArrivePassengerAndWaitMinute extends StatelessWidget {
|
||||
const DriverArrivePassengerAndWaitMinute({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
return Column(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
child: LinearProgressIndicator(
|
||||
backgroundColor: AppColor.accentColor.withOpacity(0.3),
|
||||
color: controller.remainingTimeDriverWaitPassenger5Minute < 60
|
||||
? AppColor.redColor
|
||||
: AppColor.greenColor,
|
||||
minHeight: 20,
|
||||
value:
|
||||
controller.progressTimerDriverWaitPassenger5Minute.toDouble(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Center(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${'Driver is waiting at pickup.'.tr} ',
|
||||
style: AppStyle.subtitle),
|
||||
TextSpan(
|
||||
text: controller
|
||||
.stringRemainingTimeDriverWaitPassenger5Minute,
|
||||
style: AppStyle.title),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class TimeDriverToPassenger extends StatelessWidget {
|
||||
const TimeDriverToPassenger({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
return controller.isDriverInPassengerWay == false ||
|
||||
controller.timeToPassengerFromDriverAfterApplied > 0
|
||||
? Column(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
child: LinearProgressIndicator(
|
||||
backgroundColor: AppColor.accentColor.withOpacity(0.3),
|
||||
color: controller
|
||||
.remainingTimeToPassengerFromDriverAfterApplied <
|
||||
60
|
||||
? AppColor.redColor
|
||||
: AppColor.greenColor,
|
||||
minHeight: 20,
|
||||
value: controller
|
||||
.progressTimerToPassengerFromDriverAfterApplied
|
||||
.toDouble()
|
||||
.clamp(0.0, 1.0),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Center(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${'Driver is on the way'.tr} ',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
TextSpan(
|
||||
text: controller.stringRemainingTimeToPassenger,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: const SizedBox();
|
||||
});
|
||||
}
|
||||
}
|
||||
560
lib/views/home/map_widget.dart/buttom_sheet_map_show.dart
Normal file
560
lib/views/home/map_widget.dart/buttom_sheet_map_show.dart
Normal file
@@ -0,0 +1,560 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/controller/payment/payment_controller.dart';
|
||||
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
|
||||
GetBuilder<MapPassengerController> buttomSheetMapPage() {
|
||||
Get.put(PaymentController());
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) =>
|
||||
controller.isBottomSheetShown && controller.rideConfirm == false
|
||||
? const Positioned(
|
||||
left: 5,
|
||||
bottom: 0,
|
||||
right: 5,
|
||||
child: Column(
|
||||
// children: [
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.end,
|
||||
// children: [
|
||||
// double.parse(box.read(BoxName.passengerWalletTotal)) <
|
||||
// 0 &&
|
||||
// controller.data.isNotEmpty
|
||||
// ? Container(
|
||||
// decoration: AppStyle.boxDecoration
|
||||
// .copyWith(color: AppColor.redColor),
|
||||
// height: 50,
|
||||
// width: Get.width * .94,
|
||||
// child: Padding(
|
||||
// padding:
|
||||
// const EdgeInsets.symmetric(horizontal: 8),
|
||||
// child: Text(
|
||||
// 'Your trip cost is'.tr +
|
||||
// ' ${controller.totalCostPassenger.toStringAsFixed(2)} '
|
||||
// 'But you have a negative salary of'
|
||||
// .tr +
|
||||
// '${double.parse(box.read(BoxName.passengerWalletTotal)).toStringAsFixed(2)}'
|
||||
// ' in your'
|
||||
// .tr +
|
||||
// ' ${AppInformation.appName}'
|
||||
// ' wallet due to a previous trip.'
|
||||
// .tr,
|
||||
// style: AppStyle.subtitle,
|
||||
// ),
|
||||
// ))
|
||||
// : const SizedBox(),
|
||||
// ],
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// height: 5,
|
||||
// ),
|
||||
// AnimatedContainer(
|
||||
// // clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
// curve: Curves.easeInCirc,
|
||||
// onEnd: () {
|
||||
// controller.height = 250;
|
||||
// },
|
||||
// height: controller.heightBottomSheetShown,
|
||||
// duration: const Duration(seconds: 2),
|
||||
// child: Column(
|
||||
// children: [
|
||||
// controller.data.isEmpty
|
||||
// ? const SizedBox()
|
||||
// : Container(
|
||||
// // width: Get.width * .9,
|
||||
// height: 100,
|
||||
// decoration: BoxDecoration(
|
||||
// color: AppColor.secondaryColor,
|
||||
// boxShadow: [
|
||||
// const BoxShadow(
|
||||
// color: AppColor.accentColor,
|
||||
// offset: Offset(2, 2)),
|
||||
// BoxShadow(
|
||||
// color: AppColor.accentColor
|
||||
// .withOpacity(.4),
|
||||
// offset: const Offset(-2, -2))
|
||||
// ],
|
||||
// borderRadius: const BorderRadius.all(
|
||||
// Radius.circular(15))),
|
||||
// child: ListView.builder(
|
||||
// scrollDirection: Axis.horizontal,
|
||||
// itemCount: controller
|
||||
// .dataCarsLocationByPassenger.length -
|
||||
// 1,
|
||||
// itemBuilder:
|
||||
// (BuildContext context, int index) {
|
||||
// return Container(
|
||||
// color: controller.gender == 'Female'
|
||||
// ? const Color.fromARGB(
|
||||
// 255, 246, 52, 181)
|
||||
// : AppColor.secondaryColor,
|
||||
// width: Get.width,
|
||||
// child: Row(
|
||||
// mainAxisAlignment:
|
||||
// MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// SizedBox(
|
||||
// width: Get.width * .15,
|
||||
// child: Padding(
|
||||
// padding:
|
||||
// const EdgeInsets.all(8.0),
|
||||
// child: Image.asset(
|
||||
// 'assets/images/jeep.png',
|
||||
// width: 50,
|
||||
// fit: BoxFit.fill,
|
||||
// repeat: ImageRepeat.repeatX,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// width: Get.width * .55,
|
||||
// child: Column(
|
||||
// crossAxisAlignment:
|
||||
// CrossAxisAlignment.start,
|
||||
// mainAxisAlignment:
|
||||
// MainAxisAlignment.spaceEvenly,
|
||||
// children: [
|
||||
// Text(
|
||||
// controller.hours > 0
|
||||
// ? '${'Your Ride Duration is '.tr}${controller.hours} ${'H and'.tr} ${controller.minutes} ${'m'.tr}'
|
||||
// : '${'Your Ride Duration is '.tr} ${controller.minutes} m',
|
||||
// style: AppStyle.subtitle,
|
||||
// ),
|
||||
// // Text(
|
||||
// // '${'You will be thier in'.tr} ${DateFormat('h:mm a').format(controller.newTime)}',
|
||||
// // style: AppStyle.subtitle,
|
||||
// // ),
|
||||
// Text(
|
||||
// '${'Your trip distance is'.tr} ${controller.distance.toStringAsFixed(2)} ${'KM'.tr}',
|
||||
// style: AppStyle.subtitle,
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// width: Get.width * .2,
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.only(
|
||||
// right: 5, left: 5),
|
||||
// child: Column(
|
||||
// crossAxisAlignment:
|
||||
// CrossAxisAlignment.center,
|
||||
// children: [
|
||||
// Container(
|
||||
// width: Get.width * .14,
|
||||
// height: Get.height * .06,
|
||||
// decoration: BoxDecoration(
|
||||
// color: AppColor
|
||||
// .secondaryColor,
|
||||
// shape:
|
||||
// BoxShape.rectangle,
|
||||
// border: Border.all(
|
||||
// width: 2,
|
||||
// color: AppColor
|
||||
// .greenColor)),
|
||||
// child: Center(
|
||||
// child: Text(
|
||||
// '${'Fee is'.tr} \n${controller.totalPassenger.toStringAsFixed(2)}',
|
||||
// style:
|
||||
// AppStyle.subtitle,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// controller.promoTaken
|
||||
// ? const Icon(
|
||||
// Icons
|
||||
// .filter_vintage_rounded,
|
||||
// color:
|
||||
// AppColor.redColor,
|
||||
// )
|
||||
// : const SizedBox(
|
||||
// height: 0,
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// height: 5,
|
||||
// ),
|
||||
// Container(
|
||||
// // height: 130,
|
||||
// decoration: BoxDecoration(
|
||||
// color: AppColor.secondaryColor,
|
||||
// boxShadow: [
|
||||
// const BoxShadow(
|
||||
// color: AppColor.accentColor,
|
||||
// offset: Offset(2, 2)),
|
||||
// BoxShadow(
|
||||
// color: AppColor.accentColor.withOpacity(.4),
|
||||
// offset: const Offset(-2, -2))
|
||||
// ],
|
||||
// borderRadius:
|
||||
// const BorderRadius.all(Radius.circular(15))),
|
||||
// child: controller.data.isEmpty
|
||||
// ? const SizedBox()
|
||||
// : Center(
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// horizontal: 5),
|
||||
// child: Column(
|
||||
// children: [
|
||||
// Row(
|
||||
// children: [
|
||||
// const Icon(
|
||||
// Icons.location_on,
|
||||
// color: AppColor.redColor,
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// width: 10,
|
||||
// ),
|
||||
// Text(
|
||||
// 'From : '.tr,
|
||||
// style: AppStyle.subtitle,
|
||||
// ),
|
||||
// Text(
|
||||
// controller.data[0]
|
||||
// ['start_address']
|
||||
// .toString(),
|
||||
// style: AppStyle.subtitle,
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// Row(
|
||||
// children: [
|
||||
// const Icon(Icons
|
||||
// .location_searching_rounded),
|
||||
// const SizedBox(
|
||||
// width: 10,
|
||||
// ),
|
||||
// Text(
|
||||
// 'To : '.tr,
|
||||
// style: AppStyle.subtitle,
|
||||
// ),
|
||||
// Text(
|
||||
// controller.data[0]['end_address'],
|
||||
// style: AppStyle.subtitle,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// const Divider(
|
||||
// color: AppColor.accentColor,
|
||||
// thickness: 1,
|
||||
// height: 2,
|
||||
// indent: 1,
|
||||
// ),
|
||||
// SizedBox(
|
||||
// height: 40,
|
||||
// child: Row(
|
||||
// mainAxisAlignment:
|
||||
// MainAxisAlignment.center,
|
||||
// children: [
|
||||
// Container(
|
||||
// decoration: BoxDecoration(
|
||||
// color:
|
||||
// AppColor.secondaryColor,
|
||||
// borderRadius:
|
||||
// BorderRadius.circular(12),
|
||||
// // border: Border.all(),
|
||||
// ),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Icon(
|
||||
// Icons.monetization_on,
|
||||
// color: Colors.green[400],
|
||||
// ),
|
||||
// InkWell(
|
||||
// onTap: () async {
|
||||
// controller
|
||||
// .changeCashConfirmPageShown();
|
||||
// Get.find<
|
||||
// PaymentController>()
|
||||
// .getPassengerWallet();
|
||||
// },
|
||||
// child: GetBuilder<
|
||||
// PaymentController>(
|
||||
// builder: (paymentController) =>
|
||||
// paymentController
|
||||
// .isCashChecked
|
||||
// ? Text(
|
||||
// 'CASH',
|
||||
// style: AppStyle
|
||||
// .title,
|
||||
// )
|
||||
// : Text(
|
||||
// '${AppInformation.appName} Wallet',
|
||||
// style: AppStyle
|
||||
// .title,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// width: 40,
|
||||
// ),
|
||||
// GetBuilder<PaymentController>(
|
||||
// builder:
|
||||
// (paymentController) =>
|
||||
// Container(
|
||||
// decoration:
|
||||
// BoxDecoration(
|
||||
// color: AppColor
|
||||
// .secondaryColor,
|
||||
// borderRadius:
|
||||
// BorderRadius
|
||||
// .circular(
|
||||
// 12),
|
||||
// ),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Icon(
|
||||
// Icons
|
||||
// .qr_code_2_rounded,
|
||||
// color: Colors
|
||||
// .green[
|
||||
// 400],
|
||||
// ),
|
||||
// InkWell(
|
||||
// onTap: () {
|
||||
// if (controller
|
||||
// .promoTaken ==
|
||||
// false) {
|
||||
// Get.defaultDialog(
|
||||
// title: 'Add Promo'.tr,
|
||||
// titleStyle: AppStyle.title,
|
||||
// content: Column(
|
||||
// children: [
|
||||
// SizedBox(
|
||||
// width: Get.width * .7,
|
||||
// child: TextFormField(
|
||||
// controller: controller.promo,
|
||||
// decoration: InputDecoration(
|
||||
// labelText: 'Promo Code'.tr,
|
||||
// hintText: 'Enter promo code'.tr,
|
||||
// labelStyle: AppStyle.subtitle,
|
||||
// hintStyle: AppStyle.subtitle,
|
||||
// border: OutlineInputBorder(
|
||||
// borderRadius: BorderRadius.circular(10),
|
||||
// ),
|
||||
// filled: true,
|
||||
// fillColor: Colors.grey[200],
|
||||
// focusedBorder: OutlineInputBorder(
|
||||
// borderSide: const BorderSide(
|
||||
// color: AppColor.primaryColor,
|
||||
// width: 2.0,
|
||||
// ),
|
||||
// borderRadius: BorderRadius.circular(10),
|
||||
// ),
|
||||
// errorBorder: OutlineInputBorder(
|
||||
// borderSide: const BorderSide(
|
||||
// color: Colors.red,
|
||||
// width: 2.0,
|
||||
// ),
|
||||
// borderRadius: BorderRadius.circular(10),
|
||||
// ),
|
||||
// enabledBorder: OutlineInputBorder(
|
||||
// borderSide: const BorderSide(
|
||||
// color: Colors.grey,
|
||||
// width: 1.0,
|
||||
// ),
|
||||
// borderRadius: BorderRadius.circular(10),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// MyElevatedButton(
|
||||
// title: 'Add Promo'.tr,
|
||||
// onPressed: () async {
|
||||
// controller.applyPromoCodeToPassenger();
|
||||
// },
|
||||
// )
|
||||
// ],
|
||||
// ));
|
||||
// } else {
|
||||
// Get.snackbar(
|
||||
// 'You have promo!'
|
||||
// .tr,
|
||||
// '',
|
||||
// backgroundColor:
|
||||
// AppColor.redColor);
|
||||
// }
|
||||
// },
|
||||
// child: Text(
|
||||
// 'Add Promo'
|
||||
// .tr,
|
||||
// style: AppStyle
|
||||
// .title,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// )),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// width: Get.width * .95,
|
||||
// child: Row(
|
||||
// mainAxisAlignment:
|
||||
// MainAxisAlignment.center,
|
||||
// children: [
|
||||
// controller.isCashSelectedBeforeConfirmRide ==
|
||||
// false
|
||||
// ? MyElevatedButton(
|
||||
// title: 'Next'.tr,
|
||||
// onPressed: () {
|
||||
// controller
|
||||
// .changeCashConfirmPageShown();
|
||||
// },
|
||||
// )
|
||||
// :
|
||||
// // controller.isPassengerChosen ==
|
||||
// // false
|
||||
// // ? MyElevatedButton(
|
||||
// // title: 'Next'.tr,
|
||||
// // onPressed: () {
|
||||
// // controller
|
||||
// // .onChangedPassengersChoose();
|
||||
// // Get.defaultDialog(
|
||||
// // barrierDismissible:
|
||||
// // false,
|
||||
// // title:
|
||||
// // 'How Many Passengers?'
|
||||
// // .tr,
|
||||
// // titleStyle:
|
||||
// // AppStyle
|
||||
// // .title,
|
||||
// // content:
|
||||
// // Column(
|
||||
// // children: [
|
||||
// // Text(
|
||||
// // 'Allowed up to 4 Passengers.'
|
||||
// // .tr,
|
||||
// // style: AppStyle
|
||||
// // .title,
|
||||
// // ),
|
||||
// // SizedBox(
|
||||
// // height:
|
||||
// // 200, // Set the desired height here
|
||||
// // child:
|
||||
// // CupertinoPicker(
|
||||
// // itemExtent:
|
||||
// // 32,
|
||||
// // onSelectedItemChanged:
|
||||
// // (index) {
|
||||
// // controller.onChangedPassengerCount(index +
|
||||
// // 1);
|
||||
// // },
|
||||
// // children: [
|
||||
// // Text('1 Passenger'.tr),
|
||||
// // Text('2 Passengers'.tr),
|
||||
// // Text('3 Passengers'.tr),
|
||||
// // Text('4 Passengers'.tr),
|
||||
// // ],
|
||||
// // ),
|
||||
// // ),
|
||||
// // MyElevatedButton(
|
||||
// // title:
|
||||
// // 'Back',
|
||||
// // onPressed:
|
||||
// // () =>
|
||||
// // Get.back(),
|
||||
// // )
|
||||
// // ],
|
||||
// // ),
|
||||
// // );
|
||||
// // },
|
||||
// // )
|
||||
// // :
|
||||
// MyElevatedButton(
|
||||
// title: 'Confirm Selection'
|
||||
// .tr,
|
||||
// onPressed: () {
|
||||
// controller
|
||||
// .confirmRideForFirstDriver();
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
),
|
||||
)
|
||||
: const SizedBox());
|
||||
}
|
||||
|
||||
class Details extends StatelessWidget {
|
||||
const Details({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Text(
|
||||
'${'Distance is'.tr} ${controller.data[0]['distance']['text']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'${'Duration is'.tr} ${controller.data[0]['duration']['text']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Text(
|
||||
'Cost for .21/km ${controller.costDistance.toStringAsFixed(2)} ',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'${'Cost Duration'.tr} ${controller.averageDuration.toStringAsFixed(2)} is ${controller.costDuration.toStringAsFixed(2)} ',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Text(
|
||||
'Total Driver ${controller.totalDriver.toStringAsFixed(2)}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'totaME ${controller.totalME.toStringAsFixed(2)} ',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'Cost for passenger ${controller.totalPassenger.toStringAsFixed(2)} ',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
258
lib/views/home/map_widget.dart/call_passenger_page.dart
Normal file
258
lib/views/home/map_widget.dart/call_passenger_page.dart
Normal file
@@ -0,0 +1,258 @@
|
||||
// import 'dart:async';
|
||||
// import 'package:SEFER/constant/box_name.dart';
|
||||
// import 'package:SEFER/controller/home/map_passenger_controller.dart';
|
||||
// import 'package:SEFER/main.dart';
|
||||
// import 'package:SEFER/views/widgets/my_scafold.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:get/get.dart';
|
||||
// import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
// import 'package:agora_rtc_engine/agora_rtc_engine.dart';
|
||||
|
||||
// import '../../../../constant/api_key.dart';
|
||||
// import '../../../constant/colors.dart';
|
||||
// import '../../../constant/style.dart';
|
||||
// import '../../../controller/firebase/firbase_messge.dart';
|
||||
|
||||
// String appId = AK.agoraAppId;
|
||||
|
||||
// class PassengerCallPage extends StatefulWidget {
|
||||
// const PassengerCallPage({
|
||||
// super.key,
|
||||
// required this.channelName,
|
||||
// required this.token,
|
||||
// required this.remoteID,
|
||||
// });
|
||||
// final String channelName, token, remoteID;
|
||||
// @override
|
||||
// State<PassengerCallPage> createState() => _PassengerCallPageState();
|
||||
// }
|
||||
|
||||
// class _PassengerCallPageState extends State<PassengerCallPage> {
|
||||
// int uid = 0;
|
||||
// int? _remoteUid = 0; // uid of the remote user
|
||||
// bool _isJoined = false; // Indicates if the local user has joined the channel
|
||||
// late RtcEngine agoraEngine; // Agora engine instance
|
||||
// String status = '';
|
||||
// final GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey =
|
||||
// GlobalKey<ScaffoldMessengerState>(); // Global key to access the scaffold
|
||||
|
||||
// showMessage(String message) {
|
||||
// scaffoldMessengerKey.currentState?.showSnackBar(SnackBar(
|
||||
// content: Text(message),
|
||||
// ));
|
||||
// }
|
||||
|
||||
// initAgora() async {
|
||||
// await setupVoiceSDKEngine();
|
||||
// }
|
||||
|
||||
// @override
|
||||
// void initState() {
|
||||
// super.initState();
|
||||
// _remoteUid = int.parse(widget.remoteID);
|
||||
// uid = int.parse(box.read(BoxName.phone));
|
||||
// // Set up an instance of Agora engine
|
||||
// initAgora();
|
||||
// }
|
||||
|
||||
// Future<void> setupVoiceSDKEngine() async {
|
||||
// // retrieve or request microphone permission
|
||||
// await [Permission.microphone].request();
|
||||
|
||||
// //create an instance of the Agora engine
|
||||
// agoraEngine = createAgoraRtcEngine();
|
||||
// await agoraEngine.initialize(RtcEngineContext(appId: AK.agoraAppId));
|
||||
// // Register the event handler
|
||||
// agoraEngine.registerEventHandler(
|
||||
// RtcEngineEventHandler(
|
||||
// onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
|
||||
// showMessage(
|
||||
// "Local user uid:${connection.localUid} joined the channel");
|
||||
// setState(() {
|
||||
// _isJoined = true;
|
||||
// status = 'joined'.tr;
|
||||
// });
|
||||
// },
|
||||
// onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
|
||||
// showMessage("Driver joined the channel".tr);
|
||||
// setState(() {
|
||||
// status = "Driver joined the channel".tr;
|
||||
// _remoteUid = remoteUid;
|
||||
// });
|
||||
// },
|
||||
// onUserOffline: (RtcConnection connection, int? remoteUid,
|
||||
// UserOfflineReasonType reason) {
|
||||
// showMessage("Driver left the channel".tr);
|
||||
// setState(() {
|
||||
// status = "Driver left the channel".tr;
|
||||
// _remoteUid = null;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
// void join() async {
|
||||
// // Set channel options including the client role and channel profile
|
||||
// ChannelMediaOptions options = const ChannelMediaOptions(
|
||||
// clientRoleType: ClientRoleType.clientRoleBroadcaster,
|
||||
// channelProfile: ChannelProfileType.channelProfileCommunication,
|
||||
// );
|
||||
|
||||
// await agoraEngine.joinChannel(
|
||||
// token: widget.token,
|
||||
// channelId: widget.channelName,
|
||||
// options: options,
|
||||
// uid: uid,
|
||||
// );
|
||||
// }
|
||||
// //https://console.agora.io/invite?sign=5e9e22d06f22caeeada9954c9e908572%253A5ba8aed978a35eab5a5113742502ded2a41478b2a81cb19c71a30776e125b58a
|
||||
|
||||
// void leave() {
|
||||
// setState(() {
|
||||
// _isJoined = false;
|
||||
// _remoteUid = null;
|
||||
// });
|
||||
// agoraEngine.leaveChannel();
|
||||
// }
|
||||
|
||||
// // Clean up the resources when you leave
|
||||
// @override
|
||||
// void dispose() async {
|
||||
// await agoraEngine.leaveChannel();
|
||||
// super.dispose();
|
||||
// }
|
||||
|
||||
// // Build UI
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return MaterialApp(
|
||||
// scaffoldMessengerKey: scaffoldMessengerKey,
|
||||
// home: MyScafolld(
|
||||
// // appBar: AppBar(
|
||||
// // title: const Text('Get started with Voice Calling'),
|
||||
// // ),
|
||||
// title: 'Call Page'.tr,
|
||||
// isleading: true,
|
||||
// body: [
|
||||
// Positioned(
|
||||
// top: Get.height * .2,
|
||||
// child: Container(
|
||||
// height: 100, width: Get.width,
|
||||
// decoration: AppStyle.boxDecoration,
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
// children: [
|
||||
// GestureDetector(
|
||||
// onTap: () async {
|
||||
// // await callController.initAgoraFull();
|
||||
// // callController.join();
|
||||
// // FirebaseMessagesController().sendNotificationToPassengerToken(
|
||||
// // 'Call Income',
|
||||
// // '${'You have call from driver'.tr} ${box.read(BoxName.nameDriver)}',
|
||||
// // Get.find<MapDriverController>().tokenPassenger,
|
||||
// // [
|
||||
// // callController.token,
|
||||
// // callController.channelName,
|
||||
// // callController.uid.toString(),
|
||||
// // callController.remoteUid.toString(),
|
||||
// // ],
|
||||
// // );
|
||||
// join();
|
||||
// // callController.fetchToken();
|
||||
// },
|
||||
// child: Container(
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// decoration: const BoxDecoration(
|
||||
// shape: BoxShape.circle,
|
||||
// color: AppColor.greenColor),
|
||||
// child: const Icon(
|
||||
// Icons.phone,
|
||||
// size: 35,
|
||||
// color: AppColor.secondaryColor,
|
||||
// )),
|
||||
// ),
|
||||
// Column(
|
||||
// children: [
|
||||
// Text(
|
||||
// status,
|
||||
// style: AppStyle.title,
|
||||
// ),
|
||||
// Text('Driver Name'),
|
||||
// ],
|
||||
// ),
|
||||
// GestureDetector(
|
||||
// onTap: () async {
|
||||
// FirebaseMessagesController()
|
||||
// .sendNotificationToPassengerToken(
|
||||
// 'Call End'.tr,
|
||||
// 'Call End',
|
||||
// Get.find<MapPassengerController>().driverToken,
|
||||
// [],
|
||||
// 'iphone_ringtone.wav',
|
||||
// );
|
||||
// leave();
|
||||
// Get.back();
|
||||
// // },
|
||||
// child: Container(
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// decoration: const BoxDecoration(
|
||||
// shape: BoxShape.circle, color: AppColor.redColor),
|
||||
// child: const Icon(
|
||||
// Icons.phone_disabled_sharp,
|
||||
// size: 35,
|
||||
// color: AppColor.secondaryColor,
|
||||
// )),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// // ignore: prefer_const_constructors
|
||||
// ),
|
||||
// ),
|
||||
// // ListView(
|
||||
// // padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
// // children: [
|
||||
// // // Status text
|
||||
// // Container(height: 40, child: Center(child: _status())),
|
||||
// // // Button Row
|
||||
// // Row(
|
||||
// // children: <Widget>[
|
||||
// // Expanded(
|
||||
// // child: ElevatedButton(
|
||||
// // child: Text("Join".tr),
|
||||
// // onPressed: () => {join()},
|
||||
// // ),
|
||||
// // ),
|
||||
// // const SizedBox(width: 10),
|
||||
// // Expanded(
|
||||
// // child: ElevatedButton(
|
||||
// // child: Text("Leave".tr),
|
||||
// // onPressed: () => {leave()},
|
||||
// // ),
|
||||
// // ),
|
||||
// // ],
|
||||
// // ),
|
||||
// // ],
|
||||
// // ),
|
||||
// ]),
|
||||
// );
|
||||
// }
|
||||
|
||||
// // Widget _status() {
|
||||
// // String statusText;
|
||||
// //
|
||||
// // if (!_isJoined) {
|
||||
// // statusText = 'Join a channel'.tr;
|
||||
// // } else if (_remoteUid == null)
|
||||
// // statusText = 'Waiting for a remote user to join...';
|
||||
// // else
|
||||
// // statusText = 'Connected to remote user, uid:$_remoteUid';
|
||||
// //
|
||||
// // return Text(
|
||||
// // statusText,
|
||||
// // );
|
||||
// // }
|
||||
// }
|
||||
101
lib/views/home/map_widget.dart/cancel_raide_page.dart
Normal file
101
lib/views/home/map_widget.dart/cancel_raide_page.dart
Normal file
@@ -0,0 +1,101 @@
|
||||
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 '../../widgets/elevated_btn.dart';
|
||||
|
||||
void showCancelRideBottomSheet() {
|
||||
Get.bottomSheet(
|
||||
cancelRidePage(),
|
||||
backgroundColor: Colors.transparent,
|
||||
isScrollControlled: true,
|
||||
);
|
||||
}
|
||||
|
||||
GetBuilder<MapPassengerController> cancelRidePage() {
|
||||
Get.put(MapPassengerController());
|
||||
|
||||
final List<String> reasons = [
|
||||
"I don't need a ride anymore".tr,
|
||||
"I was just trying the application".tr,
|
||||
"No driver accepted my request".tr,
|
||||
"I added the wrong pick-up/drop-off location".tr,
|
||||
"I don't have a reason".tr,
|
||||
"Other".tr,
|
||||
];
|
||||
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => controller.isCancelRidePageShown
|
||||
? Container(
|
||||
height: Get.height * 0.6,
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
offset: const Offset(0, 8),
|
||||
blurRadius: 16,
|
||||
),
|
||||
],
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Can we know why you want to cancel Ride ?'.tr,
|
||||
style: AppStyle.title
|
||||
.copyWith(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Expanded(
|
||||
child: ListView.separated(
|
||||
itemCount: reasons.length,
|
||||
separatorBuilder: (context, index) => const Divider(),
|
||||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
title: Text(
|
||||
reasons[index],
|
||||
style: AppStyle.title.copyWith(fontSize: 16),
|
||||
),
|
||||
leading: Radio(
|
||||
value: index,
|
||||
groupValue: controller.selectedReason,
|
||||
onChanged: (int? value) {
|
||||
controller.selectReason(value!, reasons[index]);
|
||||
},
|
||||
activeColor: AppColor.primaryColor,
|
||||
),
|
||||
onTap: () {
|
||||
controller.selectReason(index, reasons[index]);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
MyElevatedButton(
|
||||
title: 'Cancel Ride'.tr,
|
||||
onPressed: () {
|
||||
if (controller.selectedReason == -1) {
|
||||
Get.snackbar(
|
||||
'You Should be select reason.'.tr,
|
||||
'',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: AppColor.redColor,
|
||||
colorText: Colors.white,
|
||||
);
|
||||
} else {
|
||||
controller.cancelRide();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
);
|
||||
}
|
||||
668
lib/views/home/map_widget.dart/car_details_widget_to_go.dart
Normal file
668
lib/views/home/map_widget.dart/car_details_widget_to_go.dart
Normal file
@@ -0,0 +1,668 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/constant/box_name.dart';
|
||||
import 'package:Intaleq/constant/colors.dart';
|
||||
import 'package:Intaleq/constant/style.dart';
|
||||
import 'package:Intaleq/main.dart';
|
||||
import 'package:Intaleq/views/home/profile/passenger_profile_page.dart';
|
||||
import 'package:Intaleq/views/widgets/elevated_btn.dart';
|
||||
import 'package:Intaleq/views/widgets/my_textField.dart';
|
||||
import 'dart:ui';
|
||||
|
||||
import '../../../constant/info.dart';
|
||||
import '../../../controller/functions/tts.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../../print.dart';
|
||||
import '../../widgets/mydialoug.dart';
|
||||
|
||||
// --- CarType class (unchanged) ---
|
||||
class CarType {
|
||||
final String carType;
|
||||
final String carDetail;
|
||||
final String image;
|
||||
bool isSelected = false;
|
||||
|
||||
CarType(
|
||||
{required this.carType, required this.carDetail, required this.image});
|
||||
}
|
||||
|
||||
// --- List of Car Types with NEW order and 'Electric' car ---
|
||||
List<CarType> carTypes = [
|
||||
CarType(
|
||||
carType: 'Speed',
|
||||
carDetail: 'Closest & Cheapest'.tr,
|
||||
image: 'assets/images/carspeed.png'), // First choice
|
||||
CarType(
|
||||
carType: 'Comfort',
|
||||
carDetail: 'Comfort choice'.tr,
|
||||
image: 'assets/images/blob.png'), // Second choice
|
||||
CarType(
|
||||
carType: 'Electric',
|
||||
carDetail: 'Quiet & Eco-Friendly'.tr,
|
||||
image:
|
||||
'assets/images/electric_car.jpg'), // Third choice - NOTE: Use your actual image path
|
||||
CarType(
|
||||
carType: 'Lady',
|
||||
carDetail: 'Lady Captain for girls'.tr,
|
||||
image: 'assets/images/lady.png'),
|
||||
CarType(
|
||||
carType: 'Scooter',
|
||||
carDetail: 'Delivery service'.tr,
|
||||
image: 'assets/images/moto.png'),
|
||||
CarType(
|
||||
carType: 'Rayeh Gai',
|
||||
carDetail: "Best choice for cities".tr,
|
||||
image: 'assets/images/roundtrip.png'),
|
||||
];
|
||||
|
||||
// --- Main Widget ---
|
||||
class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
CarDetailsTypeToChoose({super.key});
|
||||
final textToSpeechController = Get.put(TextToSpeechController());
|
||||
|
||||
void _prepareCarTypes(MapPassengerController controller) {
|
||||
if (controller.distance > 33) {
|
||||
if (!carTypes.any((car) => car.carType == 'Rayeh Gai')) {
|
||||
carTypes.add(CarType(
|
||||
carType: 'Rayeh Gai',
|
||||
carDetail: "Best choice for cities".tr,
|
||||
image: 'assets/images/roundtrip.png'));
|
||||
}
|
||||
} else {
|
||||
carTypes.removeWhere((car) => car.carType == 'Rayeh Gai');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
_prepareCarTypes(controller);
|
||||
|
||||
if (!(controller.data.isNotEmpty &&
|
||||
controller.isBottomSheetShown &&
|
||||
controller.rideConfirm == false)) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.secondaryColor,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(24),
|
||||
topRight: Radius.circular(24),
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
blurRadius: 20,
|
||||
spreadRadius: 5,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_buildHeader(controller),
|
||||
const Divider(height: 1),
|
||||
_buildNegativeBalanceWarning(controller),
|
||||
SizedBox(
|
||||
height: 130,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
itemCount: carTypes.length,
|
||||
itemBuilder: (context, index) {
|
||||
final carType = carTypes[index];
|
||||
final isSelected = controller.selectedIndex == index;
|
||||
return _buildHorizontalCarCard(
|
||||
context, controller, carType, isSelected, index);
|
||||
},
|
||||
),
|
||||
),
|
||||
_buildPromoButton(context, controller),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// --- All other methods are here, with updates for 'Electric' car ---
|
||||
|
||||
Widget _buildPromoButton(
|
||||
BuildContext context, MapPassengerController controller) {
|
||||
if (controller.promoTaken) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: OutlinedButton(
|
||||
onPressed: () => _showPromoCodeDialog(context, controller),
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
backgroundColor: AppColor.primaryColor.withOpacity(0.05),
|
||||
side: BorderSide(
|
||||
color: AppColor.primaryColor.withOpacity(0.7),
|
||||
width: 1.5,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.local_offer_outlined,
|
||||
color: AppColor.primaryColor, size: 20),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Have a promo code?'.tr,
|
||||
style: AppStyle.title
|
||||
.copyWith(fontSize: 16, color: AppColor.primaryColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showPromoCodeDialog(
|
||||
BuildContext context, MapPassengerController controller) {
|
||||
Get.dialog(
|
||||
Dialog(
|
||||
shape:
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
|
||||
backgroundColor: AppColor.secondaryColor,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: Form(
|
||||
key: controller.promoFormKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
'Apply Promo Code'.tr,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.headTitle.copyWith(fontSize: 22),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Enter your code below to apply the discount.'.tr,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.subtitle
|
||||
.copyWith(color: AppColor.writeColor.withOpacity(0.7)),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
MyTextForm(
|
||||
controller: controller.promo,
|
||||
label: 'Promo Code'.tr,
|
||||
hint: 'Enter your promo code'.tr,
|
||||
type: TextInputType.text,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
onPressed: () => Get.back(),
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: AppColor.writeColor,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12)),
|
||||
side: BorderSide(
|
||||
color: AppColor.writeColor.withOpacity(0.3)),
|
||||
),
|
||||
child: Text('Cancel'.tr),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: MyElevatedButton(
|
||||
title: 'Apply'.tr,
|
||||
onPressed: () {
|
||||
if (controller.promoFormKey.currentState!
|
||||
.validate()) {
|
||||
controller.applyPromoCodeToPassenger(context);
|
||||
Get.back();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
barrierColor: Colors.black.withOpacity(0.5),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHorizontalCarCard(
|
||||
BuildContext context,
|
||||
MapPassengerController controller,
|
||||
CarType carType,
|
||||
bool isSelected,
|
||||
int index) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
controller.selectCarFromList(index);
|
||||
_showCarDetailsDialog(
|
||||
context, controller, carType, textToSpeechController);
|
||||
},
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
width: 110,
|
||||
margin: const EdgeInsets.only(right: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? AppColor.primaryColor.withOpacity(0.15)
|
||||
: AppColor.writeColor.withOpacity(0.05),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: isSelected ? AppColor.primaryColor : Colors.transparent,
|
||||
width: 2.0,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(carType.image, height: 50),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
carType.carType.tr,
|
||||
style: AppStyle.subtitle
|
||||
.copyWith(fontWeight: FontWeight.bold, fontSize: 14),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
_buildPriceDisplay(controller, carType),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeader(MapPassengerController controller) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 16, 20, 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Choose your ride'.tr,
|
||||
style: AppStyle.headTitle.copyWith(fontSize: 22)),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'${controller.distance} ${'KM'.tr} • ${controller.hours > 0 ? '${controller.hours}h ${controller.minutes}m' : '${controller.minutes} min'}',
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
color: AppColor.primaryColor, fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNegativeBalanceWarning(MapPassengerController controller) {
|
||||
final passengerWallet =
|
||||
double.tryParse(box.read(BoxName.passengerWalletTotal) ?? '0.0') ?? 0.0;
|
||||
if (passengerWallet < 0.0) {
|
||||
return Container(
|
||||
color: AppColor.redColor.withOpacity(0.8),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.error_outline, color: Colors.white, size: 24),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${'You have a negative balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${'SYP'.tr}.',
|
||||
style: AppStyle.subtitle.copyWith(color: Colors.white))),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
Widget _buildPriceDisplay(
|
||||
MapPassengerController mapPassengerController, CarType carType) {
|
||||
return Text(
|
||||
'${_getPassengerPriceText(carType, mapPassengerController)} ${'SYP'.tr}',
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColor.primaryColor));
|
||||
}
|
||||
|
||||
// UPDATED to include 'Electric'
|
||||
String _getPassengerPriceText(
|
||||
CarType carType, MapPassengerController mapPassengerController) {
|
||||
switch (carType.carType) {
|
||||
case 'Comfort':
|
||||
return mapPassengerController.totalPassengerComfort.toStringAsFixed(1);
|
||||
case 'Speed':
|
||||
return mapPassengerController.totalPassengerSpeed.toStringAsFixed(1);
|
||||
case 'Electric':
|
||||
return mapPassengerController.totalPassengerElectric.toStringAsFixed(1);
|
||||
case 'Awfar Car':
|
||||
return mapPassengerController.totalPassengerBalash.toStringAsFixed(1);
|
||||
case 'Scooter':
|
||||
return mapPassengerController.totalPassengerScooter.toStringAsFixed(1);
|
||||
case 'Lady':
|
||||
return mapPassengerController.totalPassengerLady.toStringAsFixed(1);
|
||||
case 'Pink Bike':
|
||||
return mapPassengerController.totalPassengerScooter.toStringAsFixed(1);
|
||||
case 'Rayeh Gai':
|
||||
return mapPassengerController.totalPassengerRayehGai.toStringAsFixed(1);
|
||||
default:
|
||||
return '...';
|
||||
}
|
||||
}
|
||||
|
||||
void _showCarDetailsDialog(
|
||||
BuildContext context,
|
||||
MapPassengerController mapPassengerController,
|
||||
CarType carType,
|
||||
TextToSpeechController textToSpeechController) {
|
||||
Get.dialog(
|
||||
Dialog(
|
||||
shape:
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(24.0)),
|
||||
backgroundColor: AppColor.secondaryColor,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 24, 20, 20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Image.asset(carType.image, height: 70),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
carType.carType.tr,
|
||||
style: AppStyle.headTitle.copyWith(fontSize: 22),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
IconButton(
|
||||
onPressed: () => textToSpeechController.speakText(
|
||||
_getCarDescription(mapPassengerController, carType)),
|
||||
icon: Icon(Icons.volume_up_outlined,
|
||||
color: AppColor.primaryColor, size: 24),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
_getCarDescription(mapPassengerController, carType),
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
color: AppColor.writeColor.withOpacity(0.7),
|
||||
fontSize: 15,
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: AppColor.writeColor.withOpacity(0.8),
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12)),
|
||||
),
|
||||
child: Text('Cancel'.tr),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: MyElevatedButton(
|
||||
kolor: AppColor.greenColor,
|
||||
title: 'Next'.tr,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
_handleCarSelection(
|
||||
context, mapPassengerController, carType);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
barrierColor: Colors.black.withOpacity(0.5),
|
||||
);
|
||||
}
|
||||
|
||||
// UPDATED to include 'Electric'
|
||||
String _getCarDescription(
|
||||
MapPassengerController mapPassengerController, CarType carType) {
|
||||
switch (carType.carType) {
|
||||
case 'Comfort':
|
||||
return mapPassengerController.endNameAddress
|
||||
.toLowerCase()
|
||||
.contains("airport".tr)
|
||||
? "Best choice for a comfortable car with a flexible route and stop points. This airport offers visa entry at this price."
|
||||
.tr
|
||||
: 'Best choice for comfort car and flexible route and stops point'
|
||||
.tr;
|
||||
case 'Speed':
|
||||
return 'This trip goes directly from your starting point to your destination for a fixed price. The driver must follow the planned route'
|
||||
.tr;
|
||||
case 'Electric':
|
||||
return 'Travel in a modern, silent electric car. A premium, eco-friendly choice for a smooth ride.'
|
||||
.tr;
|
||||
case 'Scooter':
|
||||
case 'Pink Bike':
|
||||
return 'This is for delivery or a motorcycle.'.tr;
|
||||
case 'Mishwar Vip':
|
||||
return "Perfect for passengers seeking the latest car models with the freedom to choose any route they desire"
|
||||
.tr;
|
||||
case 'Awfar Car':
|
||||
return "Old and affordable, perfect for budget rides.".tr;
|
||||
case 'Lady':
|
||||
return "This trip is for women only".tr;
|
||||
case 'Rayeh Gai':
|
||||
return "Rayeh Gai: Round trip service for convenient travel between cities, easy and reliable."
|
||||
.tr;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
void _handleCarSelection(BuildContext context,
|
||||
MapPassengerController mapPassengerController, CarType carType) {
|
||||
box.write(BoxName.carType, carType.carType);
|
||||
mapPassengerController.totalPassenger =
|
||||
_getOriginalPrice(carType, mapPassengerController);
|
||||
if (carType.carType == 'Mishwar Vip') {
|
||||
Get.back();
|
||||
mapPassengerController.mishwariOption();
|
||||
} else if (carType.carType == 'Lady') {
|
||||
if (box.read(BoxName.gender).toString() != '') {
|
||||
mapPassengerController.isBottomSheetShown = false;
|
||||
mapPassengerController.update();
|
||||
mapPassengerController.changeCashConfirmPageShown();
|
||||
} else {
|
||||
MyDialog().getDialog('Idintify gender',
|
||||
'You should ideintify your gender for this type of trip!'.tr, () {
|
||||
Get.to(() => PassengerProfilePage());
|
||||
});
|
||||
}
|
||||
} else if (carType.carType == 'Rayeh Gai') {
|
||||
Get.defaultDialog(
|
||||
barrierDismissible: false,
|
||||
title: "Select betweeen types".tr,
|
||||
content:
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
_buildRayehGaiOption(mapPassengerController, 'Awfar Car',
|
||||
mapPassengerController.totalPassengerRayehGaiBalash),
|
||||
_buildRayehGaiOption(mapPassengerController, 'Speed',
|
||||
mapPassengerController.totalPassengerRayehGai),
|
||||
_buildRayehGaiOption(mapPassengerController, 'Comfort',
|
||||
mapPassengerController.totalPassengerRayehGaiComfort)
|
||||
]),
|
||||
cancel: MyElevatedButton(
|
||||
kolor: AppColor.redColor,
|
||||
title: 'Cancel'.tr,
|
||||
onPressed: () => Get.back()),
|
||||
confirm: MyElevatedButton(
|
||||
kolor: AppColor.greenColor,
|
||||
title: 'Next'.tr,
|
||||
onPressed: () {
|
||||
mapPassengerController.isBottomSheetShown = false;
|
||||
mapPassengerController.update();
|
||||
mapPassengerController.changeCashConfirmPageShown();
|
||||
}));
|
||||
} else {
|
||||
mapPassengerController.isBottomSheetShown = false;
|
||||
mapPassengerController.update();
|
||||
mapPassengerController.changeCashConfirmPageShown();
|
||||
}
|
||||
}
|
||||
|
||||
// UPDATED to include 'Electric'
|
||||
double _getOriginalPrice(
|
||||
CarType carType, MapPassengerController mapPassengerController) {
|
||||
switch (carType.carType) {
|
||||
case 'Comfort':
|
||||
return mapPassengerController.totalPassengerComfort;
|
||||
case 'Speed':
|
||||
return mapPassengerController.totalPassengerSpeed;
|
||||
case 'Electric':
|
||||
return mapPassengerController.totalPassengerElectric;
|
||||
case 'Awfar Car':
|
||||
return mapPassengerController.totalPassengerBalash;
|
||||
case 'Lady':
|
||||
return mapPassengerController.totalPassengerLady;
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildRayehGaiOption(MapPassengerController mapPassengerController,
|
||||
String carTypeName, double price) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Get.back();
|
||||
mapPassengerController.totalPassenger = price;
|
||||
mapPassengerController.isBottomSheetShown = false;
|
||||
mapPassengerController.update();
|
||||
mapPassengerController.changeCashConfirmPageShown();
|
||||
},
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(children: [
|
||||
Text(carTypeName.tr),
|
||||
Text(price.toStringAsFixed(0))
|
||||
])),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BurcMoney extends StatelessWidget {
|
||||
const BurcMoney({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (mapPassengerController) {
|
||||
final passengerWallet =
|
||||
double.tryParse(box.read(BoxName.passengerWalletTotal) ?? '0.0') ??
|
||||
0.0;
|
||||
|
||||
return mapPassengerController.data.isNotEmpty &&
|
||||
mapPassengerController.isBottomSheetShown &&
|
||||
!mapPassengerController.rideConfirm &&
|
||||
passengerWallet < 0.0
|
||||
? Positioned(
|
||||
bottom: Get.height * .41,
|
||||
left: 16,
|
||||
right: 16,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.redColor.withOpacity(0.8),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${'Negative Balance:'.tr} ',
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
'${'You have a balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${box.read(BoxName.countryCode) == 'Egypt' ? 'LE'.tr : 'SYP'.tr} ${'due to a previous trip.'.tr}',
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTap: () async =>
|
||||
await Get.find<TextToSpeechController>().speakText(
|
||||
'${'you have a negative balance of'.tr}${passengerWallet.toStringAsFixed(2)}${' in your'.tr} ${AppInformation.appName}${' wallet due to a previous trip.'.tr}'),
|
||||
child: const Icon(
|
||||
Icons.headphones,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
207
lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart
Normal file
207
lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart
Normal file
@@ -0,0 +1,207 @@
|
||||
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/views/home/my_wallet/passenger_wallet.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/info.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../../controller/payment/payment_controller.dart';
|
||||
import '../../../main.dart';
|
||||
import '../../widgets/elevated_btn.dart';
|
||||
|
||||
class CashConfirmPageShown extends StatelessWidget {
|
||||
CashConfirmPageShown({super.key});
|
||||
final PaymentController paymentController = Get.put(PaymentController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
// شرط الإظهار الرئيسي لم يتغير
|
||||
return Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
// التحكم في ظهور اللوحة لم يتغير
|
||||
transform: Matrix4.translationValues(
|
||||
0, controller.isCashConfirmPageShown ? 0 : Get.height, 0),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.secondaryColor,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(24),
|
||||
topRight: Radius.circular(24),
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
blurRadius: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// --- 1. رأس الصفحة ---
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Payment Method'.tr,
|
||||
style: AppStyle.headTitle.copyWith(fontSize: 24),
|
||||
),
|
||||
// زر الإغلاق (كان معلقاً في الكود القديم، تم تفعيله هنا)
|
||||
IconButton(
|
||||
onPressed: () => controller.changeCashConfirmPageShown(),
|
||||
icon: const Icon(Icons.close, color: AppColor.writeColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// --- 2. بطاقات اختيار الدفع ---
|
||||
GetBuilder<PaymentController>(builder: (paymentCtrl) {
|
||||
// نفس منطق تغيير اللون للسيارات النسائية
|
||||
final bool isLadyRide = box.read(BoxName.carType) == 'Lady' ||
|
||||
box.read(BoxName.carType) == 'Pink Bike';
|
||||
final Color selectedColor =
|
||||
isLadyRide ? Colors.pink.shade300 : AppColor.primaryColor;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
// بطاقة المحفظة
|
||||
_buildPaymentOptionCard(
|
||||
icon: Icons.account_balance_wallet_outlined,
|
||||
title: '${AppInformation.appName} Wallet'.tr,
|
||||
subtitle:
|
||||
'${'Balance:'.tr} ${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${'SYP'.tr}',
|
||||
isSelected: paymentCtrl.isWalletChecked,
|
||||
selectedColor: selectedColor,
|
||||
onTap: () =>
|
||||
paymentCtrl.onChangedPaymentMethodWallet(true),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// بطاقة الكاش
|
||||
_buildPaymentOptionCard(
|
||||
icon: Icons.money_rounded,
|
||||
title: 'Cash'.tr,
|
||||
subtitle: 'Pay directly to the captain'.tr,
|
||||
isSelected: paymentCtrl.isCashChecked,
|
||||
selectedColor: selectedColor,
|
||||
onTap: () =>
|
||||
paymentCtrl.onChangedPaymentMethodCash(true),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// --- 3. أزرار التأكيد (بنفس منطقك القديم تماماً) ---
|
||||
GetBuilder<PaymentController>(builder: (paymentCtrl) {
|
||||
final bool isWalletSufficient = (double.tryParse(
|
||||
box.read(BoxName.passengerWalletTotal) ?? '0') ??
|
||||
0) >=
|
||||
controller.totalPassenger;
|
||||
|
||||
// إذا تم اختيار المحفظة والرصيد غير كافٍ
|
||||
if (paymentCtrl.isWalletChecked && !isWalletSufficient) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
MyElevatedButton(
|
||||
title: 'Top up Wallet to continue'.tr,
|
||||
onPressed: () =>
|
||||
Get.to(() => const PassengerWallet()),
|
||||
kolor: AppColor.redColor,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextButton(
|
||||
onPressed: () =>
|
||||
paymentCtrl.onChangedPaymentMethodCash(true),
|
||||
child: Text("Or pay with Cash instead".tr,
|
||||
style: TextStyle(color: AppColor.primaryColor)),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
// في كل الحالات الأخرى (كاش، أو محفظة برصيد كافٍ)
|
||||
else {
|
||||
return MyElevatedButton(
|
||||
title: 'Confirm & Find a Ride'.tr,
|
||||
onPressed: () {
|
||||
// --- نفس منطقك القديم بالضبط ---
|
||||
controller.changeCashConfirmPageShown();
|
||||
controller.isSearchingWindow = true;
|
||||
controller.confirmRideForAllDriverAvailable();
|
||||
controller.update();
|
||||
},
|
||||
);
|
||||
}
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// --- ويدجت مساعدة لبناء بطاقة الدفع ---
|
||||
Widget _buildPaymentOptionCard({
|
||||
required IconData icon,
|
||||
required String title,
|
||||
required String subtitle,
|
||||
required bool isSelected,
|
||||
required VoidCallback onTap,
|
||||
required Color selectedColor,
|
||||
}) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 250),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? selectedColor.withOpacity(0.1)
|
||||
: AppColor.writeColor.withOpacity(0.05),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? selectedColor
|
||||
: AppColor.writeColor.withOpacity(0.2),
|
||||
width: isSelected ? 2.0 : 1.0,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon,
|
||||
color: isSelected ? selectedColor : AppColor.writeColor,
|
||||
size: 28),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title,
|
||||
style:
|
||||
AppStyle.title.copyWith(fontWeight: FontWeight.bold)),
|
||||
Text(subtitle,
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
color: AppColor.writeColor.withOpacity(0.7))),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (isSelected)
|
||||
Icon(Icons.check_circle_rounded, color: selectedColor, size: 24),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
106
lib/views/home/map_widget.dart/driver_card_from_passenger.dart
Normal file
106
lib/views/home/map_widget.dart/driver_card_from_passenger.dart
Normal file
@@ -0,0 +1,106 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import 'hexegone_clipper.dart';
|
||||
|
||||
GetBuilder<MapPassengerController> hexagonClipper() {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: ((controller) => controller.rideConfirm
|
||||
? Positioned(
|
||||
top: Get.height * .1,
|
||||
left: Get.width * .1,
|
||||
right: Get.width * .1,
|
||||
child: ClipPath(
|
||||
clipper:
|
||||
HexagonClipper(), // CustomClipper to create a hexagon shape
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(microseconds: 300),
|
||||
height: 250,
|
||||
width: 250,
|
||||
// decoration: AppStyle.boxDecoration,
|
||||
// gradient: const LinearGradient(
|
||||
// colors: [AppColor.greenColor, AppColor.secondaryColor],
|
||||
// begin: Alignment.topLeft,
|
||||
// end: Alignment.bottomCenter,
|
||||
// ),
|
||||
// border: Border.all(),
|
||||
// color: AppColor.secondaryColor,
|
||||
// borderRadius: BorderRadius.circular(15)),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Waiting for Driver ...'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
// IconButton(
|
||||
// onPressed: () {
|
||||
// },
|
||||
// icon: const Icon(Icons.add),
|
||||
// ),
|
||||
// Text(
|
||||
// controller.dataCarsLocationByPassenger['message']
|
||||
// [controller.carsOrder]['phone']
|
||||
// .toString(),
|
||||
// style: AppStyle.title,
|
||||
// ),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Text(
|
||||
'${controller.dataCarsLocationByPassenger['message'][controller.carsOrder]['first_name']} ${controller.dataCarsLocationByPassenger['message'][controller.carsOrder]['last_name']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'Age is '.tr +
|
||||
controller
|
||||
.dataCarsLocationByPassenger['message']
|
||||
[controller.carsOrder]['age']
|
||||
.toString(),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Text(
|
||||
controller.dataCarsLocationByPassenger['message']
|
||||
[controller.carsOrder]['make']
|
||||
.toString(),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
controller.dataCarsLocationByPassenger['message']
|
||||
[controller.carsOrder]['model']
|
||||
.toString(),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'Rating is '.tr +
|
||||
controller.dataCarsLocationByPassenger['message']
|
||||
[controller.carsOrder]['ratingDriver']
|
||||
.toString(),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(border: Border.all(width: 2)),
|
||||
child: Text(
|
||||
controller.dataCarsLocationByPassenger['message']
|
||||
[controller.carsOrder]['car_plate']
|
||||
.toString(),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox()));
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
// import 'package:intl/intl.dart';
|
||||
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
|
||||
class DriverTimeArrivePassengerPage extends StatelessWidget {
|
||||
const DriverTimeArrivePassengerPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) {
|
||||
return controller.remainingTime == 0
|
||||
? Positioned(
|
||||
bottom: Get.height * .35,
|
||||
right: Get.width * .05,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(
|
||||
start: 5, end: 5),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
controller.durationByPassenger.toString() +
|
||||
' to arrive you.'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
" ${DateFormat('h:mm a').format(controller.newTime)}",
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
)
|
||||
: const SizedBox();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:Intaleq/constant/box_name.dart';
|
||||
import 'package:Intaleq/constant/table_names.dart';
|
||||
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 '../../../main.dart';
|
||||
|
||||
GetBuilder<MapPassengerController> formSearchPlacesDestenation() {
|
||||
if (box.read(BoxName.addWork).toString() == '' ||
|
||||
box.read(BoxName.addHome).toString() == '') {
|
||||
box.write(BoxName.addWork, 'addWork');
|
||||
box.write(BoxName.addHome, 'addHome');
|
||||
}
|
||||
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: controller.placeDestinationController,
|
||||
onChanged: (value) {
|
||||
if (controller.placeDestinationController.text.length > 2) {
|
||||
controller.getPlaces();
|
||||
controller.changeHeightPlaces();
|
||||
} else if (controller
|
||||
.placeDestinationController.text.isEmpty) {
|
||||
controller.clearPlacesDestination();
|
||||
controller.changeHeightPlaces();
|
||||
}
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: controller.hintTextDestinationPoint,
|
||||
hintStyle:
|
||||
AppStyle.subtitle.copyWith(color: Colors.grey[600]),
|
||||
prefixIcon:
|
||||
const Icon(Icons.search, color: AppColor.primaryColor),
|
||||
suffixIcon: controller
|
||||
.placeDestinationController.text.isNotEmpty
|
||||
? IconButton(
|
||||
icon: Icon(Icons.clear, color: Colors.grey[400]),
|
||||
onPressed: () {
|
||||
controller.placeDestinationController.clear();
|
||||
controller.clearPlacesDestination();
|
||||
controller.changeHeightPlaces();
|
||||
},
|
||||
)
|
||||
: 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],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8.0),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.changePickerShown();
|
||||
},
|
||||
icon: Icon(Icons.location_on_outlined,
|
||||
color: AppColor.accentColor, size: 30),
|
||||
tooltip: controller.isAnotherOreder
|
||||
? 'Pick destination on map'
|
||||
: 'Pick on map',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_buildQuickActionButton(
|
||||
icon: Icons.work_outline,
|
||||
text: box.read(BoxName.addWork) == 'addWork'
|
||||
? 'Add Work'.tr
|
||||
: 'To Work'.tr,
|
||||
onTap: () async {
|
||||
if (box.read(BoxName.addWork) == 'addWork') {
|
||||
controller.workLocationFromMap = true;
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.changePickerShown();
|
||||
} else {
|
||||
_handleQuickAction(controller, BoxName.addWork, 'To Work');
|
||||
}
|
||||
},
|
||||
onLongPress: () =>
|
||||
_showChangeLocationDialog(controller, 'Work'),
|
||||
),
|
||||
_buildQuickActionButton(
|
||||
icon: Icons.home_outlined,
|
||||
text: box.read(BoxName.addHome) == 'addHome'
|
||||
? 'Add Home'.tr
|
||||
: 'To Home'.tr,
|
||||
onTap: () async {
|
||||
if (box.read(BoxName.addHome) == 'addHome') {
|
||||
controller.homeLocationFromMap = true;
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.changePickerShown();
|
||||
} else {
|
||||
_handleQuickAction(controller, BoxName.addHome, 'To Home');
|
||||
}
|
||||
},
|
||||
onLongPress: () =>
|
||||
_showChangeLocationDialog(controller, 'Home'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
height: controller.placesDestination.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 NeverScrollableScrollPhysics(),
|
||||
itemCount: controller.placesDestination.length,
|
||||
separatorBuilder: (context, index) =>
|
||||
const Divider(height: 1, color: Colors.grey),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
var res = controller.placesDestination[index];
|
||||
|
||||
// استخراج البيانات حسب بنية السيرفر الجديد
|
||||
var title = res['name'] ?? 'Unknown Place';
|
||||
var address = res['address'] ?? 'Unknown Address';
|
||||
var latitude = res['latitude'];
|
||||
var longitude = res['longitude'];
|
||||
var primaryCategory =
|
||||
'Place'; // يمكن تطويره لاحقاً لو أضفت نوع للمكان
|
||||
|
||||
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),
|
||||
),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.favorite_border, color: Colors.grey),
|
||||
onPressed: () async {
|
||||
if (latitude != null && longitude != null) {
|
||||
await sql.insertMapLocation({
|
||||
'latitude': latitude,
|
||||
'longitude': longitude,
|
||||
'name': title,
|
||||
'rate': 'N/A',
|
||||
}, TableName.placesFavorite);
|
||||
|
||||
Toast.show(
|
||||
context,
|
||||
'$title ${'Saved Successfully'.tr}',
|
||||
AppColor.primaryColor,
|
||||
);
|
||||
} else {
|
||||
Toast.show(
|
||||
context,
|
||||
'Invalid location data',
|
||||
AppColor.redColor,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
onTap: () async {
|
||||
if (latitude != null && longitude != null) {
|
||||
await sql.insertMapLocation({
|
||||
'latitude': latitude,
|
||||
'longitude': longitude,
|
||||
'name': title,
|
||||
'rate': 'N/A',
|
||||
'createdAt': DateTime.now().toIso8601String(),
|
||||
}, TableName.recentLocations);
|
||||
|
||||
controller.passengerLocation = controller.newMyLocation;
|
||||
controller.myDestination = LatLng(latitude, longitude);
|
||||
controller.convertHintTextDestinationNewPlaces(index);
|
||||
|
||||
controller.placesDestination = [];
|
||||
controller.placeDestinationController.clear();
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.passengerStartLocationFromMap = true;
|
||||
controller.isPickerShown = true;
|
||||
} else {
|
||||
Toast.show(
|
||||
context,
|
||||
'Invalid location data',
|
||||
AppColor.redColor,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildQuickActionButton({
|
||||
required IconData icon,
|
||||
required String text,
|
||||
VoidCallback? onTap,
|
||||
VoidCallback? onLongPress,
|
||||
}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.blueColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
border: Border.all(color: AppColor.blueColor.withOpacity(0.3)),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(icon, color: AppColor.blueColor),
|
||||
const SizedBox(height: 4.0),
|
||||
Text(
|
||||
text,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.title.copyWith(
|
||||
color: AppColor.blueColor, fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showChangeLocationDialog(
|
||||
MapPassengerController controller, String locationType) {
|
||||
Get.defaultDialog(
|
||||
title: 'Change $locationType location?'.tr,
|
||||
middleText: '',
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Yes'.tr,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
if (locationType == 'Work') {
|
||||
controller.workLocationFromMap = true;
|
||||
} else {
|
||||
controller.homeLocationFromMap = true;
|
||||
}
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.changePickerShown();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleQuickAction(
|
||||
MapPassengerController controller, String boxName, String hintText) async {
|
||||
final latLng = LatLng(
|
||||
double.parse(box.read(boxName).toString().split(',')[0]),
|
||||
double.parse(box.read(boxName).toString().split(',')[1]),
|
||||
);
|
||||
controller.hintTextDestinationPoint = hintText;
|
||||
controller.changeMainBottomMenuMap();
|
||||
|
||||
await controller.getDirectionMap(
|
||||
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
||||
'${latLng.latitude},${latLng.longitude}',
|
||||
);
|
||||
controller.currentLocationToFormPlaces = false;
|
||||
controller.placesDestination = [];
|
||||
controller.clearPlacesStart();
|
||||
controller.clearPlacesDestination();
|
||||
controller.passengerStartLocationFromMap = false;
|
||||
controller.isPickerShown = false;
|
||||
controller.showBottomSheet1();
|
||||
}
|
||||
138
lib/views/home/map_widget.dart/form_search_start.dart
Normal file
138
lib/views/home/map_widget.dart/form_search_start.dart
Normal file
@@ -0,0 +1,138 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/constant/table_names.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/functions/toast.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../../main.dart';
|
||||
|
||||
GetBuilder<MapPassengerController> formSearchPlacesStart() {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
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 > 5) {
|
||||
// Reduced character limit
|
||||
controller.getPlacesStart();
|
||||
controller.changeHeightStartPlaces();
|
||||
} else if (controller.placeStartController.text.isEmpty) {
|
||||
controller.clearPlacesStart();
|
||||
controller.changeHeightPlaces(); // Collapse if empty
|
||||
}
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: controller.hintTextStartPoint,
|
||||
hintStyle:
|
||||
AppStyle.subtitle.copyWith(color: Colors.grey[600]),
|
||||
prefixIcon:
|
||||
const 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();
|
||||
controller
|
||||
.changeHeightPlaces(); // Collapse on clear
|
||||
},
|
||||
)
|
||||
: 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],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8.0),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
controller.startLocationFromMap = true;
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.changePickerShown();
|
||||
},
|
||||
icon: Icon(Icons.location_on_outlined,
|
||||
color: AppColor.accentColor, size: 30),
|
||||
tooltip: 'Choose on Map',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
height: controller.placesStart.isNotEmpty ? controller.height : 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 NeverScrollableScrollPhysics(),
|
||||
itemCount: controller.placesStart.length,
|
||||
separatorBuilder: (context, index) =>
|
||||
const Divider(height: 1, color: Colors.grey),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
var res = controller.placesStart[index];
|
||||
return ListTile(
|
||||
leading: Image.network(res['icon'], width: 30, height: 30),
|
||||
title: Text(res['name'].toString(),
|
||||
style: AppStyle.subtitle
|
||||
.copyWith(fontWeight: FontWeight.w500)),
|
||||
subtitle: Text(res['vicinity'].toString(),
|
||||
style: TextStyle(color: Colors.grey[600], fontSize: 12)),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.favorite_border, color: Colors.grey),
|
||||
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 Successfully'.tr}',
|
||||
AppColor.primaryColor);
|
||||
},
|
||||
),
|
||||
onTap: () async {
|
||||
controller.changeHeightPlaces();
|
||||
await sql.insertMapLocation({
|
||||
'latitude': res['geometry']['location']['lat'],
|
||||
'longitude': res['geometry']['location']['lng'],
|
||||
'name': res['name'].toString(),
|
||||
'rate': res['rating'].toString(),
|
||||
'createdAt': DateTime.now().toIso8601String(),
|
||||
}, TableName.recentLocations);
|
||||
|
||||
controller.convertHintTextStartNewPlaces(index);
|
||||
controller.currentLocationString = res['name'];
|
||||
controller.placesStart = [];
|
||||
controller.placeStartController.clear();
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
167
lib/views/home/map_widget.dart/form_serch_multiy_point.dart
Normal file
167
lib/views/home/map_widget.dart/form_serch_multiy_point.dart
Normal file
@@ -0,0 +1,167 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/constant/table_names.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/functions/toast.dart';
|
||||
import '../../../controller/home/map_passenger_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:
|
||||
const 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);
|
||||
}
|
||||
},
|
||||
// onEditingComplete: () => controller.changeHeight(),
|
||||
),
|
||||
),
|
||||
),
|
||||
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 {
|
||||
controller.changeHeightPlaces();
|
||||
if (controller.currentLocationToFormPlacesAll[index] ==
|
||||
true) {
|
||||
controller.newStartPointLocation =
|
||||
controller.passengerLocation;
|
||||
} else {
|
||||
controller.passengerLocation =
|
||||
controller.newStartPointLocation;
|
||||
}
|
||||
|
||||
controller.convertHintTextPlaces(index, res);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
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,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
}
|
||||
457
lib/views/home/map_widget.dart/google_map_passenger_widget.dart
Normal file
457
lib/views/home/map_widget.dart/google_map_passenger_widget.dart
Normal file
@@ -0,0 +1,457 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:Intaleq/controller/home/points_for_rider_controller.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/functions/location_controller.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../widgets/mycircular.dart';
|
||||
import '../../widgets/mydialoug.dart';
|
||||
|
||||
class GoogleMapPassengerWidget extends StatelessWidget {
|
||||
GoogleMapPassengerWidget({
|
||||
super.key,
|
||||
});
|
||||
WayPointController wayPointController = Get.put(WayPointController());
|
||||
final LocationController locationController = Get.find<LocationController>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => controller.isLoading
|
||||
? const MyCircularProgressIndicator()
|
||||
: Positioned(
|
||||
bottom: Get.height * .2,
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: GoogleMap(
|
||||
onMapCreated: controller.onMapCreated,
|
||||
|
||||
cameraTargetBounds: CameraTargetBounds(controller.boundsdata),
|
||||
minMaxZoomPreference: const MinMaxZoomPreference(6, 18),
|
||||
onLongPress: (argument) {
|
||||
MyDialog().getDialog('Are you want to go to this site'.tr, '',
|
||||
() async {
|
||||
controller.clearPolyline();
|
||||
if (controller.dataCarsLocationByPassenger != null) {
|
||||
await controller.getDirectionMap(
|
||||
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
||||
'${argument.latitude.toString()},${argument.longitude.toString()}');
|
||||
|
||||
Get.back();
|
||||
controller.bottomSheet();
|
||||
controller.showBottomSheet1();
|
||||
} else {
|
||||
Get.back();
|
||||
Get.snackbar(
|
||||
'We Are Sorry That we dont have cars in your Location!'
|
||||
.tr,
|
||||
'',
|
||||
colorText: AppColor.redColor,
|
||||
duration: const Duration(seconds: 11),
|
||||
instantInit: true,
|
||||
snackPosition: SnackPosition.TOP,
|
||||
titleText: Text(
|
||||
'Error'.tr,
|
||||
style: const TextStyle(color: AppColor.redColor),
|
||||
),
|
||||
messageText: Text(
|
||||
'We Are Sorry That we dont have cars in your Location!'
|
||||
.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
icon: const Icon(Icons.error),
|
||||
shouldIconPulse: true,
|
||||
maxWidth: double.infinity,
|
||||
margin: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(16),
|
||||
borderRadius: 8,
|
||||
borderColor: AppColor.redColor,
|
||||
borderWidth: 2,
|
||||
backgroundColor: AppColor.secondaryColor,
|
||||
leftBarIndicatorColor: AppColor.redColor,
|
||||
boxShadows: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.25),
|
||||
blurRadius: 4,
|
||||
spreadRadius: 2,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
backgroundGradient: const LinearGradient(
|
||||
colors: [AppColor.redColor, AppColor.accentColor],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
// mainButton: TextButton(
|
||||
// onPressed: () {
|
||||
// controller.getCarsLocationByPassenger();
|
||||
// },
|
||||
// child: Text(
|
||||
// 'Try Again'.tr,
|
||||
// style: const TextStyle(
|
||||
// color: AppColor.secondaryColor),
|
||||
// ),
|
||||
// ),
|
||||
onTap: (GetSnackBar snackBar) {
|
||||
// Do something when the snackbar is tapped.
|
||||
},
|
||||
isDismissible: true,
|
||||
showProgressIndicator: false,
|
||||
dismissDirection: DismissDirection.up,
|
||||
progressIndicatorController: null,
|
||||
progressIndicatorBackgroundColor: Colors.transparent,
|
||||
progressIndicatorValueColor: null,
|
||||
snackStyle: SnackStyle.GROUNDED,
|
||||
forwardAnimationCurve: Curves.easeInToLinear,
|
||||
reverseAnimationCurve: Curves.easeInOut,
|
||||
animationDuration: const Duration(milliseconds: 4000),
|
||||
barBlur: 8,
|
||||
overlayBlur: 0,
|
||||
snackbarStatus: null,
|
||||
overlayColor: AppColor.primaryColor.withOpacity(0.5),
|
||||
userInputForm: null,
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
});
|
||||
// Get.defaultDialog(
|
||||
// title: 'Are you want to go to this site'.tr,
|
||||
// content: Column(
|
||||
// children: [
|
||||
// Text('${argument.latitude},${argument.longitude}'),
|
||||
// ],
|
||||
// ),
|
||||
// confirm: MyElevatedButton(
|
||||
// title: 'Ok'.tr,
|
||||
// onPressed: () async {
|
||||
// controller.clearPolyline();
|
||||
// if (controller.dataCarsLocationByPassenger != null) {
|
||||
// await controller.getMap(
|
||||
// '${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
||||
// '${argument.latitude.toString()},${argument.longitude.toString()}');
|
||||
|
||||
// Get.back();
|
||||
// controller.bottomSheet();
|
||||
// controller.showBottomSheet1();
|
||||
// } else {
|
||||
// Get.back();
|
||||
// Get.snackbar(
|
||||
// 'We Are Sorry That we dont have cars in your Location!'
|
||||
// .tr,
|
||||
// '',
|
||||
// colorText: AppColor.redColor,
|
||||
// duration: const Duration(seconds: 11),
|
||||
// instantInit: true,
|
||||
// snackPosition: SnackPosition.TOP,
|
||||
// titleText: Text(
|
||||
// 'Error'.tr,
|
||||
// style:
|
||||
// const TextStyle(color: AppColor.redColor),
|
||||
// ),
|
||||
// messageText: Text(
|
||||
// 'We Are Sorry That we dont have cars in your Location!'
|
||||
// .tr,
|
||||
// style: AppStyle.title,
|
||||
// ),
|
||||
// icon: const Icon(Icons.error),
|
||||
// shouldIconPulse: true,
|
||||
// maxWidth: double.infinity,
|
||||
// margin: const EdgeInsets.all(16),
|
||||
// padding: const EdgeInsets.all(16),
|
||||
// borderRadius: 8,
|
||||
// borderColor: AppColor.redColor,
|
||||
// borderWidth: 2,
|
||||
// backgroundColor: AppColor.secondaryColor,
|
||||
// leftBarIndicatorColor: AppColor.redColor,
|
||||
// boxShadows: [
|
||||
// BoxShadow(
|
||||
// color: Colors.black.withOpacity(0.25),
|
||||
// blurRadius: 4,
|
||||
// spreadRadius: 2,
|
||||
// offset: const Offset(0, 4),
|
||||
// ),
|
||||
// ],
|
||||
// backgroundGradient: const LinearGradient(
|
||||
// colors: [
|
||||
// AppColor.redColor,
|
||||
// AppColor.accentColor
|
||||
// ],
|
||||
// begin: Alignment.topLeft,
|
||||
// end: Alignment.bottomRight,
|
||||
// ),
|
||||
// // mainButton: TextButton(
|
||||
// // onPressed: () {
|
||||
// // controller.getCarsLocationByPassenger();
|
||||
// // },
|
||||
// // child: Text(
|
||||
// // 'Try Again'.tr,
|
||||
// // style: const TextStyle(
|
||||
// // color: AppColor.secondaryColor),
|
||||
// // ),
|
||||
// // ),
|
||||
// onTap: (GetSnackBar snackBar) {
|
||||
// // Do something when the snackbar is tapped.
|
||||
// },
|
||||
// isDismissible: true,
|
||||
// showProgressIndicator: false,
|
||||
// dismissDirection: DismissDirection.up,
|
||||
// progressIndicatorController: null,
|
||||
// progressIndicatorBackgroundColor:
|
||||
// Colors.transparent,
|
||||
// progressIndicatorValueColor: null,
|
||||
// snackStyle: SnackStyle.GROUNDED,
|
||||
// forwardAnimationCurve: Curves.easeInToLinear,
|
||||
// reverseAnimationCurve: Curves.easeInOut,
|
||||
// animationDuration:
|
||||
// const Duration(milliseconds: 4000),
|
||||
// barBlur: 8,
|
||||
// overlayBlur: 0,
|
||||
// snackbarStatus: null,
|
||||
// overlayColor:
|
||||
// AppColor.primaryColor.withOpacity(0.5),
|
||||
// userInputForm: null,
|
||||
// );
|
||||
// }
|
||||
|
||||
// //
|
||||
// }),
|
||||
// );
|
||||
},
|
||||
|
||||
onTap: (argument) {
|
||||
controller.hidePlaces();
|
||||
|
||||
// controller.changeBottomSheetShown();
|
||||
// controller.bottomSheet();
|
||||
},
|
||||
initialCameraPosition: CameraPosition(
|
||||
target: controller.passengerLocation,
|
||||
zoom: 15,
|
||||
),
|
||||
|
||||
markers: controller.markers.toSet(),
|
||||
// {
|
||||
// if (controller.statusRide != 'Apply' ||
|
||||
// !controller.rideTimerBegin)
|
||||
// for (var carLocation in controller.carLocationsModels)
|
||||
|
||||
// // Marker(
|
||||
// // // anchor: const Offset(4, 4),
|
||||
// // position: LatLng(
|
||||
// // carLocation.latitude,
|
||||
// // carLocation.longitude,
|
||||
// // ),
|
||||
// // icon: controller.carIcon,
|
||||
// // markerId: MarkerId(carLocation.toString()),
|
||||
// // rotation: carLocation.heading,
|
||||
// // ),
|
||||
// // controller.carMarrkerAplied,
|
||||
// if (controller.statusRide == 'Apply')
|
||||
// // for (var carLocation
|
||||
// // in controller.driverCarsLocationToPassengerAfterApplied)
|
||||
// Marker(
|
||||
// // anchor: const Offset(4, 4),
|
||||
// position: LatLng(
|
||||
// double.parse(
|
||||
// controller
|
||||
// .datadriverCarsLocationToPassengerAfterApplied[
|
||||
// 'message'][0]['latitude'],
|
||||
// ),
|
||||
// double.parse(
|
||||
// controller
|
||||
// .datadriverCarsLocationToPassengerAfterApplied[
|
||||
// 'message'][0]['longitude'],
|
||||
// ),
|
||||
// ), //carLocation,
|
||||
// icon: controller.carIcon,
|
||||
// rotation: double.parse(controller
|
||||
// .datadriverCarsLocationToPassengerAfterApplied[
|
||||
// 'message'][0]['heading']),
|
||||
// markerId: MarkerId(controller
|
||||
// .datadriverCarsLocationToPassengerAfterApplied[
|
||||
// 'message'][0]['longitude']
|
||||
// .toString())),
|
||||
// for (int i = 1;
|
||||
// i < controller.coordinatesWithoutEmpty.length - 1;
|
||||
// i++)
|
||||
// Marker(
|
||||
// // anchor: const Offset(4, 4),
|
||||
// position: LatLng(
|
||||
// double.parse(controller.coordinatesWithoutEmpty[i]
|
||||
// .split(',')[0]),
|
||||
// double.parse(controller.coordinatesWithoutEmpty[i]
|
||||
// .split(',')[1])),
|
||||
// icon: controller.tripIcon,
|
||||
// markerId: MarkerId(
|
||||
// controller.coordinatesWithoutEmpty[i].toString())),
|
||||
// if (controller.isMarkersShown)
|
||||
// Marker(
|
||||
// markerId: MarkerId('MyLocation'.tr),
|
||||
// position: controller.newStartPointLocation,
|
||||
// draggable: true,
|
||||
// icon: controller.startIcon,
|
||||
// ),
|
||||
// if (controller.isMarkersShown)
|
||||
// Marker(
|
||||
// markerId: MarkerId('Destination'.tr),
|
||||
// position: controller.myDestination,
|
||||
// draggable: true,
|
||||
// icon: controller.endIcon,
|
||||
// ),
|
||||
// if (controller.haveSteps)
|
||||
// Marker(
|
||||
// markerId: MarkerId('StartSteps'.tr),
|
||||
// position: LatLng(
|
||||
// double.parse(
|
||||
// controller.placesCoordinate[0].split(',')[0]),
|
||||
// double.parse(
|
||||
// controller.placesCoordinate[0].split(',')[1])),
|
||||
// draggable: true,
|
||||
// icon: controller.startIcon,
|
||||
// ),
|
||||
// if (controller.haveSteps)
|
||||
// Marker(
|
||||
// markerId: MarkerId('EndSteps'.tr),
|
||||
// position: controller.latestPosition,
|
||||
// draggable: true,
|
||||
// icon: controller.endIcon,
|
||||
// ),
|
||||
// },
|
||||
polygons: controller.polygons,
|
||||
polylines: controller.polyLines.toSet(),
|
||||
// {
|
||||
// Polyline(
|
||||
// polylineId: const PolylineId('route'),
|
||||
// points: controller.polylineCoordinates,
|
||||
// color: AppColor.primaryColor,
|
||||
// width: 4,
|
||||
// // patterns: [
|
||||
// // PatternItem.dot,
|
||||
// // PatternItem.gap(10),
|
||||
// // ],
|
||||
// endCap: Cap.roundCap,
|
||||
// startCap: Cap.roundCap,
|
||||
// geodesic: true,
|
||||
// ),
|
||||
|
||||
// Polyline(
|
||||
// zIndex: 1,
|
||||
// consumeTapEvents: true,
|
||||
// geodesic: true,
|
||||
// endCap: Cap.buttCap,
|
||||
// startCap: Cap.buttCap,
|
||||
// visible: true,
|
||||
// polylineId: const PolylineId('route0'),
|
||||
// points: controller.polylineCoordinatesPointsAll[0],
|
||||
// color: AppColor.blueColor,
|
||||
// width: 5,
|
||||
// ),
|
||||
// Polyline(
|
||||
// zIndex: 2,
|
||||
// consumeTapEvents: true,
|
||||
// geodesic: true,
|
||||
// endCap: Cap.buttCap,
|
||||
// startCap: Cap.buttCap,
|
||||
// visible: true,
|
||||
// polylineId: const PolylineId('route1'),
|
||||
// points: controller.polylineCoordinatesPointsAll[1],
|
||||
// color: AppColor.yellowColor,
|
||||
// width: 5,
|
||||
// ),
|
||||
// Polyline(
|
||||
// zIndex: 2,
|
||||
// consumeTapEvents: true,
|
||||
// geodesic: true,
|
||||
// endCap: Cap.buttCap,
|
||||
// startCap: Cap.buttCap,
|
||||
// visible: true,
|
||||
// polylineId: const PolylineId('route2'),
|
||||
// points: controller.polylineCoordinatesPointsAll[2],
|
||||
// color: AppColor.greenColor,
|
||||
// width: 5,
|
||||
// ),
|
||||
// Polyline(
|
||||
// zIndex: 2,
|
||||
// consumeTapEvents: true,
|
||||
// geodesic: true,
|
||||
// endCap: Cap.buttCap,
|
||||
// startCap: Cap.buttCap,
|
||||
// visible: true,
|
||||
// polylineId: const PolylineId('route3'),
|
||||
// points: controller.polylineCoordinatesPointsAll[2],
|
||||
// color: AppColor.deepPurpleAccent,
|
||||
// width: 5,
|
||||
// ),
|
||||
// // Polyline(
|
||||
// // zIndex: 2,
|
||||
// // consumeTapEvents: true,
|
||||
// // geodesic: true,
|
||||
// // endCap: Cap.buttCap,
|
||||
// // startCap: Cap.buttCap,
|
||||
// // visible: true,
|
||||
// // polylineId: PolylineId('g'),
|
||||
// // points: [
|
||||
// // LatLng(controller.southwest.latitude,
|
||||
// // controller.southwest.longitude),
|
||||
// // LatLng(controller.northeast.latitude,
|
||||
// // controller.northeast.longitude)
|
||||
// // ],
|
||||
// // color: AppColor.primaryColor,
|
||||
// // width: 5,
|
||||
// // ),
|
||||
// },
|
||||
// circles: {
|
||||
// Circle(
|
||||
// circleId: const CircleId('kk'),
|
||||
// center: controller.mylocation,
|
||||
// radius: 60,
|
||||
// fillColor: AppColor.primaryColor,)
|
||||
// },
|
||||
|
||||
circles: <Circle>{
|
||||
Circle(
|
||||
circleId: const CircleId('circle_id'),
|
||||
center: controller.passengerLocation,
|
||||
radius: 100,
|
||||
fillColor: Colors.blue.withOpacity(0.3),
|
||||
strokeColor: Colors.blue,
|
||||
strokeWidth: 2,
|
||||
),
|
||||
},
|
||||
|
||||
mapType:
|
||||
controller.mapType ? MapType.satellite : MapType.terrain,
|
||||
myLocationButtonEnabled: true,
|
||||
// liteModeEnabled: true, tiltGesturesEnabled: false,
|
||||
|
||||
// indoorViewEnabled: true,
|
||||
trafficEnabled: controller.mapTrafficON,
|
||||
buildingsEnabled: true,
|
||||
mapToolbarEnabled: true,
|
||||
onCameraMove: (position) {
|
||||
int waypointsLength =
|
||||
Get.find<WayPointController>().wayPoints.length;
|
||||
int index = controller.wayPointIndex;
|
||||
if (waypointsLength > 0) {
|
||||
controller.placesCoordinate[index] =
|
||||
'${position.target.latitude.toString()},${position.target.longitude}';
|
||||
}
|
||||
if (controller.startLocationFromMap == true) {
|
||||
controller.newStartPointLocation = position.target;
|
||||
} else if (controller.passengerStartLocationFromMap == true) {
|
||||
controller.newStartPointLocation = position.target;
|
||||
}
|
||||
controller.newMyLocation = position.target;
|
||||
},
|
||||
myLocationEnabled: true,
|
||||
// liteModeEnabled: true,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
52
lib/views/home/map_widget.dart/hexegone_clipper.dart
Normal file
52
lib/views/home/map_widget.dart/hexegone_clipper.dart
Normal file
@@ -0,0 +1,52 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class HexagonClipper extends CustomClipper<Path> {
|
||||
@override
|
||||
Path getClip(Size size) {
|
||||
final path = Path();
|
||||
final height = size.height;
|
||||
final width = size.width;
|
||||
final centerX = width / 2;
|
||||
final centerY = height / 2;
|
||||
final radius = width / 2;
|
||||
|
||||
const angle = 2 * pi / 10; // Angle between each side of the hexagon
|
||||
|
||||
// Start at the top right vertex of the hexagon
|
||||
final startX = centerX + radius * cos(0);
|
||||
final startY = centerY + radius * sin(0);
|
||||
path.moveTo(startX, startY);
|
||||
|
||||
// Draw the remaining sides of the hexagon
|
||||
for (int i = 1; i < 10; i++) {
|
||||
final x = centerX + radius * cos(angle * i);
|
||||
final y = centerY + radius * sin(angle * i);
|
||||
path.lineTo(x, y);
|
||||
}
|
||||
|
||||
path.close();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReclip(HexagonClipper oldClipper) => false;
|
||||
}
|
||||
|
||||
class ArrowClipper extends CustomClipper<Path> {
|
||||
@override
|
||||
Path getClip(Size size) {
|
||||
final path = Path();
|
||||
path.moveTo(0, size.height / 2);
|
||||
path.lineTo(size.width / 2, 0);
|
||||
path.lineTo(size.width, size.height / 2);
|
||||
path.lineTo(size.width / 2, size.height);
|
||||
path.close();
|
||||
return path;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReclip(ArrowClipper oldClipper) => false;
|
||||
}
|
||||
165
lib/views/home/map_widget.dart/left_main_menu_icons.dart
Normal file
165
lib/views/home/map_widget.dart/left_main_menu_icons.dart
Normal file
@@ -0,0 +1,165 @@
|
||||
import 'package:Intaleq/constant/box_name.dart';
|
||||
import 'package:Intaleq/controller/firebase/firbase_messge.dart';
|
||||
import 'package:Intaleq/env/env.dart';
|
||||
import 'package:Intaleq/main.dart';
|
||||
import 'package:Intaleq/views/auth/login_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:secure_string_operations/secure_string_operations.dart';
|
||||
import 'dart:ui'; // مهم لإضافة تأثير الضبابية
|
||||
|
||||
import '../../../constant/char_map.dart';
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../controller/auth/login_controller.dart';
|
||||
import '../../../controller/functions/encrypt_decrypt.dart';
|
||||
import '../../../controller/functions/tts.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../../controller/home/vip_waitting_page.dart';
|
||||
import '../../../print.dart';
|
||||
import '../../auth/otp_page.dart';
|
||||
import '../../auth/otp_token_page.dart';
|
||||
|
||||
// --- الدالة الرئيسية بالتصميم الجديد ---
|
||||
GetBuilder<MapPassengerController> leftMainMenuIcons() {
|
||||
Get.put(TextToSpeechController());
|
||||
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.8), // لون شبه شفاف
|
||||
borderRadius: BorderRadius.circular(50.0),
|
||||
border: Border.all(color: AppColor.writeColor.withOpacity(0.2)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min, // ليأخذ الشريط حجم الأزرار فقط
|
||||
children: [
|
||||
// --- تم استخدام دالة مساعدة جديدة للزر ---
|
||||
_buildMapActionButton(
|
||||
icon: Icons.satellite_alt_outlined,
|
||||
tooltip: 'Toggle Map Type',
|
||||
onPressed: () => controller.changeMapType(),
|
||||
),
|
||||
_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,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
_buildVerticalDivider(),
|
||||
_buildMapActionButton(
|
||||
icon: Octicons.watch,
|
||||
tooltip: 'VIP Waiting Page',
|
||||
onPressed: () => Get.to(() => VipWaittingPage()),
|
||||
),
|
||||
// _buildMapActionButton(
|
||||
// icon: Octicons.ellipsis,
|
||||
// tooltip: 'test',
|
||||
// onPressed: () => Get.to(() => TestPage()),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// --- دالة مساعدة جديدة لإنشاء الأزرار بشكل أنيق ---
|
||||
Widget _buildMapActionButton({
|
||||
required IconData icon,
|
||||
required String tooltip,
|
||||
required VoidCallback onPressed,
|
||||
}) {
|
||||
return IconButton(
|
||||
onPressed: onPressed,
|
||||
icon: Icon(icon, color: AppColor.writeColor, size: 22),
|
||||
tooltip: tooltip,
|
||||
splashRadius: 22,
|
||||
padding: const EdgeInsets.all(12),
|
||||
constraints: const BoxConstraints(), // لإزالة المساحات الافتراضية
|
||||
);
|
||||
}
|
||||
|
||||
// --- ويدجت للفاصل الرأسي بين الأزرار ---
|
||||
Widget _buildVerticalDivider() {
|
||||
return Container(
|
||||
height: 20,
|
||||
width: 1,
|
||||
color: AppColor.writeColor.withOpacity(0.2),
|
||||
);
|
||||
}
|
||||
|
||||
// --- باقي الكود الخاص بك يبقى كما هو بدون تغيير ---
|
||||
class TestPage extends StatelessWidget {
|
||||
const TestPage({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final firebaseMessagesController =
|
||||
Get.isRegistered<FirebaseMessagesController>()
|
||||
? Get.find<FirebaseMessagesController>()
|
||||
: Get.put(FirebaseMessagesController());
|
||||
return Scaffold(
|
||||
appBar: AppBar(),
|
||||
body: Center(
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
Get.put(LoginController());
|
||||
Get.to(() => PhoneNumberScreen());
|
||||
// firebaseMessagesController.sendNotificationToDriverMAP(
|
||||
// 'title',
|
||||
// DateTime.now().toString(),
|
||||
// 'ffX7xVXpdE_Xq8JBH3lgS4:APA91bGBHp53E-ZuXdlLBpRZohzqR9sazqcn3pwpEDG7JxkVi9MBtFDlCipzLpPCvD6LHEtds88ugGyCty7pEJVyx6tQYvzHVDCh7l3_7axpyriTBs5iv9E',
|
||||
// [],
|
||||
// '');
|
||||
// Get.to(
|
||||
// () => OtpVerificationPage(
|
||||
// phone: '963992952235',
|
||||
// deviceToken: 'abcdefg123456789',
|
||||
// token: 'passengerToken123',
|
||||
// ptoken: 'passengerToken456',
|
||||
// ),
|
||||
// );
|
||||
},
|
||||
child: Text(
|
||||
"Text Button",
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
642
lib/views/home/map_widget.dart/main_bottom_Menu_map.dart
Normal file
642
lib/views/home/map_widget.dart/main_bottom_Menu_map.dart
Normal file
@@ -0,0 +1,642 @@
|
||||
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:google_maps_flutter/google_maps_flutter.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
|
||||
import '../../../constant/table_names.dart';
|
||||
|
||||
import '../../../controller/functions/toast.dart';
|
||||
|
||||
import '../../../controller/functions/tts.dart';
|
||||
|
||||
import '../../widgets/error_snakbar.dart';
|
||||
|
||||
import '../../widgets/mydialoug.dart';
|
||||
|
||||
import 'form_search_start.dart';
|
||||
|
||||
class MainBottomMenuMap extends StatelessWidget {
|
||||
const MainBottomMenuMap({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(MapPassengerController());
|
||||
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => Positioned(
|
||||
bottom: Get.height * .04, // Increased bottom padding
|
||||
|
||||
left: 16,
|
||||
|
||||
right: 16,
|
||||
|
||||
child: GestureDetector(
|
||||
onTap: controller
|
||||
.changeMainBottomMenuMap, // Make the whole area tappable
|
||||
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(
|
||||
milliseconds: 300), // Reduced duration for smoother animation
|
||||
|
||||
curve: Curves.easeInOut, // Added animation curve
|
||||
|
||||
height: controller.mainBottomMenuMapHeight,
|
||||
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.secondaryColor, // Use a solid background color
|
||||
|
||||
borderRadius: BorderRadius.circular(16), // More rounded corners
|
||||
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
blurRadius: 10,
|
||||
offset: Offset(0, 5),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
child: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(), // Add bouncing effect
|
||||
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
|
||||
crossAxisAlignment: CrossAxisAlignment
|
||||
.stretch, // Stretch children to full width
|
||||
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
controller.isMainBottomMenuMap
|
||||
? 'Where are you going?'.tr
|
||||
: 'Quick Actions'.tr,
|
||||
style: AppStyle.title
|
||||
.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: controller.changeMainBottomMenuMap,
|
||||
icon: Icon(
|
||||
controller.isMainBottomMenuMap
|
||||
? Icons.keyboard_arrow_down_rounded
|
||||
: Icons.keyboard_arrow_up_rounded,
|
||||
size: 28,
|
||||
color: AppColor.primaryColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (controller.isMainBottomMenuMap) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: InkWell(
|
||||
onTap: () => controller.changeMainBottomMenuMap(),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.primaryColor
|
||||
.withOpacity(0.05), // Subtle background
|
||||
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: DefaultTextStyle(
|
||||
style: AppStyle.subtitle
|
||||
.copyWith(color: AppColor.writeColor),
|
||||
child: Center(
|
||||
child: controller.isPickerShown
|
||||
? clickPointPosition(controller, context)
|
||||
: whereWidgetSmall(controller),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (controller.recentPlaces.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Text('Recent Places'.tr, style: AppStyle.subtitle),
|
||||
|
||||
SizedBox(
|
||||
height: 30,
|
||||
child: Center(
|
||||
child: ListView.separated(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: controller.recentPlaces.length,
|
||||
separatorBuilder: (context, index) =>
|
||||
const SizedBox(width: 8),
|
||||
itemBuilder: (context, index) =>
|
||||
_buildRecentPlaceButton(
|
||||
controller, context, index),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
if (!controller.isAnotherOreder)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Text(
|
||||
'${'From:'.tr} ${controller.currentLocationString}'
|
||||
.tr,
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: !controller.isAnotherOreder
|
||||
? const SizedBox()
|
||||
: formSearchPlacesStart(),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: formSearchPlacesDestenation(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16)),
|
||||
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,
|
||||
hint: 'Paste location link here'.tr,
|
||||
type: TextInputType.url,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
MyElevatedButton(
|
||||
title: 'Go to this location'.tr,
|
||||
onPressed: () async {
|
||||
controller.goToWhatappLocation();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.shade100, // Lighter background
|
||||
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
|
||||
border: Border.all(
|
||||
color: Colors.blue.shade400), // Add a border
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.link, color: Colors.blue.shade700),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Paste WhatsApp location link'.tr,
|
||||
style: TextStyle(color: Colors.blue.shade700),
|
||||
),
|
||||
),
|
||||
const Icon(Icons.arrow_forward_ios_rounded,
|
||||
size: 16, color: Colors.blueGrey),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
showCupertinoModalPopup(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
CupertinoActionSheet(
|
||||
title: Text('Select Order Type'.tr),
|
||||
message: Text('Choose who this order is for'.tr),
|
||||
actions: <Widget>[
|
||||
CupertinoActionSheetAction(
|
||||
child: Text('I want to order for myself'.tr),
|
||||
onPressed: () {
|
||||
controller.changeisAnotherOreder(false);
|
||||
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
child: Text(
|
||||
'I want to order for someone else'.tr),
|
||||
onPressed: () {
|
||||
controller.changeisAnotherOreder(true);
|
||||
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
cancelButton: CupertinoActionSheetAction(
|
||||
isDefaultAction: true,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text('Cancel'.tr),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
!controller.isAnotherOreder
|
||||
? 'Order for someone else'.tr
|
||||
: 'Order for myself'.tr,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRecentPlaceButton(
|
||||
MapPassengerController controller, BuildContext context, int index) {
|
||||
final textToSpeechController = Get.find<TextToSpeechController>();
|
||||
|
||||
return 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}',
|
||||
'${controller.recentPlaces[index]['latitude']},${controller.recentPlaces[index]['longitude']}',
|
||||
);
|
||||
|
||||
controller.showBottomSheet1();
|
||||
});
|
||||
},
|
||||
onLongPress: () {
|
||||
MyDialog().getDialog(
|
||||
"Are you sure to delete this location?".tr,
|
||||
'',
|
||||
() {
|
||||
sql.deleteData(TableName.recentLocations,
|
||||
controller.recentPlaces[index]['id']);
|
||||
|
||||
controller.getFavioratePlaces();
|
||||
|
||||
controller.update();
|
||||
|
||||
Get.back();
|
||||
|
||||
mySnackbarSuccess('deleted'.tr);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.primaryColor.withOpacity(0.05), // Subtle background
|
||||
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppColor.primaryColor.withOpacity(0.1), width: 1),
|
||||
),
|
||||
),
|
||||
child: Text(controller.recentPlaces[index]['name'],
|
||||
style: const TextStyle(fontSize: 14)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget clickPointPosition(
|
||||
MapPassengerController controller, BuildContext context) {
|
||||
return TextButton(
|
||||
onPressed: () async {
|
||||
controller.clearPolyline();
|
||||
|
||||
controller.data = [];
|
||||
|
||||
if (controller.passengerStartLocationFromMap == true) {
|
||||
controller.newMyLocation = controller.newStartPointLocation;
|
||||
|
||||
controller.changeMainBottomMenuMap();
|
||||
|
||||
await controller.getDirectionMap(
|
||||
'${controller.newStartPointLocation.latitude},${controller.newStartPointLocation.longitude}',
|
||||
'${controller.myDestination.latitude},${controller.myDestination.longitude}',
|
||||
);
|
||||
|
||||
controller.currentLocationToFormPlaces = false;
|
||||
|
||||
controller.placesDestination = [];
|
||||
|
||||
controller.clearPlacesStart();
|
||||
|
||||
controller.clearPlacesDestination();
|
||||
|
||||
controller.passengerStartLocationFromMap = false;
|
||||
|
||||
controller.isPickerShown = false;
|
||||
|
||||
controller.showBottomSheet1();
|
||||
} else if (controller.startLocationFromMap == true) {
|
||||
controller.newMyLocation = controller.newStartPointLocation;
|
||||
|
||||
controller.hintTextStartPoint =
|
||||
'${controller.newStartPointLocation.latitude.toStringAsFixed(4)} , ${controller.newStartPointLocation.longitude.toStringAsFixed(4)}';
|
||||
|
||||
controller.startLocationFromMap = false;
|
||||
|
||||
controller.isPickerShown = false;
|
||||
} else if (controller.workLocationFromMap == true) {
|
||||
controller.hintTextDestinationPoint = 'To Work'.tr;
|
||||
|
||||
box.write(BoxName.addWork,
|
||||
'${controller.newMyLocation.latitude.toStringAsFixed(4)} , ${controller.newMyLocation.longitude.toStringAsFixed(4)}');
|
||||
|
||||
controller.newMyLocation = controller.newMyLocation;
|
||||
|
||||
controller.isPickerShown = false;
|
||||
|
||||
controller.workLocationFromMap = false;
|
||||
|
||||
Get.snackbar('Work Saved'.tr, '',
|
||||
backgroundColor: AppColor.greenColor);
|
||||
} else if (controller.homeLocationFromMap == true) {
|
||||
controller.hintTextDestinationPoint = 'To Home'.tr;
|
||||
|
||||
box.write(BoxName.addHome,
|
||||
'${controller.newMyLocation.latitude.toStringAsFixed(4)} , ${controller.newMyLocation.longitude.toStringAsFixed(4)}');
|
||||
|
||||
controller.newMyLocation = controller.newMyLocation;
|
||||
|
||||
controller.isPickerShown = false;
|
||||
|
||||
controller.homeLocationFromMap = false;
|
||||
|
||||
controller.update();
|
||||
|
||||
Get.snackbar('Home Saved'.tr, '',
|
||||
backgroundColor: AppColor.greenColor);
|
||||
} else {
|
||||
controller.hintTextDestinationPoint =
|
||||
'${controller.newMyLocation.latitude.toStringAsFixed(4)} , ${controller.newMyLocation.longitude.toStringAsFixed(4)}';
|
||||
|
||||
controller.myDestination = controller.newMyLocation;
|
||||
|
||||
controller.isPickerShown = false;
|
||||
|
||||
controller.changeMainBottomMenuMap();
|
||||
|
||||
controller.passengerStartLocationFromMap = true;
|
||||
|
||||
controller.isPickerShown = true;
|
||||
|
||||
if (controller.isAnotherOreder == false) {
|
||||
await controller.mapController?.animateCamera(
|
||||
CameraUpdate.newLatLng(LatLng(
|
||||
controller.passengerLocation.latitude,
|
||||
controller.passengerLocation.longitude)));
|
||||
|
||||
Get.defaultDialog(
|
||||
title: 'Destination selected'.tr,
|
||||
titleStyle: AppStyle.title,
|
||||
content: Text(
|
||||
'Now select start pick'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'OK'.tr,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
}));
|
||||
}
|
||||
|
||||
if (controller.isWhatsAppOrder == true) {
|
||||
Get.defaultDialog(
|
||||
title: 'Destination selected'.tr,
|
||||
titleStyle: AppStyle.title,
|
||||
content: Text(
|
||||
'Now select start pick'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'OK'.tr,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
controller.placesDestination = [];
|
||||
|
||||
controller.placeDestinationController.clear();
|
||||
|
||||
controller.showBottomSheet1();
|
||||
|
||||
controller.changeMainBottomMenuMap();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
controller.passengerStartLocationFromMap
|
||||
? Icons.location_on
|
||||
: Icons.location_searching,
|
||||
size: 20,
|
||||
color: AppColor.primaryColor,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
controller.passengerStartLocationFromMap
|
||||
? 'Confirm Pick-up Location'.tr
|
||||
: "Set Location on Map".tr,
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColor.primaryColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget whereWidgetSmall(MapPassengerController controller) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.location_searching, color: AppColor.primaryColor),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'${'Where to'.tr} ${(box.read(BoxName.name).toString().split(' ')[0])} ',
|
||||
style: AppStyle.subtitle),
|
||||
|
||||
// if (controller.noCarString)
|
||||
|
||||
// Text('Nearest Car: ~'.tr,
|
||||
|
||||
// style: TextStyle(color: Colors.grey.shade600))
|
||||
|
||||
// else
|
||||
|
||||
Text(
|
||||
controller.nearestCar != null
|
||||
? 'Nearest Car: ${controller.nearestDistance.toStringAsFixed(0)} m'
|
||||
: 'No cars nearby'.tr,
|
||||
style: TextStyle(color: Colors.grey.shade600),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FaviouratePlacesDialog extends StatelessWidget {
|
||||
const FaviouratePlacesDialog({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(MapPassengerController());
|
||||
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => Center(
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
List favoritePlaces =
|
||||
await sql.getAllData(TableName.placesFavorite);
|
||||
|
||||
Get.defaultDialog(
|
||||
title: 'Favorite Places'.tr,
|
||||
content: SizedBox(
|
||||
width: Get.width * .8,
|
||||
height: 300,
|
||||
child: favoritePlaces.isEmpty
|
||||
? Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.star_border_rounded,
|
||||
size: 99,
|
||||
color: AppColor.accentColor,
|
||||
),
|
||||
Text(
|
||||
'No favorite places yet!'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: ListView.separated(
|
||||
itemCount: favoritePlaces.length,
|
||||
separatorBuilder: (context, index) => const Divider(),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return ListTile(
|
||||
leading:
|
||||
const Icon(Icons.star, color: Colors.amber),
|
||||
title: Text(favoritePlaces[index]['name'],
|
||||
style: AppStyle.title),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.delete_outline,
|
||||
color: Colors.redAccent),
|
||||
onPressed: () async {
|
||||
await sql.deleteData(TableName.placesFavorite,
|
||||
favoritePlaces[index]['id']);
|
||||
|
||||
Get.back();
|
||||
|
||||
Toast.show(
|
||||
context,
|
||||
'${'Deleted'.tr} ${favoritePlaces[index]['name']} from your favorites',
|
||||
AppColor.redColor);
|
||||
},
|
||||
),
|
||||
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: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.star_border_rounded,
|
||||
color: AppColor.accentColor),
|
||||
const SizedBox(width: 8),
|
||||
Text('Favorite Places'.tr, style: AppStyle.title),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
277
lib/views/home/map_widget.dart/map_menu_widget.dart
Normal file
277
lib/views/home/map_widget.dart/map_menu_widget.dart
Normal file
@@ -0,0 +1,277 @@
|
||||
import 'package:Intaleq/constant/box_name.dart';
|
||||
import 'package:Intaleq/main.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/constant/style.dart';
|
||||
import 'package:Intaleq/views/home/my_wallet/passenger_wallet.dart';
|
||||
import 'package:Intaleq/views/home/profile/complaint_page.dart';
|
||||
import 'package:Intaleq/views/home/profile/order_history.dart';
|
||||
import 'package:Intaleq/views/home/profile/promos_passenger_page.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'dart:ui'; // مهم لإضافة تأثير الضبابية
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../notification/notification_page.dart';
|
||||
import '../HomePage/contact_us.dart';
|
||||
import '../setting_page.dart';
|
||||
import '../profile/passenger_profile_page.dart';
|
||||
|
||||
// --- الويدجت الرئيسية بالتصميم الجديد ---
|
||||
class MapMenuWidget extends StatelessWidget {
|
||||
const MapMenuWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// استخدام Get.lazyPut لضمان وجود الكنترولر
|
||||
Get.lazyPut(() => MapPassengerController());
|
||||
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => Stack(
|
||||
children: [
|
||||
// --- القائمة الجانبية المنزلقة ---
|
||||
_buildSideMenu(controller),
|
||||
|
||||
// --- زر القائمة العائم ---
|
||||
// _buildMenuButton(controller),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// --- ويدجت لبناء زر القائمة ---
|
||||
Widget _buildMenuButton(MapPassengerController controller) {
|
||||
return Positioned(
|
||||
top: 45,
|
||||
left: 16,
|
||||
child: SafeArea(
|
||||
child: InkWell(
|
||||
onTap: controller.getDrawerMenu, // نفس دالتك القديمة
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.secondaryColor.withOpacity(0.8),
|
||||
shape: BoxShape.circle,
|
||||
border:
|
||||
Border.all(color: AppColor.writeColor.withOpacity(0.2)),
|
||||
),
|
||||
child: Icon(
|
||||
controller.widthMenu > 0
|
||||
? Icons.close_rounded
|
||||
: Icons.menu_rounded,
|
||||
color: AppColor.writeColor,
|
||||
size: 26,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// --- ويدجت لبناء القائمة الجانبية ---
|
||||
Widget _buildSideMenu(MapPassengerController controller) {
|
||||
return AnimatedPositioned(
|
||||
duration: const Duration(milliseconds: 400),
|
||||
curve: Curves.fastOutSlowIn,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
// تحريك القائمة من خارج الشاشة إلى داخلها
|
||||
left: controller.widthMenu > 0 ? 0 : -Get.width,
|
||||
child: ClipRRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
|
||||
child: Container(
|
||||
width: Get.width * 0.75, // عرض القائمة
|
||||
constraints: const BoxConstraints(maxWidth: 300),
|
||||
color: AppColor.secondaryColor.withOpacity(0.9),
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// --- 1. رأس القائمة (معلومات المستخدم) ---
|
||||
_buildMenuHeader(),
|
||||
|
||||
// --- 2. الأزرار السريعة المدمجة ---
|
||||
_buildQuickActionButtons(),
|
||||
const Divider(
|
||||
color: AppColor.writeColor,
|
||||
indent: 16,
|
||||
endIndent: 16,
|
||||
height: 1),
|
||||
|
||||
// --- 3. قائمة الخيارات الرئيسية ---
|
||||
Expanded(
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
children: [
|
||||
IconMainPageMap(
|
||||
title: 'My Wallet'.tr,
|
||||
icon: Icons.account_balance_wallet_outlined,
|
||||
onTap: () => Get.to(() => const PassengerWallet())),
|
||||
IconMainPageMap(
|
||||
title: 'Order History'.tr,
|
||||
icon: Icons.history_edu_rounded,
|
||||
onTap: () => Get.to(() => const OrderHistory())),
|
||||
IconMainPageMap(
|
||||
title: 'Contact Us'.tr,
|
||||
icon: Icons.contact_support_outlined,
|
||||
onTap: () => Get.to(() => ContactUsPage())),
|
||||
IconMainPageMap(
|
||||
title: 'Driver'.tr,
|
||||
icon: Ionicons.car_sport_outline,
|
||||
onTap: () => _launchDriverAppUrl()),
|
||||
IconMainPageMap(
|
||||
title: 'Complaint'.tr,
|
||||
icon: Icons.feedback_outlined,
|
||||
onTap: () => Get.to(() => ComplaintPage())),
|
||||
IconMainPageMap(
|
||||
title: 'Promos'.tr,
|
||||
icon: Icons.local_offer_outlined,
|
||||
onTap: () =>
|
||||
Get.to(() => const PromosPassengerPage())),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// --- ويدجت مساعدة لرأس القائمة ---
|
||||
Widget _buildMenuHeader() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// CircleAvatar(
|
||||
// radius: 30,
|
||||
// backgroundColor: AppColor.primaryColor,
|
||||
// child:
|
||||
// const Icon(Icons.person, color: AppColor.writeColor, size: 35),
|
||||
// ),
|
||||
// const SizedBox(height: 12),
|
||||
Text(
|
||||
"Welcome Back!".tr, // يمكنك تغييرها لاسم المستخدم
|
||||
style: AppStyle.title
|
||||
.copyWith(color: AppColor.writeColor.withOpacity(0.7)),
|
||||
),
|
||||
Text(
|
||||
box.read(BoxName.name), // يمكنك تغييرها لاسم المستخدم
|
||||
style: AppStyle.headTitle.copyWith(fontSize: 22),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// --- ويدجت مساعدة للأزرار السريعة ---
|
||||
Widget _buildQuickActionButtons() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildSmallActionButton(
|
||||
icon: Icons.notifications_none_rounded,
|
||||
label: 'Alerts'.tr,
|
||||
onTap: () => Get.to(() => const NotificationPage())),
|
||||
_buildSmallActionButton(
|
||||
icon: Icons.person_outline_rounded,
|
||||
label: 'Profile'.tr,
|
||||
onTap: () => Get.to(() => PassengerProfilePage())),
|
||||
_buildSmallActionButton(
|
||||
icon: Icons.settings_outlined,
|
||||
label: 'Settings'.tr,
|
||||
onTap: () => Get.to(() => const SettingPage())),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSmallActionButton(
|
||||
{required IconData icon,
|
||||
required String label,
|
||||
required VoidCallback onTap}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(icon, color: AppColor.writeColor, size: 24),
|
||||
const SizedBox(height: 4),
|
||||
Text(label, style: AppStyle.subtitle.copyWith(fontSize: 12)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// --- نفس دالتك القديمة لفتح رابط تطبيق السائق ---
|
||||
void _launchDriverAppUrl() async {
|
||||
final String driverAppUrl;
|
||||
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||
driverAppUrl =
|
||||
'https://play.google.com/store/apps/details?id=com.sefer_driver';
|
||||
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
|
||||
driverAppUrl = 'https://apps.apple.com/eg/app/tripz-driver/id6502189302';
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final Uri url = Uri.parse(driverAppUrl);
|
||||
if (await canLaunchUrl(url)) {
|
||||
await launchUrl(url);
|
||||
} else {
|
||||
Get.snackbar('Error', 'Could not launch driver app store.');
|
||||
}
|
||||
} catch (e) {
|
||||
Get.snackbar('Error', 'Could not open the link.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- كلاس عناصر القائمة بالتصميم الجديد (يستخدم ListTile) ---
|
||||
class IconMainPageMap extends StatelessWidget {
|
||||
const IconMainPageMap({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.onTap,
|
||||
required this.icon,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final IconData icon;
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
onTap: onTap,
|
||||
leading:
|
||||
Icon(icon, size: 26, color: AppColor.writeColor.withOpacity(0.8)),
|
||||
title: Text(
|
||||
title.tr,
|
||||
style: AppStyle.title.copyWith(fontSize: 16),
|
||||
),
|
||||
splashColor: AppColor.primaryColor.withOpacity(0.2),
|
||||
);
|
||||
}
|
||||
}
|
||||
55
lib/views/home/map_widget.dart/menu_map_page.dart
Normal file
55
lib/views/home/map_widget.dart/menu_map_page.dart
Normal file
@@ -0,0 +1,55 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../constant/box_name.dart';
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../../main.dart';
|
||||
|
||||
class MenuIconMapPageWidget extends StatelessWidget {
|
||||
const MenuIconMapPageWidget({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => Positioned(
|
||||
top: Get.height * .008,
|
||||
left: box.read(BoxName.lang) != 'ar' ? 5 : null,
|
||||
right: box.read(BoxName.lang) == 'ar' ? 5 : null,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: AppColor.secondaryColor,
|
||||
border: Border.all(color: AppColor.accentColor)),
|
||||
child: AnimatedCrossFade(
|
||||
sizeCurve: Curves.bounceOut,
|
||||
duration: const Duration(
|
||||
milliseconds: 300), // Adjust the duration as needed
|
||||
crossFadeState: controller.heightMenuBool
|
||||
? CrossFadeState.showFirst
|
||||
: CrossFadeState.showSecond,
|
||||
firstChild: IconButton(
|
||||
onPressed: () {
|
||||
controller.getDrawerMenu();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
color: AppColor.primaryColor,
|
||||
),
|
||||
),
|
||||
secondChild: IconButton(
|
||||
onPressed: () {
|
||||
controller.getDrawerMenu();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.menu,
|
||||
color: AppColor.accentColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
86
lib/views/home/map_widget.dart/new_main_bottom_sheet.dart
Normal file
86
lib/views/home/map_widget.dart/new_main_bottom_sheet.dart
Normal file
@@ -0,0 +1,86 @@
|
||||
import 'package:Intaleq/constant/box_name.dart';
|
||||
import 'package:Intaleq/constant/colors.dart';
|
||||
import 'package:Intaleq/constant/style.dart';
|
||||
import 'package:Intaleq/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class NewMainBottomSheet extends StatelessWidget {
|
||||
const NewMainBottomSheet({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Positioned(
|
||||
bottom: 0,
|
||||
left: 5,
|
||||
right: 5,
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
width: Get.width,
|
||||
height: Get.height * .15,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(),
|
||||
borderRadius: BorderRadius.circular(15)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Text('Home'.tr),
|
||||
const Icon(Icons.home),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(),
|
||||
borderRadius: BorderRadius.circular(15)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Text('Work'.tr),
|
||||
const Icon(Icons.work_outline),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
color: AppColor.blueColor.withOpacity(.5),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Icon(Icons.search),
|
||||
Text(
|
||||
"${"Where you want go ".tr}${(box.read(BoxName.name).toString().split(' ')[0]).toString()} ?",
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
105
lib/views/home/map_widget.dart/passengerRideLoctionWidget.dart
Normal file
105
lib/views/home/map_widget.dart/passengerRideLoctionWidget.dart
Normal file
@@ -0,0 +1,105 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'dart:ui'; // مهم لإضافة تأثير الضبابية
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
|
||||
// --- الويدجت الرئيسية بالتصميم الجديد ---
|
||||
class PassengerRideLocationWidget extends StatefulWidget {
|
||||
const PassengerRideLocationWidget({super.key});
|
||||
|
||||
@override
|
||||
State<PassengerRideLocationWidget> createState() =>
|
||||
_PassengerRideLocationWidgetState();
|
||||
}
|
||||
|
||||
class _PassengerRideLocationWidgetState
|
||||
extends State<PassengerRideLocationWidget>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
late Animation<double> _animation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// --- إعداد الأنيميشن للأيقونة ---
|
||||
_animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 1200),
|
||||
)..repeat(reverse: true); // التكرار بشكل عكسي لإنشاء تأثير النبض
|
||||
|
||||
_animation = Tween<double>(begin: 0.9, end: 1.1).animate(
|
||||
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
// --- نفس شرط الإظهار الخاص بك ---
|
||||
return AnimatedPositioned(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeOut,
|
||||
bottom: controller.isPassengerRideLocationWidget
|
||||
? 20
|
||||
: -100, // حركة دخول وخروج ناعمة
|
||||
left: 20,
|
||||
right: 20,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(50.0), // حواف دائرية بالكامل
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0), // تأثير زجاجي
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.secondaryColor.withOpacity(0.85),
|
||||
borderRadius: BorderRadius.circular(50.0),
|
||||
border: Border.all(color: AppColor.writeColor.withOpacity(0.2)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// --- أيقونة متحركة لجذب الانتباه ---
|
||||
ScaleTransition(
|
||||
scale: _animation,
|
||||
child: Icon(
|
||||
Icons.location_on,
|
||||
color: AppColor.primaryColor,
|
||||
size: 28,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// --- نص إرشادي واضح ---
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Set pickup location".tr,
|
||||
style: AppStyle.title
|
||||
.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(
|
||||
"Move the map to adjust the pin".tr,
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
color: AppColor.writeColor.withOpacity(0.7),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
418
lib/views/home/map_widget.dart/payment_method.page.dart
Normal file
418
lib/views/home/map_widget.dart/payment_method.page.dart
Normal file
@@ -0,0 +1,418 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/constant/box_name.dart';
|
||||
import 'package:Intaleq/controller/functions/secure_storage.dart';
|
||||
import 'package:Intaleq/controller/home/payment/credit_card_controller.dart';
|
||||
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';
|
||||
|
||||
class PaymentMethodPage extends StatelessWidget {
|
||||
const PaymentMethodPage({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => Positioned(
|
||||
right: 5,
|
||||
bottom: 5,
|
||||
left: 5,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 400),
|
||||
height: controller.isPaymentMethodPageShown
|
||||
? controller.paymentPageShown
|
||||
: 0,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.secondaryColor,
|
||||
borderRadius: BorderRadius.circular(15)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'My Card'.tr,
|
||||
style: AppStyle.title.copyWith(fontSize: 22),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () =>
|
||||
controller.changePaymentMethodPageShown(),
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Add Card'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
// GetBuilder<CreditCardController>(
|
||||
// builder: (controller) => IconButton(
|
||||
// onPressed: () {
|
||||
// // controller.scanCard();
|
||||
// // Get.defaultDialog(content: OptionConfigureWidget(
|
||||
// // initialOptions: scanOptions,
|
||||
// // onScanOptionChanged: (newOptions) =>
|
||||
// // scanOptions = newOptions,
|
||||
// // ),
|
||||
// // );
|
||||
// },
|
||||
// icon: const Icon(Icons.contact_emergency_sharp),
|
||||
// ),
|
||||
// )
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const MyCreditCardWidget(),
|
||||
const Spacer(),
|
||||
GetBuilder<CreditCardController>(
|
||||
builder: (controller) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
MyElevatedButton(
|
||||
title: 'Add Credit Card'.tr,
|
||||
onPressed: () async {
|
||||
if (controller.formKey.currentState!
|
||||
.validate()) {
|
||||
SecureStorage().saveData(
|
||||
BoxName.cardNumber,
|
||||
controller
|
||||
.cardNumberController.text);
|
||||
SecureStorage().saveData(
|
||||
BoxName.cardHolderName,
|
||||
controller
|
||||
.cardHolderNameController.text);
|
||||
SecureStorage().saveData(
|
||||
BoxName.cvvCode,
|
||||
controller.cvvCodeController.text);
|
||||
SecureStorage().saveData(
|
||||
BoxName.expiryDate,
|
||||
controller
|
||||
.expiryDateController.text);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
class MyCreditCardWidget extends StatelessWidget {
|
||||
const MyCreditCardWidget({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(CreditCardController());
|
||||
return GetBuilder<CreditCardController>(
|
||||
builder: (controller) => Container(
|
||||
height: Get.height * .4,
|
||||
width: Get.width * .9,
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColor.secondaryColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(15)),
|
||||
gradient: LinearGradient(colors: [
|
||||
AppColor.secondaryColor,
|
||||
// AppColor.blueColor,
|
||||
// AppColor.greenColor,
|
||||
AppColor.accentColor,
|
||||
// AppColor.primaryColor,
|
||||
// AppColor.redColor,
|
||||
// AppColor.yellowColor
|
||||
]),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
spreadRadius: 3,
|
||||
offset: Offset(3, 3),
|
||||
blurRadius: 3,
|
||||
color: AppColor.redColor),
|
||||
BoxShadow(
|
||||
offset: Offset(-3, -3),
|
||||
blurRadius: 3,
|
||||
spreadRadius: 3,
|
||||
color: AppColor.redColor),
|
||||
],
|
||||
),
|
||||
child: Form(
|
||||
key: controller.formKey,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
getCardIcon(controller.cardNumberController
|
||||
.text), // Dynamic credit card icon
|
||||
SizedBox(
|
||||
width: Get.width * .03,
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * .25,
|
||||
child: Text(
|
||||
'Card Number'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * .03,
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * .4,
|
||||
height: 70,
|
||||
child: TextFormField(
|
||||
maxLength: 16,
|
||||
keyboardType: TextInputType.number,
|
||||
controller: controller.cardNumberController,
|
||||
style: const TextStyle(
|
||||
color: AppColor.blueColor,
|
||||
fontFamily: 'digital-counter-7',
|
||||
fontWeight: FontWeight.bold),
|
||||
decoration: const InputDecoration(
|
||||
helperStyle: TextStyle(
|
||||
fontFamily: 'digital-counter-7'),
|
||||
// labelText: 'Card Number',
|
||||
),
|
||||
// inputFormatters: [DigitObscuringFormatter()],
|
||||
validator: (value) {
|
||||
if (value!.isEmpty || value.length != 16) {
|
||||
return 'Please enter a valid 16-digit card number'
|
||||
.tr;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.person),
|
||||
SizedBox(
|
||||
width: Get.width * .03,
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * .25,
|
||||
child: Text(
|
||||
'Holder Name',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * .03,
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * .3,
|
||||
child: SizedBox(
|
||||
// height: 50,
|
||||
child: TextFormField(
|
||||
style: AppStyle.title,
|
||||
keyboardType: TextInputType.text,
|
||||
// maxLength: 16,
|
||||
controller: controller.cardHolderNameController,
|
||||
decoration: const InputDecoration(
|
||||
// labelText: 'Cardholder Name',
|
||||
),
|
||||
validator: (value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Please enter the cardholder name'
|
||||
.tr;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: Get.width * .4,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.date_range_outlined),
|
||||
SizedBox(
|
||||
width: Get.width * .03,
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: Get.width * .2,
|
||||
child: Text(
|
||||
'Expiry Date',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * .1,
|
||||
child: SizedBox(
|
||||
height: 60,
|
||||
child: TextFormField(
|
||||
maxLength: 4,
|
||||
keyboardType: TextInputType.datetime,
|
||||
controller:
|
||||
controller.expiryDateController,
|
||||
style: AppStyle.title,
|
||||
decoration: const InputDecoration(),
|
||||
validator: (value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Please enter the expiry date'
|
||||
.tr;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * .4,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.security),
|
||||
SizedBox(
|
||||
width: Get.width * .021,
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: Get.width * .2,
|
||||
child: Text(
|
||||
'CVV Code',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * .2,
|
||||
child: SizedBox(
|
||||
height: 60,
|
||||
child: TextFormField(
|
||||
obscureText: true,
|
||||
keyboardType: TextInputType.number,
|
||||
style: const TextStyle(
|
||||
color: AppColor.primaryColor,
|
||||
fontFamily: 'digital-counter-7'),
|
||||
maxLength: 3,
|
||||
controller:
|
||||
controller.cvvCodeController,
|
||||
decoration: const InputDecoration(
|
||||
// labelText: 'CVV Code',
|
||||
),
|
||||
validator: (value) {
|
||||
if (value!.isEmpty &&
|
||||
value.length != 3) {
|
||||
return 'Please enter the CVV code'
|
||||
.tr;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// const SizedBox(
|
||||
// height: 20,
|
||||
// ),
|
||||
MyElevatedButton(
|
||||
title: 'Save'.tr,
|
||||
onPressed: () {
|
||||
if (controller.formKey.currentState!.validate()) {
|
||||
// final creditCard = CreditCardModel(
|
||||
// cardNumber: controller.cardNumberController.text,
|
||||
// cardHolderName:
|
||||
// controller.cardHolderNameController.text,
|
||||
// expiryDate: controller.expiryDateController.text,
|
||||
// cvvCode: controller.cvvCodeController.text,
|
||||
// );
|
||||
// Process the credit card details
|
||||
// You can use GetX to handle the logic here
|
||||
|
||||
if (controller.formKey.currentState!.validate()) {
|
||||
SecureStorage().saveData(BoxName.cardNumber,
|
||||
controller.cardNumberController.text);
|
||||
SecureStorage().saveData(BoxName.cardHolderName,
|
||||
controller.cardHolderNameController.text);
|
||||
SecureStorage().saveData(BoxName.cvvCode,
|
||||
controller.cvvCodeController.text);
|
||||
SecureStorage().saveData(BoxName.expiryDate,
|
||||
controller.expiryDateController.text);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
))));
|
||||
}
|
||||
|
||||
Widget getCardIcon(String cardNumber) {
|
||||
String cardType = detectCardType(
|
||||
cardNumber); // Function to detect card type based on the first digit
|
||||
|
||||
IconData iconData;
|
||||
Color iconColor;
|
||||
|
||||
switch (cardType) {
|
||||
case 'Visa':
|
||||
iconData = Icons.credit_card_rounded;
|
||||
iconColor = Colors.blue; // Change color for Visa cards
|
||||
break;
|
||||
case 'Mastercard':
|
||||
iconData = Icons.credit_card_rounded;
|
||||
iconColor = Colors.red; // Change color for Mastercard cards
|
||||
break;
|
||||
default:
|
||||
iconData = Icons.credit_card_rounded;
|
||||
iconColor = Colors.black; // Default color for other card types
|
||||
break;
|
||||
}
|
||||
|
||||
return Icon(
|
||||
iconData,
|
||||
color: iconColor,
|
||||
);
|
||||
}
|
||||
|
||||
String detectCardType(String cardNumber) {
|
||||
if (cardNumber.startsWith('4')) {
|
||||
return 'Visa';
|
||||
} else if (cardNumber.startsWith('5')) {
|
||||
return 'Mastercard';
|
||||
} else {
|
||||
return 'Other';
|
||||
}
|
||||
}
|
||||
}
|
||||
215
lib/views/home/map_widget.dart/picker_animation_container.dart
Normal file
215
lib/views/home/map_widget.dart/picker_animation_container.dart
Normal file
@@ -0,0 +1,215 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/constant/table_names.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/home/map_passenger_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();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// DbSql sql = DbSql.instance;
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 5,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
height: controller.heightPickerContainer,
|
||||
decoration: const BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColor.accentColor, offset: Offset(2, 2)),
|
||||
BoxShadow(
|
||||
color: AppColor.accentColor, offset: Offset(-2, -2))
|
||||
],
|
||||
color: AppColor.secondaryColor,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(15),
|
||||
topRight: Radius.circular(15),
|
||||
)),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
controller.isPickerShown
|
||||
? const SizedBox()
|
||||
: Text(
|
||||
'Hi, Where to '.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
controller.isPickerShown
|
||||
? InkWell(
|
||||
onTapDown: (details) {
|
||||
controller.changePickerShown();
|
||||
controller.changeHeightPlaces();
|
||||
},
|
||||
child: Container(
|
||||
height: 7,
|
||||
width: Get.width * .3,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.accentColor,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: AppColor.accentColor,
|
||||
)),
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
controller.isPickerShown
|
||||
? InkWell(
|
||||
onTap: () {},
|
||||
child: formSearchPlacesDestenation(),
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
controller.changePickerShown();
|
||||
},
|
||||
child: Text(
|
||||
"Pick your destination from Map".tr,
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
List favoritePlaces = await sql
|
||||
.getAllData(TableName.placesFavorite);
|
||||
Get.defaultDialog(
|
||||
title: 'Favorite Places'.tr,
|
||||
content: SizedBox(
|
||||
width: Get.width * .8,
|
||||
height: 300,
|
||||
child: favoritePlaces.isEmpty
|
||||
? Center(
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons
|
||||
.hourglass_empty_rounded,
|
||||
size: 99,
|
||||
color: AppColor
|
||||
.primaryColor,
|
||||
),
|
||||
Text(
|
||||
'You Dont Have Any places yet !'
|
||||
.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount:
|
||||
favoritePlaces.length,
|
||||
itemBuilder:
|
||||
(BuildContext context,
|
||||
int index) {
|
||||
return Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await controller
|
||||
.getDirectionMap(
|
||||
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
||||
'${favoritePlaces[index]['latitude']},${favoritePlaces[index]['longitude']}',
|
||||
);
|
||||
controller
|
||||
.changePickerShown();
|
||||
controller
|
||||
.changeBottomSheetShown();
|
||||
controller
|
||||
.bottomSheet();
|
||||
Get.back();
|
||||
},
|
||||
child: Text(
|
||||
favoritePlaces[
|
||||
index]['name'],
|
||||
style:
|
||||
AppStyle.title,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await sql.deleteData(
|
||||
TableName
|
||||
.placesFavorite,
|
||||
favoritePlaces[
|
||||
index]
|
||||
['id']);
|
||||
Get.back();
|
||||
Get.snackbar(
|
||||
'Deleted ',
|
||||
'${'You are Delete'.tr} ${favoritePlaces[index]['name']} from your list',
|
||||
backgroundColor:
|
||||
AppColor
|
||||
.accentColor);
|
||||
},
|
||||
icon: const Icon(Icons
|
||||
.favorite_outlined),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
onCancel: () {},
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
"Go To Favorite Places".tr,
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (controller.isPickerShown &&
|
||||
controller.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}',
|
||||
);
|
||||
controller.changePickerShown();
|
||||
controller.changeBottomSheetShown();
|
||||
controller.bottomSheet();
|
||||
// await sql
|
||||
// .getAllData(TableName.placesFavorite)
|
||||
},
|
||||
),
|
||||
if (controller.isPickerShown &&
|
||||
controller.placesDestination.isEmpty)
|
||||
const SizedBox(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
329
lib/views/home/map_widget.dart/points_page_for_rider.dart
Normal file
329
lib/views/home/map_widget.dart/points_page_for_rider.dart
Normal file
@@ -0,0 +1,329 @@
|
||||
import 'package:flutter/material.dart';
|
||||
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/points_for_rider_controller.dart';
|
||||
|
||||
class PointsPageForRider extends StatelessWidget {
|
||||
PointsPageForRider({
|
||||
super.key,
|
||||
});
|
||||
MapPassengerController mapPassengerController =
|
||||
Get.put(MapPassengerController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(WayPointController());
|
||||
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
return Positioned(
|
||||
bottom: 2,
|
||||
left: 2,
|
||||
right: 2,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
height: controller.wayPointSheetHeight,
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: ListView(
|
||||
children: [
|
||||
// const AppBarPointsPageForRider(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
mapPassengerController.downPoints();
|
||||
},
|
||||
icon: const Icon(Icons.arrow_drop_down_circle_outlined),
|
||||
),
|
||||
GetBuilder<WayPointController>(builder: (wayPointController) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
wayPointController.addWayPoints();
|
||||
controller.isWayPointStopsSheetUtilGetMap = true;
|
||||
},
|
||||
child: const Text('Add Stops'),
|
||||
),
|
||||
wayPointController.wayPoints.length > 1
|
||||
? ElevatedButton(
|
||||
onPressed: () async {
|
||||
mapPassengerController
|
||||
.getMapPointsForAllMethods();
|
||||
},
|
||||
child: const Text('Get Direction'),
|
||||
)
|
||||
: const SizedBox()
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: Get.height * .36,
|
||||
child: GetBuilder<WayPointController>(
|
||||
builder: (wayPointController) {
|
||||
return ReorderableListView(
|
||||
// The children of the list are the text fields
|
||||
children: wayPointController.wayPoints
|
||||
.asMap()
|
||||
.entries
|
||||
.map((entry) {
|
||||
final index = entry.key;
|
||||
final wayPoint = entry.value;
|
||||
return Padding(
|
||||
key: ValueKey(index),
|
||||
padding: const EdgeInsets.all(1),
|
||||
child: ListTile(
|
||||
leading: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.deepPurpleAccent,
|
||||
border: Border.all(),
|
||||
shape: BoxShape.rectangle),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(2),
|
||||
child: Text(
|
||||
index.toString(),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
)),
|
||||
title: InkWell(
|
||||
onTap: () {
|
||||
// showAddLocationDialog(context);
|
||||
Get.defaultDialog(
|
||||
content: SizedBox(
|
||||
width: Get.width,
|
||||
height: 400,
|
||||
child: mapPassengerController
|
||||
.placeListResponse[index]),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(),
|
||||
color:
|
||||
AppColor.accentColor.withOpacity(.5)),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(index > 0
|
||||
? mapPassengerController
|
||||
.currentLocationStringAll[index]
|
||||
.toString()
|
||||
: ''),
|
||||
const Icon(
|
||||
Icons.reorder,
|
||||
size: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
trailing: index > 0
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () {
|
||||
wayPointController.removeTextField(index);
|
||||
},
|
||||
)
|
||||
: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
color: AppColor.secondaryColor,
|
||||
),
|
||||
onPressed: () {},
|
||||
)),
|
||||
);
|
||||
}).toList(),
|
||||
|
||||
// The callback when the user reorders the text fields
|
||||
onReorder: (int oldIndex, int newIndex) {
|
||||
wayPointController.reorderTextFields(oldIndex, newIndex);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// GetBuilder<PointsForRiderController>(
|
||||
// builder: (controller) => Container(
|
||||
// decoration: AppStyle.boxDecoration,
|
||||
// height: Get.height *
|
||||
// .5, // height: controller.heightPointsPageForRider,
|
||||
// width: Get.width,
|
||||
// child: Column(
|
||||
// children: [
|
||||
// SizedBox(
|
||||
// height: 300,
|
||||
// child: ReorderableListView(
|
||||
// onReorder: (oldIndex, newIndex) {
|
||||
// if (oldIndex < newIndex) {
|
||||
// newIndex -= 1;
|
||||
// }
|
||||
// pointsForRiderController.locations.insert(
|
||||
// newIndex,
|
||||
// pointsForRiderController.locations
|
||||
// .removeAt(oldIndex));
|
||||
// },
|
||||
// children: [
|
||||
// for (int i = 0;
|
||||
// i < pointsForRiderController.locations.length;
|
||||
// i++)
|
||||
// ListTile(
|
||||
// key: Key('$i'),
|
||||
// title: DragTarget<int>(
|
||||
// onAccept: (int data) {
|
||||
// pointsForRiderController.locations
|
||||
// .insert(i, 'New Text Field');
|
||||
// },
|
||||
// builder: (context, candidateData, rejectedData) {
|
||||
// return Row(
|
||||
// children: [
|
||||
// SizedBox(
|
||||
// width: 300,
|
||||
// child: TextField(
|
||||
// controller: TextEditingController(
|
||||
// text: pointsForRiderController
|
||||
// .locations[i]),
|
||||
// onChanged: (value) {
|
||||
// pointsForRiderController
|
||||
// .locations[i] = value;
|
||||
// },
|
||||
// decoration: InputDecoration(
|
||||
// prefixIcon: IconButton(
|
||||
// onPressed: () {
|
||||
// pointsForRiderController
|
||||
// .removeLocation(i);
|
||||
// },
|
||||
// icon: const Icon(Icons.delete),
|
||||
// ),
|
||||
// labelText: 'Text Field ${i + 1}',
|
||||
// border: const OutlineInputBorder(),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// IconButton(
|
||||
// onPressed: () {
|
||||
// // pointsForRiderController.onReorder(
|
||||
// // index, newIndex);
|
||||
// },
|
||||
// icon: const Icon(Icons.reorder),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ElevatedButton(
|
||||
// onPressed: () {
|
||||
// pointsForRiderController.addLocation('location');
|
||||
// },
|
||||
// child: const Text('Add Text Field'),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ));
|
||||
}
|
||||
|
||||
void showAddLocationDialog(BuildContext context, int index) {
|
||||
final TextEditingController locationController = TextEditingController();
|
||||
// Get.put(WayPointController());
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Dialog.fullscreen(
|
||||
// title: const Text('Add Location'),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
size: 40,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'Add Location'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const Icon(
|
||||
Icons.clear,
|
||||
color: AppColor.secondaryColor,
|
||||
)
|
||||
],
|
||||
),
|
||||
// SizedBox(
|
||||
// width: Get.width,
|
||||
// child: formSearchCaptain(),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class AppBarPointsPageForRider extends StatelessWidget {
|
||||
const AppBarPointsPageForRider({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.arrow_back_ios_new_rounded,
|
||||
color: AppColor.primaryColor,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
child: Row(
|
||||
children: [
|
||||
const CircleAvatar(
|
||||
backgroundColor: AppColor.primaryColor,
|
||||
maxRadius: 15,
|
||||
child: Icon(
|
||||
Icons.person,
|
||||
color: AppColor.secondaryColor,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
child: Text(
|
||||
"Switch Rider".tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.clear,
|
||||
color: AppColor.secondaryColor,
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
286
lib/views/home/map_widget.dart/ride_begin_passenger.dart
Normal file
286
lib/views/home/map_widget.dart/ride_begin_passenger.dart
Normal file
@@ -0,0 +1,286 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/constant/box_name.dart';
|
||||
import 'package:Intaleq/controller/profile/profile_controller.dart';
|
||||
import 'package:Intaleq/main.dart';
|
||||
import 'package:Intaleq/views/home/profile/complaint_page.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/links.dart';
|
||||
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';
|
||||
|
||||
// --- الويدجت الرئيسية بالتصميم الجديد ---
|
||||
class RideBeginPassenger extends StatelessWidget {
|
||||
const RideBeginPassenger({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// --- نفس منطق استدعاء الكنترولرز ---
|
||||
final ProfileController profileController = Get.put(ProfileController());
|
||||
final AudioRecorderController audioController =
|
||||
Get.put(AudioRecorderController());
|
||||
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
// --- نفس شرط الإظهار الخاص بك ---
|
||||
if (controller.statusRide != 'Begin') {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.secondaryColor,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(24),
|
||||
topRight: Radius.circular(24),
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
blurRadius: 20,
|
||||
offset: const Offset(0, -5),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// مقبض السحب (Handle)
|
||||
Container(
|
||||
width: 40,
|
||||
height: 5,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.writeColor.withOpacity(0.3),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// --- 1. قسم معلومات السائق ---
|
||||
_buildDriverInfo(controller),
|
||||
const Divider(height: 24, thickness: 0.5),
|
||||
|
||||
// --- 2. قسم تقدم الرحلة ---
|
||||
_buildTripProgress(controller),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// --- 3. قسم الإجراءات والأمان ---
|
||||
_buildActionButtons(
|
||||
context, controller, profileController, audioController),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// --- ويدجت مساعدة لعرض معلومات السائق بشكل منظم ---
|
||||
Widget _buildDriverInfo(MapPassengerController controller) {
|
||||
return Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 28,
|
||||
backgroundImage: NetworkImage(
|
||||
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg'),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(controller.driverName,
|
||||
style: AppStyle.title.copyWith(fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
'${controller.make} ${controller.model} • ${box.read(BoxName.carType)}',
|
||||
style: AppStyle.subtitle
|
||||
.copyWith(color: AppColor.writeColor.withOpacity(0.7)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.writeColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(
|
||||
controller.licensePlate,
|
||||
style: AppStyle.subtitle
|
||||
.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.5),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Text(controller.driverRate,
|
||||
style: AppStyle.subtitle
|
||||
.copyWith(fontWeight: FontWeight.bold)),
|
||||
const SizedBox(width: 2),
|
||||
const Icon(Icons.star_rounded,
|
||||
color: AppColor.yellowColor, size: 16),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// --- ويدجت مساعدة لعرض شريط التقدم ---
|
||||
Widget _buildTripProgress(MapPassengerController controller) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Time to Destination'.tr, style: AppStyle.subtitle),
|
||||
Text(controller.stringRemainingTimeRideBegin,
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
fontWeight: FontWeight.bold, color: AppColor.primaryColor)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: LinearProgressIndicator(
|
||||
backgroundColor: AppColor.primaryColor.withOpacity(0.2),
|
||||
color: controller.remainingTimeTimerRideBegin < 60
|
||||
? AppColor.redColor
|
||||
: AppColor.greenColor,
|
||||
minHeight: 10,
|
||||
value: controller.progressTimerRideBegin.toDouble(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// --- ويدجت مساعدة لعرض أزرار الإجراءات ---
|
||||
Widget _buildActionButtons(
|
||||
BuildContext context,
|
||||
MapPassengerController controller,
|
||||
ProfileController profileController,
|
||||
AudioRecorderController audioController) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_buildActionButton(
|
||||
icon: Icons.sos_rounded,
|
||||
label: 'SOS'.tr,
|
||||
color: AppColor.redColor,
|
||||
onTap: () async {
|
||||
// --- نفس منطقك القديم ---
|
||||
if (box.read(BoxName.sosPhonePassenger) == null) {
|
||||
await profileController.updatField(
|
||||
'sosPhone', TextInputType.phone);
|
||||
box.write(BoxName.sosPhonePassenger,
|
||||
profileController.prfoileData['sosPhone']);
|
||||
} else {
|
||||
makePhoneCall('122');
|
||||
}
|
||||
}),
|
||||
_buildActionButton(
|
||||
icon: FontAwesome.whatsapp,
|
||||
label: 'WhatsApp'.tr,
|
||||
color: AppColor.greenColor,
|
||||
onTap: () async {
|
||||
// --- نفس منطقك القديم ---
|
||||
if (box.read(BoxName.sosPhonePassenger) == null ||
|
||||
box.read(BoxName.sosPhonePassenger) == 'sos') {
|
||||
await profileController.updatField(
|
||||
'sosPhone', TextInputType.phone);
|
||||
box.write(BoxName.sosPhonePassenger,
|
||||
profileController.prfoileData['sosPhone']);
|
||||
} else {
|
||||
final phoneNumber =
|
||||
box.read(BoxName.sosPhonePassenger).toString();
|
||||
final phone = box.read(BoxName.countryCode) == 'Egypt'
|
||||
? '+2$phoneNumber'
|
||||
: '+962$phoneNumber';
|
||||
controller.sendWhatsapp(phone);
|
||||
}
|
||||
}),
|
||||
_buildActionButton(
|
||||
icon: Foundation.video,
|
||||
label: 'Video Call'.tr,
|
||||
color: AppColor.blueColor,
|
||||
onTap: () async {
|
||||
// --- نفس منطقك القديم ---
|
||||
await controller.getTokenForParent();
|
||||
}),
|
||||
_buildActionButton(
|
||||
icon: audioController.isRecording
|
||||
? Icons.mic_off_rounded
|
||||
: Icons.mic_none_rounded,
|
||||
label: audioController.isRecording ? 'Stop'.tr : 'Record'.tr,
|
||||
color: AppColor.primaryColor,
|
||||
onTap: () async {
|
||||
// --- نفس منطقك القديم ---
|
||||
if (audioController.isRecording == false) {
|
||||
await audioController.startRecording();
|
||||
Toast.show(context, 'Start Record'.tr, AppColor.greenColor);
|
||||
} else {
|
||||
await audioController.stopRecording();
|
||||
Toast.show(context, 'Record saved'.tr, AppColor.greenColor);
|
||||
}
|
||||
},
|
||||
),
|
||||
_buildActionButton(
|
||||
icon: Icons.note_add_outlined,
|
||||
label: 'Complaint'.tr,
|
||||
color: AppColor.yellowColor,
|
||||
onTap: () {
|
||||
// --- نفس منطقك القديم ---
|
||||
Get.to(() => ComplaintPage(), transition: Transition.downToUp);
|
||||
}),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// --- ويدجت مساعدة لبناء زر إجراء فردي ---
|
||||
Widget _buildActionButton(
|
||||
{required IconData icon,
|
||||
required String label,
|
||||
required Color color,
|
||||
required VoidCallback onTap}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(icon, color: color, size: 26),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(label, style: AppStyle.subtitle.copyWith(fontSize: 12)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
174
lib/views/home/map_widget.dart/ride_from_start_app.dart
Normal file
174
lib/views/home/map_widget.dart/ride_from_start_app.dart
Normal file
@@ -0,0 +1,174 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../constant/box_name.dart';
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../../controller/profile/profile_controller.dart';
|
||||
import '../../../main.dart';
|
||||
|
||||
class RideFromStartApp extends StatelessWidget {
|
||||
const RideFromStartApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ProfileController profileController = Get.put(ProfileController());
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
return (controller.statusRideFromStart
|
||||
// || controller.statusRide == 'Begin'
|
||||
)
|
||||
? Positioned(
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 4,
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
height: Get.height * .3,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Container(
|
||||
width: Get.width * .15,
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'⏱️',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
box.read(BoxName.arrivalTime),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: Get.width * .15,
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'📍',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
controller.rideStatusFromStartApp['data']
|
||||
['distance']
|
||||
.toString(),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: Get.width * .15,
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'💵 ',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
controller.rideStatusFromStartApp['data']
|
||||
['price'],
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 30,
|
||||
backgroundImage: NetworkImage(
|
||||
// '',
|
||||
// ),
|
||||
'https://ride.mobile-app.store/portrate_captain_image/${controller.rideStatusFromStartApp['data']['driver_id']}.jpg'),
|
||||
),
|
||||
Text(
|
||||
'${controller.rideStatusFromStartApp['data']['driverName']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Text(
|
||||
'${controller.rideStatusFromStartApp['data']['rateDriver']} 📈',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'${controller.rideStatusFromStartApp['data']['carType']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
if (box.read(BoxName.sosPhonePassenger) == null) {
|
||||
{
|
||||
await profileController.updatField(
|
||||
'sosPhone', TextInputType.phone);
|
||||
box.write(BoxName.sosPhonePassenger,
|
||||
profileController.prfoileData['sosPhone']);
|
||||
}
|
||||
} else {
|
||||
controller
|
||||
.sendSMS(box.read(BoxName.sosPhonePassenger));
|
||||
}
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.sos_rounded,
|
||||
color: AppColor.redColor,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
if (box.read(BoxName.sosPhonePassenger) == null ||
|
||||
box.read(BoxName.sosPhonePassenger) == 'sos') {
|
||||
{
|
||||
await profileController.updatField(
|
||||
'sosPhone', TextInputType.phone);
|
||||
box.write(BoxName.sosPhonePassenger,
|
||||
profileController.prfoileData['sosPhone']);
|
||||
}
|
||||
} else {
|
||||
String phoneNumber = box
|
||||
.read(BoxName.sosPhonePassenger)
|
||||
.toString();
|
||||
// phoneNumber = phoneNumber.replaceAll('0', '');
|
||||
var phone =
|
||||
// '+${box.read(BoxName.countryCode)}${box.read(BoxName.sosPhonePassenger)}';
|
||||
'${box.read(BoxName.sosPhonePassenger)}';
|
||||
controller.sendWhatsapp(phone);
|
||||
}
|
||||
},
|
||||
icon: const Icon(
|
||||
FontAwesome.whatsapp,
|
||||
color: AppColor.greenColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox();
|
||||
});
|
||||
}
|
||||
}
|
||||
283
lib/views/home/map_widget.dart/searching_captain_window.dart
Normal file
283
lib/views/home/map_widget.dart/searching_captain_window.dart
Normal file
@@ -0,0 +1,283 @@
|
||||
import 'dart:async';
|
||||
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/views/widgets/elevated_btn.dart';
|
||||
import 'package:Intaleq/views/widgets/my_textField.dart';
|
||||
|
||||
// --- الويدجت الرئيسية بالتصميم الجديد ---
|
||||
class SearchingCaptainWindow extends StatefulWidget {
|
||||
const SearchingCaptainWindow({super.key});
|
||||
|
||||
@override
|
||||
State<SearchingCaptainWindow> createState() => _SearchingCaptainWindowState();
|
||||
}
|
||||
|
||||
class _SearchingCaptainWindowState extends State<SearchingCaptainWindow>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(seconds: 2),
|
||||
)..repeat();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) {
|
||||
return AnimatedPositioned(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
bottom: controller.isSearchingWindow ? 0 : -Get.height * 0.4,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.fromLTRB(20, 20, 20, 16),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.secondaryColor,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(24),
|
||||
topRight: Radius.circular(24),
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
blurRadius: 20,
|
||||
offset: const Offset(0, -5),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// --- 1. أنيميشن الرادار ---
|
||||
_buildRadarAnimation(controller),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// --- 2. زر الإلغاء ---
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
// --- نفس منطقك للإلغاء ---
|
||||
controller.cancelRide();
|
||||
},
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: AppColor.writeColor,
|
||||
side: BorderSide(
|
||||
color: AppColor.writeColor.withOpacity(0.3)),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12)),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
),
|
||||
child: Text('Cancel Search'.tr),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// --- ويدجت بناء أنيميشن الرادار ---
|
||||
Widget _buildRadarAnimation(MapPassengerController controller) {
|
||||
return SizedBox(
|
||||
height: 180, // ارتفاع ثابت لمنطقة الأنيميشن
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
// --- دوائر الرادار المتحركة ---
|
||||
...List.generate(3, (index) {
|
||||
return FadeTransition(
|
||||
opacity: Tween<double>(begin: 1.0, end: 0.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: Interval((index) / 3, 1.0, curve: Curves.easeInOut),
|
||||
),
|
||||
),
|
||||
child: ScaleTransition(
|
||||
scale: Tween<double>(begin: 0.3, end: 1.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: Interval((index) / 3, 1.0, curve: Curves.easeInOut),
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: AppColor.primaryColor.withOpacity(0.7),
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
// --- المحتوى في المنتصف ---
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
controller.driversStatusForSearchWindow,
|
||||
style: AppStyle.headTitle.copyWith(fontSize: 20),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Searching for the nearest captain...'.tr,
|
||||
style: AppStyle.subtitle
|
||||
.copyWith(color: AppColor.writeColor.withOpacity(0.7)),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// --- استدعاء نفس دالة المؤقت الخاصة بك ---
|
||||
buildTimerForIncrease(controller),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// --- نفس دالة المؤقت الخاصة بك مع تعديلات شكلية بسيطة ---
|
||||
Widget buildTimerForIncrease(MapPassengerController mapPassengerController) {
|
||||
return StreamBuilder<int>(
|
||||
stream: Stream.periodic(const Duration(seconds: 1))
|
||||
.map((_) => ++mapPassengerController.currentTimeSearchingCaptainWindow),
|
||||
initialData: 0,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.data! > 30) {
|
||||
// --- عرض زر زيادة الأجرة بنفس منطقك القديم ---
|
||||
return TextButton(
|
||||
onPressed: () =>
|
||||
_showIncreaseFeeDialog(context, mapPassengerController),
|
||||
child: Text(
|
||||
"No one accepted? Try increasing the fare.".tr,
|
||||
style: AppStyle.title.copyWith(
|
||||
color: AppColor.primaryColor,
|
||||
decoration: TextDecoration.underline),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final double progress = (snapshot.data ?? 0).toDouble() / 30.0;
|
||||
|
||||
return SizedBox(
|
||||
height: 40,
|
||||
width: 40,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
value: progress,
|
||||
strokeWidth: 3,
|
||||
color: AppColor.primaryColor,
|
||||
backgroundColor: AppColor.primaryColor.withOpacity(0.2),
|
||||
),
|
||||
Center(
|
||||
child: Text(
|
||||
'${snapshot.data ?? 0}',
|
||||
style: AppStyle.title.copyWith(
|
||||
color: AppColor.writeColor, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// --- دالة لعرض نافذة زيادة الأجرة (مأخوذة من منطقك القديم) ---
|
||||
void _showIncreaseFeeDialog(
|
||||
BuildContext context, MapPassengerController mapPassengerController) {
|
||||
Get.defaultDialog(
|
||||
barrierDismissible: false,
|
||||
title: "Increase Your Trip Fee (Optional)".tr,
|
||||
titleStyle: AppStyle.title,
|
||||
content: Column(
|
||||
children: [
|
||||
Text(
|
||||
"We haven't found any drivers yet. Consider increasing your trip fee to make your offer more attractive to drivers."
|
||||
.tr,
|
||||
style: AppStyle.subtitle,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
mapPassengerController.increasFeeFromPassenger.text =
|
||||
(mapPassengerController.totalPassenger + 3)
|
||||
.toStringAsFixed(1);
|
||||
mapPassengerController.update();
|
||||
},
|
||||
icon: const Icon(Icons.add_circle,
|
||||
size: 40, color: AppColor.greenColor),
|
||||
),
|
||||
SizedBox(
|
||||
width: 100,
|
||||
child: Form(
|
||||
key: mapPassengerController.increaseFeeFormKey,
|
||||
child: MyTextForm(
|
||||
controller: mapPassengerController.increasFeeFromPassenger,
|
||||
label:
|
||||
mapPassengerController.totalPassenger.toStringAsFixed(2),
|
||||
hint:
|
||||
mapPassengerController.totalPassenger.toStringAsFixed(2),
|
||||
type: TextInputType.number,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
mapPassengerController.increasFeeFromPassenger.text =
|
||||
(mapPassengerController.totalPassenger - 3)
|
||||
.toStringAsFixed(1);
|
||||
mapPassengerController.update();
|
||||
},
|
||||
icon: const Icon(Icons.remove_circle,
|
||||
size: 40, color: AppColor.redColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text("No, thanks".tr,
|
||||
style: const TextStyle(color: AppColor.redColor)),
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
mapPassengerController.cancelRide();
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(backgroundColor: AppColor.greenColor),
|
||||
child: Text("Increase Fee".tr),
|
||||
onPressed: () =>
|
||||
mapPassengerController.increaseFeeByPassengerAndReOrder(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
340
lib/views/home/map_widget.dart/select_driver_mishwari.dart
Normal file
340
lib/views/home/map_widget.dart/select_driver_mishwari.dart
Normal file
@@ -0,0 +1,340 @@
|
||||
import 'package:Intaleq/constant/colors.dart';
|
||||
import 'package:Intaleq/constant/style.dart';
|
||||
import 'package:Intaleq/controller/home/map_passenger_controller.dart';
|
||||
import 'package:Intaleq/views/widgets/elevated_btn.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../constant/links.dart';
|
||||
import '../../../print.dart';
|
||||
|
||||
class CupertinoDriverListWidget extends StatelessWidget {
|
||||
MapPassengerController mapPassengerController =
|
||||
Get.put(MapPassengerController());
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: Text('Driver List'.tr), // Ensure text is properly localized
|
||||
),
|
||||
child: SafeArea(
|
||||
child: mapPassengerController.driversForMishwari.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
'No drivers available at the moment. Please try again later.'
|
||||
.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 18, // Adjust the size as needed
|
||||
fontWeight: FontWeight.w600,
|
||||
color: CupertinoColors.inactiveGray, // Customize color
|
||||
),
|
||||
textAlign: TextAlign.center, // Center-align the text
|
||||
),
|
||||
)
|
||||
: ListView.separated(
|
||||
itemCount: mapPassengerController.driversForMishwari.length,
|
||||
separatorBuilder: (context, index) =>
|
||||
const Divider(height: 1),
|
||||
itemBuilder: (context, index) {
|
||||
var driver =
|
||||
mapPassengerController.driversForMishwari[index];
|
||||
return Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: CupertinoListTile(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4, horizontal: 8),
|
||||
leading: CircleAvatar(
|
||||
radius: 25,
|
||||
backgroundImage: NetworkImage(
|
||||
'${AppLink.IntaleqCairoServer}/portrate_captain_image/${driver['id']}.jpg',
|
||||
),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return Image.network(
|
||||
'${AppLink.IntaleqCairoServer}/portrate_captain_image/${driver['id']}.jpg',
|
||||
fit: BoxFit.cover,
|
||||
loadingBuilder: (BuildContext context,
|
||||
Widget child,
|
||||
ImageChunkEvent? loadingProgress) {
|
||||
if (loadingProgress == null) {
|
||||
return child; // Image is loaded
|
||||
} else {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(
|
||||
value: loadingProgress
|
||||
.expectedTotalBytes !=
|
||||
null
|
||||
? loadingProgress
|
||||
.cumulativeBytesLoaded /
|
||||
(loadingProgress
|
||||
.expectedTotalBytes ??
|
||||
1)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
errorBuilder: (BuildContext context,
|
||||
Object error, StackTrace? stackTrace) {
|
||||
return const Icon(
|
||||
Icons
|
||||
.person, // Icon to show when image fails to load
|
||||
size: 25, // Adjust the size as needed
|
||||
color: AppColor
|
||||
.blueColor, // Color for the error icon
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${driver['NAME'].toString().split(' ')[0]} ${driver['NAME'].toString().split(' ')[1]}',
|
||||
style:
|
||||
const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text('${'Age'.tr}: ${driver['age'].toString()}'),
|
||||
Row(
|
||||
children: [
|
||||
const Icon(CupertinoIcons.star_fill,
|
||||
size: 16,
|
||||
color: CupertinoColors.systemYellow),
|
||||
const SizedBox(width: 4),
|
||||
Text(driver['rating']?.toStringAsFixed(1) ??
|
||||
'N/A'.tr),
|
||||
const SizedBox(width: 8),
|
||||
Text('${'Rides'.tr}: ${driver['ride_count']}'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${'Car'.tr}: ${driver['make']} ${driver['model']} (${driver['year']})'),
|
||||
Text('${'Plate'.tr}: ${driver['car_plate']}'),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SizedBox(
|
||||
// width: Get.width * .3,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('${'Color'.tr}: ${driver['color']}'),
|
||||
const SizedBox(width: 8),
|
||||
Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: driver['color_hex']
|
||||
.toString() ==
|
||||
'null'
|
||||
? Colors.amber
|
||||
: hexToColor(driver['color_hex']
|
||||
.toString()),
|
||||
borderRadius:
|
||||
BorderRadius.circular(4),
|
||||
border: Border.all(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
Log.print(' driver["id"]: ${driver['driver_id']}');
|
||||
Get.find<MapPassengerController>().driverIdVip =
|
||||
driver['driver_id'];
|
||||
|
||||
// Handle driver selection
|
||||
Get.defaultDialog(
|
||||
title:
|
||||
'${'Selected driver'.tr}: ${driver['NAME']}',
|
||||
content: Column(
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${'Car'.tr}: ${driver['make']} ${driver['model']} (${driver['year']})'),
|
||||
Text(
|
||||
'${'Plate'.tr}: ${driver['car_plate']}'),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'${'Color'.tr}: ${driver['color']}'),
|
||||
const SizedBox(width: 8),
|
||||
Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: driver['color_hex']
|
||||
.toString() ==
|
||||
'null'
|
||||
? Colors.amber
|
||||
: hexToColor(
|
||||
driver['color_hex']
|
||||
.toString()),
|
||||
borderRadius:
|
||||
BorderRadius.circular(4),
|
||||
border: Border.all(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'OK'.tr,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
showDateTimePickerDialog(driver);
|
||||
}));
|
||||
print('${'Selected driver'.tr}: ${driver['NAME']}');
|
||||
// Get.back(); // Close the dialog
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
Color hexToColor(String hexColor) {
|
||||
hexColor = hexColor.replaceAll("#", "");
|
||||
String colorString = "ff$hexColor";
|
||||
return Color(int.parse(colorString, radix: 16));
|
||||
}
|
||||
|
||||
void showDriverSelectionDialog(Map<String, dynamic> driver) {
|
||||
Get.defaultDialog(
|
||||
title: '${'Selected driver'.tr}: ${driver['name']}',
|
||||
content: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${'Car'.tr}: ${driver['make']} ${driver['model']} (${driver['year']})'),
|
||||
Text('${'Plate'.tr}: ${driver['car_plate']}'),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('${'Color'.tr}: ${driver['color']}'),
|
||||
const SizedBox(width: 8),
|
||||
Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: driver['color_hex'].toString() == 'null'
|
||||
? Colors.amber
|
||||
: hexToColor(driver['color_hex'].toString()),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
border: Border.all(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'OK'.tr,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
showDateTimePickerDialog(driver);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void showDateTimePickerDialog(Map<String, dynamic> driver) {
|
||||
DateTime selectedDateTime = DateTime.now();
|
||||
|
||||
Get.defaultDialog(
|
||||
barrierDismissible: false,
|
||||
title: "Select date and time of trip".tr,
|
||||
content: SizedBox(
|
||||
// height: 400, // Adjust height as needed
|
||||
width: double.maxFinite,
|
||||
child: Column(
|
||||
children: [
|
||||
DateTimePickerWidget(),
|
||||
],
|
||||
),
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Confirm Trip'.tr,
|
||||
onPressed: () async {
|
||||
DateTime selectedDateTime =
|
||||
mapPassengerController.selectedDateTime.value;
|
||||
// Save trip data and set up notifications
|
||||
Get.back();
|
||||
await mapPassengerController.saveTripData(driver, selectedDateTime);
|
||||
},
|
||||
),
|
||||
cancel: MyElevatedButton(
|
||||
kolor: AppColor.redColor,
|
||||
title: 'Cancel'.tr,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DateTimePickerWidget extends StatelessWidget {
|
||||
final MapPassengerController controller = Get.put(MapPassengerController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
transitionBetweenRoutes: false,
|
||||
automaticallyImplyLeading: false,
|
||||
middle: Text('Date and Time Picker'.tr),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Obx(() => Text(
|
||||
'${'Selected Date and Time'.tr}: ${controller.selectedDateTime.value}',
|
||||
style: const TextStyle(fontSize: 18),
|
||||
textAlign: TextAlign.center,
|
||||
)),
|
||||
const SizedBox(height: 20),
|
||||
SizedBox(
|
||||
height: 200,
|
||||
child: CupertinoDatePicker(
|
||||
mode: CupertinoDatePickerMode.dateAndTime,
|
||||
initialDateTime: controller.selectedDateTime.value,
|
||||
onDateTimeChanged: (newDateTime) {
|
||||
controller.updateDateTime(newDateTime);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
|
||||
GetBuilder<MapPassengerController> timerForCancelTripFromPassenger() {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) {
|
||||
final isNearEnd =
|
||||
controller.remainingTime <= 5; // Define a threshold for "near end"
|
||||
|
||||
return controller.remainingTime > 0 && controller.remainingTime != 25
|
||||
? Positioned(
|
||||
bottom: 5,
|
||||
left: 10,
|
||||
right: 10,
|
||||
child: Container(
|
||||
height: 180,
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
value: controller.progress,
|
||||
// Set the color based on the "isNearEnd" condition
|
||||
color: isNearEnd ? Colors.red : Colors.blue,
|
||||
),
|
||||
Text(
|
||||
'${controller.remainingTime}',
|
||||
style: AppStyle.number,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
width: 30,
|
||||
),
|
||||
Text(
|
||||
'You can cancel Ride now'.tr,
|
||||
style: AppStyle.title,
|
||||
)
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'After this period\nYou can\'t cancel!'.tr,
|
||||
style: AppStyle.title,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox();
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/views/widgets/elevated_btn.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import 'ride_begin_passenger.dart';
|
||||
|
||||
class TimerToPassengerFromDriver extends StatelessWidget {
|
||||
const TimerToPassengerFromDriver({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
if (controller.remainingTime == 0 &&
|
||||
(controller.isDriverInPassengerWay == true ||
|
||||
controller.timeToPassengerFromDriverAfterApplied > 0)) {
|
||||
// ) {
|
||||
return Positioned(
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 5,
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
height: controller.remainingTime == 0 &&
|
||||
(controller.isDriverInPassengerWay == true ||
|
||||
controller.timeToPassengerFromDriverAfterApplied > 0)
|
||||
? 200
|
||||
: 0,
|
||||
// width: 100,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'You Can cancel Ride After Captain did not come in the time'
|
||||
.tr,
|
||||
style: AppStyle.title,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Stack(
|
||||
children: [
|
||||
LinearProgressIndicator(
|
||||
backgroundColor: AppColor.accentColor,
|
||||
color: controller
|
||||
.remainingTimeToPassengerFromDriverAfterApplied <
|
||||
60
|
||||
? AppColor.redColor
|
||||
: AppColor.greenColor,
|
||||
minHeight: 25,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
value: controller
|
||||
.progressTimerToPassengerFromDriverAfterApplied
|
||||
.toDouble(),
|
||||
),
|
||||
Center(
|
||||
child: Text(
|
||||
controller.stringRemainingTimeToPassenger,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.phone,
|
||||
color: AppColor.blueColor,
|
||||
),
|
||||
),
|
||||
controller.remainingTimeToPassengerFromDriverAfterApplied < 60
|
||||
? MyElevatedButton(
|
||||
title: 'You can cancel trip'.tr,
|
||||
onPressed: () async {
|
||||
await controller
|
||||
.calculateDistanceBetweenPassengerAndDriverBeforeCancelRide();
|
||||
})
|
||||
: const SizedBox()
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (controller.remainingTime == 0 &&
|
||||
controller.isDriverArrivePassenger == true) {
|
||||
return Positioned(
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 5,
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
height: controller.remainingTime == 0 &&
|
||||
controller.isDriverArrivePassenger == true
|
||||
? 150
|
||||
: 0,
|
||||
// width: 100,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'The driver waiting you in picked location .'.tr,
|
||||
style: AppStyle.title,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Stack(
|
||||
children: [
|
||||
LinearProgressIndicator(
|
||||
backgroundColor: AppColor.accentColor,
|
||||
color:
|
||||
controller.remainingTimeDriverWaitPassenger5Minute <
|
||||
60
|
||||
? AppColor.redColor
|
||||
: AppColor.greenColor,
|
||||
minHeight: 50,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
value: controller
|
||||
.progressTimerDriverWaitPassenger5Minute
|
||||
.toDouble(),
|
||||
),
|
||||
Center(
|
||||
child: Text(
|
||||
controller
|
||||
.stringRemainingTimeDriverWaitPassenger5Minute,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'Please go to Car now '.tr,
|
||||
style: AppStyle.title,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const RideBeginPassenger();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
319
lib/views/home/map_widget.dart/vip_begin.dart
Normal file
319
lib/views/home/map_widget.dart/vip_begin.dart
Normal file
@@ -0,0 +1,319 @@
|
||||
import 'package:Intaleq/constant/links.dart';
|
||||
import 'package:Intaleq/views/home/profile/complaint_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/constant/box_name.dart';
|
||||
import 'package:Intaleq/controller/profile/profile_controller.dart';
|
||||
import 'package:Intaleq/main.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
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';
|
||||
|
||||
class VipRideBeginPassenger extends StatelessWidget {
|
||||
const VipRideBeginPassenger({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ProfileController profileController = Get.put(ProfileController());
|
||||
AudioRecorderController audioController =
|
||||
Get.put(AudioRecorderController());
|
||||
// Get.put(MapPassengerController());
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
if (controller.statusRideVip == 'Begin' ||
|
||||
!controller.statusRideFromStart) {
|
||||
return Positioned(
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 10,
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
height: controller.statusRideVip == 'Begin' ? Get.height * .33 : 0,
|
||||
// width: 100,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 30,
|
||||
backgroundImage: NetworkImage(
|
||||
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg',
|
||||
),
|
||||
onBackgroundImageError: (_, __) {
|
||||
// Handle error here
|
||||
},
|
||||
backgroundColor: Colors.grey,
|
||||
child: const Icon(
|
||||
Icons.person, // Default icon or placeholder
|
||||
size: 30,
|
||||
color: Colors.white,
|
||||
), // Placeholder background color
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6, vertical: 2),
|
||||
child: Text(
|
||||
controller.driverName,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6, vertical: 2),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Text(
|
||||
controller.make,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Text(
|
||||
controller.model,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3),
|
||||
child: Text(
|
||||
'vip',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${controller.driverRate} 📈',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
// SizedBox(
|
||||
// height: 5,
|
||||
// ),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
width: Get.width * .15,
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: IconButton(
|
||||
onPressed: () => Get.to(
|
||||
() => ComplaintPage(),
|
||||
transition: Transition.downToUp,
|
||||
),
|
||||
icon: const Icon(
|
||||
Icons.note_add,
|
||||
color: AppColor.redColor,
|
||||
),
|
||||
tooltip: ' Add Note', // Optional tooltip for clarity
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: Get.width * .15,
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: audioController.isRecording == false
|
||||
? IconButton(
|
||||
onPressed: () async {
|
||||
await audioController.startRecording();
|
||||
Toast.show(context, 'Start Record'.tr,
|
||||
AppColor.greenColor);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.play_circle_fill_outlined,
|
||||
color: AppColor.greenColor,
|
||||
),
|
||||
tooltip:
|
||||
' Add Note', // Optional tooltip for clarity
|
||||
)
|
||||
: IconButton(
|
||||
onPressed: () async {
|
||||
await audioController.stopRecording();
|
||||
Toast.show(context, 'Record saved'.tr,
|
||||
AppColor.greenColor);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.stop_circle,
|
||||
color: AppColor.greenColor,
|
||||
),
|
||||
tooltip:
|
||||
' Add Note', // Optional tooltip for clarity
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
width: Get.width * .15,
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
if (box.read(BoxName.sosPhonePassenger) == null) {
|
||||
{
|
||||
await profileController.updatField(
|
||||
'sosPhone', TextInputType.phone);
|
||||
box.write(BoxName.sosPhonePassenger,
|
||||
profileController.prfoileData['sosPhone']);
|
||||
}
|
||||
} else {
|
||||
makePhoneCall('122');
|
||||
// box.read(BoxName.sosPhonePassenger));
|
||||
}
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.sos_rounded,
|
||||
color: AppColor.redColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
width: Get.width * .15,
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
if (box.read(BoxName.sosPhonePassenger) == null ||
|
||||
box.read(BoxName.sosPhonePassenger) == 'sos') {
|
||||
{
|
||||
await profileController.updatField(
|
||||
'sosPhone', TextInputType.phone);
|
||||
box.write(BoxName.sosPhonePassenger,
|
||||
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);
|
||||
}
|
||||
},
|
||||
icon: const Icon(
|
||||
FontAwesome.whatsapp,
|
||||
color: AppColor.greenColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
width: Get.width * .15,
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
await controller.getTokenForParent();
|
||||
},
|
||||
icon: const Icon(
|
||||
AntDesign.Safety,
|
||||
color: AppColor.blueColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Stack(
|
||||
children: [
|
||||
// StreamCounter(),
|
||||
LinearProgressIndicator(
|
||||
backgroundColor: AppColor.accentColor,
|
||||
color:
|
||||
// controller.remainingTimeTimerRideBegin < 60
|
||||
// ? AppColor.redColor
|
||||
// :
|
||||
AppColor.greenColor,
|
||||
minHeight: 25,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
value:
|
||||
24 //controller.progressTimerRideBegin.toDouble(),
|
||||
),
|
||||
Center(
|
||||
child: Text(
|
||||
controller.stringElapsedTimeRideBeginVip,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const SizedBox();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class StreamCounter extends StatelessWidget {
|
||||
const StreamCounter({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
// Build the UI based on the timer value
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(MapPassengerController());
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
return StreamBuilder<int>(
|
||||
initialData: 0,
|
||||
stream: controller.timerController.stream,
|
||||
builder: (context, snapshot) {
|
||||
// Calculate the remaining time based on the current tick
|
||||
final remainingTime = controller.durationToRide - snapshot.data!;
|
||||
|
||||
// Format the remaining time as a string
|
||||
final formattedRemainingTime =
|
||||
'${(remainingTime / 60).floor()}:${(remainingTime % 60).toString().padLeft(2, '0')}';
|
||||
|
||||
// Return the UI widgets based on the remaining time
|
||||
return Column(
|
||||
children: [
|
||||
Text(formattedRemainingTime),
|
||||
// ElevatedButton(
|
||||
// onPressed: () {
|
||||
// // Handle button press here
|
||||
// },
|
||||
// ),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user