24-12/26/1

This commit is contained in:
Hamza-Ayed
2024-12-26 00:58:41 +03:00
parent 970e444f4a
commit 186cd3aa54
14 changed files with 2912 additions and 3466 deletions

View File

@@ -575,7 +575,7 @@ class MapPassengerController extends GetxController {
void getDrawerMenu() { void getDrawerMenu() {
heightMenuBool = !heightMenuBool; heightMenuBool = !heightMenuBool;
widthMapTypeAndTraffic = heightMenuBool == true ? 0 : 50; widthMapTypeAndTraffic = heightMenuBool == true ? 0 : 50;
heightMenu = heightMenuBool == true ? 70 : 0; heightMenu = heightMenuBool == true ? 80 : 0;
widthMenu = heightMenuBool == true ? 110 : 0; widthMenu = heightMenuBool == true ? 110 : 0;
update(); update();
} }
@@ -3160,7 +3160,7 @@ class MapPassengerController extends GetxController {
} else { } else {
isMainBottomMenuMap = !isMainBottomMenuMap; isMainBottomMenuMap = !isMainBottomMenuMap;
mainBottomMenuMapHeight = mainBottomMenuMapHeight =
isMainBottomMenuMap == true ? Get.height * .2 : Get.height * .55; isMainBottomMenuMap == true ? Get.height * .2 : Get.height * .7;
isWayPointSheet = false; isWayPointSheet = false;
if (heightMenuBool == true) { if (heightMenuBool == true) {
getDrawerMenu(); getDrawerMenu();
@@ -4074,7 +4074,7 @@ class MapPassengerController extends GetxController {
LatLngBounds(northeast: northeast, southwest: southwest); LatLngBounds(northeast: northeast, southwest: southwest);
// Fit the camera to the bounds // Fit the camera to the bounds
var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData, 100); var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData, 130);
mapController!.animateCamera(cameraUpdate); mapController!.animateCamera(cameraUpdate);
// getDistanceFromText(data[0]['distance']['text']); // getDistanceFromText(data[0]['distance']['text']);
@@ -4132,117 +4132,51 @@ class MapPassengerController extends GetxController {
} }
Future<void> _animatePolyline(List<LatLng> coordinates) async { Future<void> _animatePolyline(List<LatLng> coordinates) async {
// Initial animation const int totalAnimations = 7;
polyLines.clear();
List<LatLng> animatedPoints = [];
// Draw initial polyline Color getAnimationColor(int cycle) {
for (int i = 0; i < coordinates.length; i++) { switch (cycle) {
animatedPoints.add(coordinates[i]); case 0:
polyLines.clear(); return AppColor.primaryColor;
polyLines.add( case 1:
Polyline( return AppColor.writeColor;
polylineId: const PolylineId('animated_route'), case 2:
points: List<LatLng>.from(animatedPoints), return AppColor.primaryColor;
width: 4, default:
color: AppColor.primaryColor, return AppColor.primaryColor;
endCap: Cap.roundCap, }
startCap: Cap.roundCap,
geodesic: true,
),
);
update();
await Future.delayed(const Duration(milliseconds: 1));
} }
// Color change animations for (int cycle = 0; cycle < totalAnimations; cycle++) {
for (int cycle = 0; cycle < 6; cycle++) {
// Change to green
polyLines.clear(); polyLines.clear();
polyLines.add( List<LatLng> animatedPoints = [];
Polyline(
polylineId: const PolylineId('animated_route'),
points: coordinates,
width: 4,
color: AppColor.bronze,
endCap: Cap.roundCap,
startCap: Cap.roundCap,
geodesic: true,
),
);
update();
await Future.delayed(const Duration(milliseconds: 500));
// Change back to primary color for (int i = 0; i < coordinates.length; i++) {
polyLines.clear(); animatedPoints.add(coordinates[i]);
polyLines.add( polyLines.clear();
Polyline( polyLines.add(
polylineId: const PolylineId('animated_route'), Polyline(
points: coordinates, polylineId: const PolylineId('animated_route'),
width: 4, points: List<LatLng>.from(animatedPoints),
color: AppColor.writeColor, width: 4,
endCap: Cap.roundCap, color: getAnimationColor(cycle),
startCap: Cap.roundCap, endCap: Cap.roundCap,
geodesic: true, startCap: Cap.roundCap,
), geodesic: true,
); ),
update(); );
await Future.delayed(const Duration(milliseconds: 500)); update();
await Future.delayed(const Duration(milliseconds: 10));
}
if (cycle < totalAnimations - 1) {
await Future.delayed(const Duration(milliseconds: 500));
polyLines.clear();
update();
await Future.delayed(const Duration(milliseconds: 200));
}
} }
} }
// Add this method to your controller class
// Future<void> _animatePolyline(List<LatLng> coordinates) async {
// // Clear existing polylines
// polyLines.clear();
// // Create segments for animation
// List<LatLng> animatedPoints = [];
// // Calculate step size for smoother animation
// int stepSize = (coordinates.length / 20).round();
// stepSize = stepSize < 1 ? 1 : stepSize;
// for (int i = 0; i < coordinates.length; i += stepSize) {
// // Add points gradually
// animatedPoints.add(coordinates[i]);
// if (animatedPoints.length > 1) {
// // Remove previous polyline
// if (polyLines.isNotEmpty) {
// polyLines.clear();
// }
// // Add new polyline segment
// polyLines.add(
// Polyline(
// polylineId: const PolylineId('animated_route'),
// points: List<LatLng>.from(animatedPoints),
// width: 4,
// color: Colors.blue,
// ),
// );
// // Update camera position to follow animation
// if (mapController != null) {
// final bounds = LatLngBounds(
// southwest: animatedPoints.reduce((value, element) => LatLng(
// min(value.latitude, element.latitude),
// min(value.longitude, element.longitude))),
// northeast: animatedPoints.reduce((value, element) => LatLng(
// max(value.latitude, element.latitude),
// max(value.longitude, element.longitude))),
// );
// mapController!.animateCamera(
// CameraUpdate.newLatLngBounds(bounds, 100),
// );
// }
// }
// update();
// await Future.delayed(const Duration(milliseconds: 50));
// }
// }
String shortenAddress(String fullAddress) { String shortenAddress(String fullAddress) {
// Split the address into parts // Split the address into parts

File diff suppressed because it is too large Load Diff

View File

@@ -37,461 +37,297 @@ class LoginPage extends StatelessWidget {
isleading: false, isleading: false,
body: [ body: [
if (box.read(BoxName.agreeTerms) != 'agreed') if (box.read(BoxName.agreeTerms) != 'agreed')
agreedPage() _buildAgreementPage(controller)
else if (box.read(BoxName.countryCode) == null) else if (box.read(BoxName.countryCode) == null)
CountryPicker() _buildCountryPicker()
else if (box.read(BoxName.locationPermission) != 'true') else if (box.read(BoxName.locationPermission) != 'true')
locationPermissionDialog() _buildLocationPermissionDialog(controller)
else else
SingleChildScrollView( _buildLoginContent(controller, authController),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Center(
child: Container(
decoration: AppStyle.boxDecoration1,
height: Get.height * .7,
width: Get.width * .9,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Image.asset(
'assets/images/logo.gif',
height: Get.width * .3,
width: Get.width * .3,
fit: BoxFit.fill,
),
Platform.isIOS && controller.isTest == 0
? Container(
decoration: AppStyle.boxDecoration,
child: Column(
children: [
Form(
key: controller.formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Column(
children: [
TextFormField(
keyboardType: TextInputType
.emailAddress,
controller: controller
.emailController,
decoration: InputDecoration(
focusedBorder:
OutlineInputBorder(
borderSide:
const BorderSide(
color: AppColor
.primaryColor,
width: 2.0,
),
borderRadius:
BorderRadius.circular(
10),
),
fillColor:
AppColor.accentColor,
hoverColor:
AppColor.accentColor,
focusColor:
AppColor.accentColor,
border: const OutlineInputBorder(
borderRadius:
BorderRadius.all(
Radius.circular(
12))),
labelText: 'Email'.tr,
hintText:
'Enter your email address'
.tr,
),
validator: (value) {
if (value!.isEmpty ||
(!value.contains('@') ||
!value.contains(
'.'))) {
return 'Please enter Your Email.'
.tr;
}
return null;
},
),
const SizedBox(
height: 15,
),
TextFormField(
obscureText: true,
keyboardType: TextInputType
.emailAddress,
controller: controller
.passwordController,
decoration: InputDecoration(
focusedBorder:
OutlineInputBorder(
borderSide:
const BorderSide(
color: AppColor
.primaryColor,
width: 2.0,
),
borderRadius:
BorderRadius.circular(
10),
),
fillColor:
AppColor.accentColor,
hoverColor:
AppColor.accentColor,
focusColor:
AppColor.accentColor,
border: const OutlineInputBorder(
borderRadius:
BorderRadius.all(
Radius.circular(
12))),
labelText: 'Password'.tr,
hintText:
'Please enter your phone number.'
.tr,
),
validator: (value) {
if (value!.isEmpty) {
return 'Please enter Your Password.'
.tr;
}
if (value.length < 6) {
return 'Password must br at least 6 character.'
.tr;
}
return null;
},
),
GetBuilder<LoginController>(
builder: (controller) =>
controller.isloading
? const MyCircularProgressIndicator()
: MyElevatedButton(
onPressed: () {
if (controller
.formKey
.currentState!
.validate()) {
controller
.login();
}
},
title:
'Submit'.tr,
),
)
],
),
),
),
),
const SizedBox(
height: 10,
),
],
),
)
: Container(
decoration: AppStyle.boxDecoration1,
height: Get.height * .3,
width: Get.width * .8,
child: Center(
child: Text(
'Sign in with Google for easier email and name entry'
.tr,
textAlign: TextAlign.center,
style: AppStyle.title,
),
),
),
// MyElevatedButton(
// title: 'Sign In by Google'.tr,
// onPressed: () async {
// await GoogleSignInHelper.signInFromLogin();
// },
// kolor: AppColor.blueColor,
// ),
InkWell(
onTap: () async {
await GoogleSignInHelper().signInFromLogin();
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: AppColor.redColor,
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
FontAwesome.google,
color: AppColor.blueColor,
),
const SizedBox(width: 8),
Text(
'Sign In by Google'.tr,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
!Platform.isAndroid
? GestureDetector(
onTap: () async {
User? user =
await authController.signInWithApple();
if (user != null) {
box.write(BoxName.passengerID, user.uid);
box.write(BoxName.email, user.email);
await controller.loginUsingCredentials(
box
.read(BoxName.passengerID)
.toString(),
box.read(BoxName.email).toString(),
);
// Navigate to another screen or perform other actions
} else {
Get.snackbar('user not found'.tr, '',
backgroundColor: AppColor.redColor);
}
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.apple,
color: Colors.white,
size: 24,
),
const SizedBox(width: 8),
Text(
'Sign in with Apple'.tr,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
),
),
)
: const SizedBox(),
],
),
)),
SizedBox(
height: Get.height * .1,
),
GestureDetector(
onTap: () => Get.to(() => ContactUsPage()),
child: Text(
'If you need assistance, contact us'
.tr, // Improved wording
style: AppStyle.subtitle,
),
),
// Text(
// 'if you dont have account'.tr,
// style: AppStyle.subtitle,
// ),
// AnimatedTextKit(
// onTap: () => Get.to(() => SmsSignupEgypt()),
// animatedTexts: [
// TypewriterAnimatedText(
// 'Register'.tr,
// textStyle: AppStyle.headTitle2,
// speed: const Duration(milliseconds: 200),
// ),
// ],
// totalRepeatCount: 4,
// pause: const Duration(milliseconds: 200),
// displayFullTextOnTap: true,
// stopPauseOnTap: true,
// ),
// const Spacer(),
const SizedBox(
height: 100,
),
],
),
),
)
], ],
), ),
); );
} }
Padding agreedPage() { Widget _buildLoginContent(
return Padding( LoginController controller, AuthController authController) {
padding: const EdgeInsets.all(16), return SingleChildScrollView(
child: SingleChildScrollView( child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Row( Image.asset(
mainAxisAlignment: MainAxisAlignment.spaceBetween, 'assets/images/logo.gif',
children: [ height: Get.width * 0.4,
Image.asset( width: Get.width * 0.4,
'assets/images/notepad.png', fit: BoxFit.contain,
width: Get.width * .2,
),
SizedBox(
width: Get.width * .7,
child: Text(
'Accept Ride\'s Terms & Review Privacy Notice'.tr,
style: AppStyle.headTitle2,
),
),
],
), ),
const SizedBox( const SizedBox(height: 32),
height: 30, if (Platform.isIOS && controller.isTest == 0)
), _buildEmailPasswordForm(controller)
RichText( else
text: TextSpan( Padding(
text: padding: const EdgeInsets.only(bottom: 24.0),
'By selecting "I Agree" below, I have reviewed and agree to the Terms of Use and acknowledge the ' child: Text(
.tr, 'Sign in for a seamless experience'.tr,
style: AppStyle.title, textAlign: TextAlign.center,
children: <TextSpan>[ style: AppStyle.subtitle,
TextSpan( ),
text: 'Privacy Notice'.tr, ),
style: const TextStyle( InkWell(
decoration: TextDecoration.underline, onTap: () async => await GoogleSignInHelper().signInFromLogin(),
color: AppColor.blueColor), child: _buildSocialButton(
recognizer: TapGestureRecognizer() icon: FontAwesome.google,
..onTap = () { text: 'Sign In with Google'.tr,
Get.defaultDialog( color: AppColor.redColor,
title: ''.tr,
content: const SizedBox(
height: 400,
width: 400,
child: SingleChildScrollView(
child:
HtmlWidget(AppInformation.privacyPolicy),
),
));
}),
TextSpan(
text: '. I am at least 18 years of age.'.tr,
),
],
), ),
), ),
const SizedBox( const SizedBox(height: 16),
height: 100, if (!Platform.isAndroid)
), GestureDetector(
GetBuilder<LoginController>( onTap: () async {
builder: (controller) => Column( User? user = await authController.signInWithApple();
children: [ if (user != null) {
Row( box.write(BoxName.passengerID, user.uid);
children: [ box.write(BoxName.email, user.email);
Checkbox.adaptive( await controller.loginUsingCredentials(
autofocus: true, box.read(BoxName.passengerID).toString(),
tristate: true, box.read(BoxName.email).toString(),
splashRadius: 25, );
activeColor: AppColor.primaryColor, } else {
value: controller.isAgreeTerms, Get.snackbar('User not found'.tr, '',
onChanged: (value) => controller.changeAgreeTerm(), backgroundColor: AppColor.redColor);
), }
Text( },
'I Agree'.tr, child: _buildSocialButton(
style: controller.isAgreeTerms icon: Icons.apple,
? AppStyle.title text: 'Sign in with Apple'.tr,
: AppStyle.title color: Colors.black,
.copyWith(color: AppColor.accentColor), ),
),
],
),
MyElevatedButton(
title: 'Submit'.tr,
onPressed: () => controller.saveAgreementTerms()),
],
), ),
) const SizedBox(height: 40),
GestureDetector(
onTap: () => Get.to(() => ContactUsPage()),
child: Text(
'Need assistance? Contact us'.tr,
style: AppStyle.subtitle.copyWith(color: Colors.grey),
),
),
], ],
), ),
), ),
); );
} }
locationPermissionDialog() { Widget _buildSocialButton({
return GetBuilder<LoginController>(builder: (controller) { required IconData icon,
return Padding( required String text,
padding: const EdgeInsets.all(16), required Color color,
child: Container( }) {
height: Get.height * .4, return Container(
decoration: AppStyle.boxDecoration1, padding: const EdgeInsets.all(12),
child: Padding( decoration: BoxDecoration(
padding: const EdgeInsets.all(20.0), color: color,
child: Center( borderRadius: BorderRadius.circular(8),
child: Column( ),
crossAxisAlignment: CrossAxisAlignment.center, child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Icon(icon, color: Colors.white),
'We use your precise location to find the nearest available driver and provide accurate pickup and dropoff information. You can manage this in Settings.' const SizedBox(width: 12),
.tr, Text(
textAlign: TextAlign.center, text,
style: AppStyle.title, style: const TextStyle(
), color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500),
TextButton( ),
onPressed: () { ],
// Optionally, navigate to app settings for manual permission control ),
openAppSettings(); );
}, }
child: Text(
"Open Settings".tr, Widget _buildEmailPasswordForm(LoginController controller) {
style: const TextStyle(color: AppColor.blueColor), return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 5,
offset: const Offset(0, 3),
),
],
),
child: Form(
key: controller.formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextFormField(
keyboardType: TextInputType.emailAddress,
controller: controller.emailController,
decoration: InputDecoration(
labelText: 'Email'.tr,
hintText: 'Your email address'.tr,
border: const OutlineInputBorder(),
),
validator: (value) => value == null ||
value.isEmpty ||
!value.contains('@') ||
!value.contains('.')
? 'Enter a valid email'.tr
: null,
),
const SizedBox(height: 16),
TextFormField(
obscureText: true,
controller: controller.passwordController,
decoration: InputDecoration(
labelText: 'Password'.tr,
hintText: 'Your password'.tr,
border: const OutlineInputBorder(),
),
validator: (value) => value == null || value.isEmpty
? 'Enter your password'.tr
: null,
),
const SizedBox(height: 24),
GetBuilder<LoginController>(
builder: (controller) => controller.isloading
? const Center(child: CircularProgressIndicator())
: ElevatedButton(
onPressed: () {
if (controller.formKey.currentState!.validate()) {
controller.login();
}
},
child: Text('Submit'.tr),
), ),
), ),
MyElevatedButton( ],
title: 'Next'.tr, ),
onPressed: () async { ),
// if (box.read(BoxName.locationPermission) != 'true') { );
// Get.put(MyDialog()).getDialog( }
// 'Location Permission is requiered for find drivers'
// .tr, Widget _buildAgreementPage(LoginController controller) {
// 'You can just manage your account!'.tr, () { return Padding(
// Get.back(); padding: const EdgeInsets.all(16),
// Get.to(() { child: Column(
// PassengerProfilePage(); crossAxisAlignment: CrossAxisAlignment.start,
// }); children: [
// }); ListTile(
// } else { leading: Image.asset('assets/images/notepad.png', width: 40),
await controller.getLocationPermission(); title: Text('Terms of Use & Privacy Notice'.tr,
// } style: AppStyle.headTitle2),
),
const SizedBox(height: 20),
RichText(
textAlign: TextAlign.left,
text: TextSpan(
style: AppStyle.title,
children: <TextSpan>[
TextSpan(
text:
'By selecting "I Agree" below, I confirm that I have read and agree to the '
.tr),
TextSpan(
text: 'Terms of Use'.tr,
style: const TextStyle(
decoration: TextDecoration.underline,
color: AppColor.blueColor),
),
const TextSpan(text: ' and acknowledge the '),
TextSpan(
text: 'Privacy Notice'.tr,
style: const TextStyle(
decoration: TextDecoration.underline,
color: AppColor.blueColor),
recognizer: TapGestureRecognizer()
..onTap = () {
Get.defaultDialog(
title: 'Privacy Notice'.tr,
content: const SizedBox(
height: 400,
width: 400,
child: SingleChildScrollView(
child: HtmlWidget(AppInformation.privacyPolicy),
),
),
);
}, },
kolor: AppColor.greenColor, ),
) TextSpan(text: '. I am at least 18 years old.'.tr),
], ],
),
),
const SizedBox(height: 40),
Row(
children: [
Checkbox(
value: controller.isAgreeTerms,
onChanged: (newValue) => controller.changeAgreeTerm(),
activeColor: AppColor.primaryColor,
),
Text('I Agree'.tr, style: AppStyle.title),
],
),
const Spacer(),
Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: controller.isAgreeTerms
? () => controller.saveAgreementTerms()
: null,
child: Text('Continue'.tr),
), ),
), ),
), ),
), ],
); ),
}); );
}
Widget _buildLocationPermissionDialog(LoginController controller) {
return Padding(
padding: const EdgeInsets.all(32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.location_on, size: 60, color: AppColor.primaryColor),
const SizedBox(height: 20),
Text(
'Enable Location Access'.tr,
style: AppStyle.headTitle2,
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
Text(
'We need your location to find nearby drivers for pickups and drop-offs.'
.tr,
textAlign: TextAlign.center,
style: AppStyle.title,
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () async => await controller.getLocationPermission(),
child: Text('Allow Location Access'.tr),
),
TextButton(
onPressed: () => openAppSettings(),
child: Text('Open Settings'.tr),
),
],
),
);
}
Widget _buildCountryPicker() {
return CountryPicker();
} }
} }

View File

@@ -33,7 +33,7 @@ class MapPagePassenger extends StatelessWidget {
Get.put(MapPassengerController()); Get.put(MapPassengerController());
Get.put(MyMenuController()); Get.put(MyMenuController());
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
checkForUpdate(context); // checkForUpdate(context);
}); });
return Scaffold( return Scaffold(
@@ -53,7 +53,8 @@ class MapPagePassenger extends StatelessWidget {
// const HeaderDestination(), // const HeaderDestination(),
const BurcMoney(), const BurcMoney(),
const PromoCode(), const PromoCode(),
const ApplyOrderWidget(), const MapMenuWidget(), const ApplyOrderWidget(),
const MapMenuWidget(),
// hexagonClipper(), // hexagonClipper(),
const CancelRidePageShow(), const CancelRidePageShow(),
CashConfirmPageShown(), CashConfirmPageShown(),

View File

@@ -18,472 +18,34 @@ class ApplyOrderWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Color _parseColor(String colorHex) { Color _parseColor(String colorHex) {
if (colorHex.isEmpty) { if (colorHex.isEmpty) return Colors.grey;
return Colors.grey; // Fallback for empty color
}
// Ensure the string starts with '0xff' for ARGB format
String processedHex = colorHex.replaceFirst('#', '0xff').trim(); String processedHex = colorHex.replaceFirst('#', '0xff').trim();
return Color(int.parse(processedHex.startsWith('0xff')
if (!processedHex.startsWith('0xff')) { ? processedHex
processedHex = '0xff$processedHex'; // Add '0xff' if missing : '0xff$processedHex'));
}
return Color(int.parse(processedHex));
} }
return GetBuilder<MapPassengerController>(builder: (controller) { return GetBuilder<MapPassengerController>(builder: (controller) {
if (controller.statusRide == 'Apply' && if (controller.statusRide == 'Apply' && !controller.isSearchingWindow) {
controller.isSearchingWindow == false) {
// double _height = Get.height * .2;
return Positioned( return Positioned(
bottom: 0, bottom: 0,
left: 0, left: 0,
right: 0, right: 0,
child: Container( child: Container(
decoration: AppStyle.boxDecoration, decoration: BoxDecoration(
height: Get.height * .36, // More modern BoxDecoration
child: ListView( 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: [ children: [
InkWell( _buildPriceInfo(context, controller),
onTap: () { const SizedBox(height: 16),
if (box.read(BoxName.carType) == 'Speed' || _buildDriverInfoCard(context, controller, _parseColor),
box.read(BoxName.carType) == 'Awfar Car' ||
box.read(BoxName.carType) == 'Delivery') {
Get.snackbar(
'This price is'.tr +
' ${controller.totalPassenger.toStringAsFixed(2)}'
.tr,
'This ride type does not allow changes to the destination or additional stops'
.tr,
snackPosition: SnackPosition.BOTTOM,
duration: const Duration(seconds: 2),
backgroundColor: AppColor.yellowColor,
);
} else {
Get.snackbar(
'This price may be changed'.tr,
'This ride type allows changes, but the price may increase'
.tr,
snackPosition: SnackPosition.BOTTOM,
duration: const Duration(seconds: 2),
backgroundColor: AppColor.yellowColor,
);
}
},
child: Text.rich(
TextSpan(
children: [
TextSpan(
text: '${'The driver accept your order for'.tr} ',
style: AppStyle.title,
),
TextSpan(
text: controller.totalPassenger.toStringAsFixed(2),
style: AppStyle.title.copyWith(
fontWeight: FontWeight.bold,
// fontSize: 22,
color: AppColor.redColor,
),
),
TextSpan(
text: ' ${'LE'.tr}',
style: AppStyle.title,
),
],
),
textAlign: TextAlign.center,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
width: 10,
),
Container(
height: Get.height * .31,
width: Get.width * .9,
decoration: AppStyle.boxDecoration,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
// 'Comfort',
box.read(BoxName.carType
.toString()), //car type fro box after selected
style: AppStyle.title,
),
const SizedBox(
width: 10,
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
// ColorFiltered(
// colorFilter: ColorFilter.mode(
// _parseColor(controller.colorHex),
// BlendMode.srcIn,
// ),
// child: Image.asset(
// box.read(BoxName.carType) == 'Comfort'
// ? 'assets/images/blob.png'
// : box.read(BoxName.carType) == 'Lady'
// ? 'assets/images/lady.png' // Assuming there's an image for Lady
// : box.read(BoxName.carType) == 'Speed'
// ? 'assets/images/carspeed.png'
// : box.read(BoxName.carType) ==
// 'Scooter'
// ? 'assets/images/moto.png'
// : box.read(BoxName.carType) ==
// 'Mishwar Vip'
// ? 'assets/images/freeRide.png'
// : box.read(BoxName
// .carType) ==
// 'Awfar Car'
// ? 'assets/images/balash.png'
// : box.read(BoxName
// .carType) ==
// 'Pink Bike'
// ? 'assets/images/pinkBike.png'
// : box.read(BoxName
// .carType) ==
// 'Rayeh Gai'
// ? 'assets/images/roundtrip.png'
// : 'assets/images/carspeed.png', // Default image if none of the above
// width: 80,
// ),
// ),
Column(
children: [
Text(
// 'Toyota Camry',
controller.model.toString(),
style: AppStyle.title,
),
Text(
// 'ر ل 2323',
controller.licensePlate.toString(),
style: AppStyle.title,
),
],
),
const SizedBox(
width: 10,
),
Text(
// 'Black',
controller.carColor.toString(),
style: AppStyle.title,
),
const SizedBox(
width: 10,
),
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',
width: 80,
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CircleAvatar(
radius: 25,
backgroundImage: NetworkImage(
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg',
),
child: Builder(
builder: (context) {
return Image.network(
'${AppLink.server}/portrate_captain_image/${controller.driverId}.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
);
},
);
},
),
),
Column(
children: [
Text(
// 'fadi ahmad',
controller.driverName,
style: AppStyle.title,
),
Text(
// '⭐ 4.8',
'${controller.driverRate}',
style: AppStyle.title,
),
],
),
IconButton(
onPressed: () async {
Get.defaultDialog(
title: 'Select one message',
titleStyle: AppStyle.title,
content: SizedBox(
width: 300,
height: Get.height * .5,
child: ListView(
children: [
InkWell(
onTap: () {
FirebaseMessagesController()
.sendNotificationToDriverMAP(
'message From passenger',
'Hello, I\'m at the agreed-upon location'
.tr,
controller.driverToken
.toString(),
[],
'ding.wav',
);
Get.back();
},
child: Container(
decoration:
AppStyle.boxDecoration,
child: Padding(
padding:
const EdgeInsets.all(
10),
child: Text(
'Hello, I\'m at the agreed-upon location'
.tr,
style: AppStyle.title,
),
),
),
),
const SizedBox(
height: 5,
),
InkWell(
onTap: () {
FirebaseMessagesController()
.sendNotificationToDriverMAP(
'message From passenger',
'My location is correct. You can search for me using the navigation app'
.tr,
controller.driverToken,
[],
'ding.wav',
);
Get.back();
},
child: Container(
decoration:
AppStyle.boxDecoration,
child: Padding(
padding:
const EdgeInsets.all(
10),
child: Text(
'My location is correct. You can search for me using the navigation app'
.tr,
style: AppStyle.title,
),
),
),
),
const SizedBox(
height: 5,
),
InkWell(
onTap: () {
FirebaseMessagesController()
.sendNotificationToDriverMAP(
'message From passenger',
'My location is correct. You can search for me using the navigation app'
.tr,
controller.driverToken,
[],
'ding.wav',
);
Get.back();
},
child: Container(
decoration:
AppStyle.boxDecoration,
child: Padding(
padding:
const EdgeInsets.all(
10),
child: Text(
'I\'m waiting for you'.tr,
style: AppStyle.title,
),
),
),
),
const SizedBox(
height: 5,
),
InkWell(
onTap: () {
FirebaseMessagesController()
.sendNotificationToDriverMAP(
'message From passenger',
"How much longer will you be?"
.tr,
controller.driverToken,
[],
'ding.wav',
);
Get.back();
},
child: Container(
decoration:
AppStyle.boxDecoration,
child: Padding(
padding:
const EdgeInsets.all(
10),
child: Text(
"How much longer will you be?"
.tr,
style: AppStyle.title,
),
),
),
),
const SizedBox(
height: 5,
),
SizedBox(
width: 190,
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Form(
key: controller
.messagesFormKey,
child: SizedBox(
width: 160,
child: MyTextForm(
controller: controller
.messageToDriver,
label:
'Type Any thing'
.tr,
hint:
'Type Any thing'
.tr,
type:
TextInputType
.name),
)),
IconButton(
onPressed: () {
FirebaseMessagesController()
.sendNotificationToDriverMAP(
'message From passenger',
controller
.messageToDriver
.text,
controller
.driverToken,
[],
'ding.wav');
controller
.messageToDriver
.clear();
Get.back();
},
icon: const Icon(
Icons.send))
],
),
)
],
),
));
},
icon: const Icon(
Icons.message,
color: AppColor.blueColor,
size: 35,
),
),
IconButton(
onPressed: () async {
HapticFeedback.heavyImpact();
// Get.to(() => const CallPage());
// Get.to(() => PassengerCallPage());
makePhoneCall(controller.driverPhone);
},
icon: const Icon(
Icons.call,
color: AppColor.greenColor,
size: 35,
),
),
],
),
),
controller.isDriverArrivePassenger
? const DriverArrivePassengerAndWaitMinute()
: const TimeDriverToPassenger()
],
),
),
const SizedBox(
width: 10,
),
],
)
], ],
), ),
), ),
@@ -493,45 +55,296 @@ class ApplyOrderWidget extends StatelessWidget {
} }
}); });
} }
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 { class DriverArrivePassengerAndWaitMinute extends StatelessWidget {
const DriverArrivePassengerAndWaitMinute({ const DriverArrivePassengerAndWaitMinute({Key? key}) : super(key: key);
super.key,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(builder: (controller) { return GetBuilder<MapPassengerController>(builder: (controller) {
return Stack( return Column(
children: [ children: [
LinearProgressIndicator( ClipRRect(
backgroundColor: AppColor.accentColor,
color: controller.remainingTimeDriverWaitPassenger5Minute < 60
? AppColor.redColor
: AppColor.greenColor,
minHeight: 25,
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
value: child: LinearProgressIndicator(
controller.progressTimerDriverWaitPassenger5Minute.toDouble(), backgroundColor: AppColor.accentColor.withOpacity(0.3),
color: controller.remainingTimeDriverWaitPassenger5Minute < 60
? AppColor.redColor
: AppColor.greenColor,
minHeight: 20,
value:
controller.progressTimerDriverWaitPassenger5Minute.toDouble(),
),
), ),
Row( const SizedBox(height: 4),
mainAxisAlignment: MainAxisAlignment.center, Center(
children: [ child: Text.rich(
Text( TextSpan(
'The driver waiting you in picked location .'.tr, children: [
style: AppStyle.subtitle, TextSpan(
textAlign: TextAlign.center, text: '${'Driver is waiting at pickup.'.tr} ',
style: AppStyle.subtitle),
TextSpan(
text: controller
.stringRemainingTimeDriverWaitPassenger5Minute,
style: AppStyle.title),
],
), ),
const SizedBox( textAlign: TextAlign.center,
width: 20, ),
), ),
Text(
controller.stringRemainingTimeDriverWaitPassenger5Minute,
style: AppStyle.title,
),
],
)
], ],
); );
}); });
@@ -539,77 +352,50 @@ class DriverArrivePassengerAndWaitMinute extends StatelessWidget {
} }
class TimeDriverToPassenger extends StatelessWidget { class TimeDriverToPassenger extends StatelessWidget {
const TimeDriverToPassenger({ const TimeDriverToPassenger({Key? key}) : super(key: key);
super.key,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(builder: (controller) { return GetBuilder<MapPassengerController>(builder: (controller) {
return controller.isDriverInPassengerWay == false || return controller.isDriverInPassengerWay == false ||
controller.timeToPassengerFromDriverAfterApplied > 0 controller.timeToPassengerFromDriverAfterApplied > 0
? Container( ? Column(
decoration: AppStyle.boxDecoration, children: [
child: Padding( ClipRRect(
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1), borderRadius: BorderRadius.circular(15),
child: Stack( child: LinearProgressIndicator(
children: [ backgroundColor: AppColor.accentColor.withOpacity(0.3),
Container( color: controller
decoration: AppStyle.boxDecoration, .remainingTimeToPassengerFromDriverAfterApplied <
width: Get.width * .7, 60
height: 15, ? AppColor.redColor
// color: AppColor.yellowColor, : AppColor.greenColor,
), minHeight: 20,
Stack( value: controller
.progressTimerToPassengerFromDriverAfterApplied
.toDouble()
.clamp(0.0, 1.0),
),
),
const SizedBox(height: 4),
Center(
child: Text.rich(
TextSpan(
children: [ children: [
LinearProgressIndicator( TextSpan(
backgroundColor: AppColor.accentColor, text: '${'Driver is on the way'.tr} ',
color: controller style: AppStyle.subtitle,
.remainingTimeToPassengerFromDriverAfterApplied < ),
60 TextSpan(
? AppColor.redColor text: controller.stringRemainingTimeToPassenger,
: AppColor.greenColor, style: AppStyle.title,
minHeight: 25,
borderRadius: BorderRadius.circular(15),
value: () {
// Ensure valid value between 0.0 and 1.0
double progress = controller
.progressTimerToPassengerFromDriverAfterApplied
.toDouble();
if (progress.isNaN || progress.isInfinite) {
// Handle invalid progress (e.g., set to 0.0)
return 0.0;
} else {
return progress.clamp(
0.0, 1.0); // Clamp to valid range
}
}(),
), ),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'The driver on your way'.tr,
style: AppStyle.title
.copyWith(color: AppColor.yellowColor),
textAlign: TextAlign.center,
),
const SizedBox(
width: 20,
),
Text(
controller.stringRemainingTimeToPassenger,
style: AppStyle.title,
),
],
),
)
], ],
), ),
], textAlign: TextAlign.center,
),
), ),
), ],
) )
: const SizedBox(); : const SizedBox();
}); });

View File

@@ -102,20 +102,13 @@ class CarDetailsTypeToChoose extends StatelessWidget {
mapPassengerController.isBottomSheetShown && mapPassengerController.isBottomSheetShown &&
mapPassengerController.rideConfirm == false mapPassengerController.rideConfirm == false
? Positioned( ? Positioned(
bottom: 0, bottom: 15,
left: 8, left: 8,
right: 8, right: 8,
child: Container( child: Container(
height: Get.height * .3, height: Get.height * .32,
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( color: AppColor.secondaryColor,
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
AppColor.secondaryColor,
AppColor.secondaryColor,
],
),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
@@ -130,6 +123,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
), ),
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
@@ -139,7 +133,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(1.0),
child: SizedBox( child: SizedBox(
height: Get.height * .22, // Adjust height as needed height: Get.height * .22, // Adjust height as needed
child: ListView.separated( child: ListView.separated(
@@ -478,73 +472,101 @@ class PromoCode extends StatelessWidget {
Get.put(BlinkingController()); Get.put(BlinkingController());
return GetBuilder<MapPassengerController>( return GetBuilder<MapPassengerController>(
builder: (mapPassengerController) { builder: (mapPassengerController) {
return mapPassengerController.data.isNotEmpty && final showPromoButton = mapPassengerController.data.isNotEmpty &&
mapPassengerController.isBottomSheetShown && mapPassengerController.isBottomSheetShown &&
mapPassengerController.rideConfirm == false && !mapPassengerController.rideConfirm &&
mapPassengerController.promoTaken == false !mapPassengerController.promoTaken;
? GetBuilder<BlinkingController>(builder: (blinkingController) {
blinkingController.startBlinking(); return showPromoButton
return Positioned( ? GetBuilder<BlinkingController>(
right: 5, builder: (blinkingController) {
bottom: Get.height * 0.36, blinkingController.startBlinking();
child: Obx(() { return Positioned(
return AnimatedContainer( right: 16, // Adjusted from 5 for better spacing
duration: const Duration(milliseconds: 500), bottom: Get.height * 0.36,
width: 70, // Circle size child: InkWell(
height: 70, onTap: () {
decoration: BoxDecoration( Get.defaultDialog(
shape: BoxShape.circle, title: 'Apply Promo Code'.tr, // More engaging title
color: blinkingController.isLightOn.value content: Padding(
? Colors.yellow padding: const EdgeInsets.symmetric(vertical: 16),
: Colors.grey, // Light on/off effect child: Form(
border: Border.all( key: mapPassengerController.promoFormKey,
color: blinkingController child: MyTextForm(
.borderColor.value, // Animated border color controller: mapPassengerController.promo,
width: 3, label: 'Promo Code'.tr, // Shortened label
), hint: 'Enter your promo code'
), .tr, // More friendly hint
child: IconButton( type: TextInputType.name,
onPressed: () { // style: AppStyle.normalTextBlack, // Apply consistent style
Get.defaultDialog(
title: 'Insert Your Promo Code'.tr,
content: Form(
key: mapPassengerController.promoFormKey,
child: MyTextForm(
controller: mapPassengerController.promo,
label: 'Insert Your Promo Code'.tr,
hint: 'Enter promo code here'.tr,
type: TextInputType.name,
),
), ),
confirm: MyElevatedButton( ),
title: 'Ok'.tr, ),
onPressed: () { confirm: MyElevatedButton(
if (mapPassengerController title: 'Apply'.tr, // Shortened button title
.promoFormKey.currentState! onPressed: () {
.validate()) { if (mapPassengerController
mapPassengerController .promoFormKey.currentState!
.applyPromoCodeToPassenger(context); .validate()) {
Get.back(); mapPassengerController
} .applyPromoCodeToPassenger(context);
})); Get.back();
}, }
icon: const Column( },
mainAxisAlignment: MainAxisAlignment.center, ),
children: [ cancel: OutlinedButton(
Icon(Icons.local_offer, size: 24), // Promo icon onPressed: () => Get.back(),
SizedBox(height: 4), child: Text('Cancel'.tr),
Text( ),
"Promo", );
style: TextStyle( },
fontSize: 12, fontWeight: FontWeight.bold), child: Container(
width: 60, // Slightly smaller for a cleaner look
height: 60,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white, // Solid white background
border: Border.all(
color: blinkingController.borderColor.value,
width: 2,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 5,
spreadRadius: 2,
), ),
], ],
), ),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.local_offer,
size: 24,
color: blinkingController.isLightOn.value
? Colors.orange
: Colors
.grey.shade600, // Distinct promo color
),
const SizedBox(height: 2),
Text(
"Promo".tr,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
],
),
),
), ),
); ),
}), );
); },
}) )
: const SizedBox(); : const SizedBox();
}, },
); );
@@ -559,51 +581,89 @@ class BurcMoney extends StatelessWidget {
return GetBuilder<MapPassengerController>( return GetBuilder<MapPassengerController>(
builder: (mapPassengerController) { builder: (mapPassengerController) {
final passengerWallet = final passengerWallet =
double.tryParse(box.read(BoxName.passengerWalletTotal)) ?? double.tryParse(box.read(BoxName.passengerWalletTotal)) ?? 0.0;
0.0; // Handle potential parsing errors
return mapPassengerController.data.isNotEmpty && return mapPassengerController.data.isNotEmpty &&
mapPassengerController.isBottomSheetShown && mapPassengerController.isBottomSheetShown &&
!mapPassengerController.rideConfirm !mapPassengerController.rideConfirm &&
passengerWallet < 0.0 // Simplified condition
? Positioned( ? Positioned(
bottom: Get.height * .41, bottom: Get.height * .41,
child: Row( left: 16, // Add left margin for better positioning
mainAxisAlignment: MainAxisAlignment.end, right: 16, // Add right margin
children: [ child: Container(
if (passengerWallet < 0.0) // Use if statement for clarity padding: const EdgeInsets.all(12),
Container( decoration: BoxDecoration(
decoration: AppStyle.boxDecoration.copyWith( color: AppColor.redColor
color: AppColor.redColor.withOpacity(.3), .withOpacity(0.8), // More prominent color
), borderRadius: BorderRadius.circular(8),
height: 50, boxShadow: [
width: Get.width, BoxShadow(
child: Padding( color: Colors.black.withOpacity(0.1),
padding: const EdgeInsets.symmetric(horizontal: 8), blurRadius: 4,
child: Row( offset: const Offset(0, 2),
mainAxisAlignment: MainAxisAlignment.spaceAround, ),
],
),
child: Row(
children: [
const Icon(
Icons.warning_amber_rounded,
color: Colors.white,
size: 24,
),
const SizedBox(width: 8),
Expanded(
child: Text.rich(
TextSpan(
children: [ children: [
IconButton( TextSpan(
onPressed: () async => await Get.find< text: '${'Negative Balance:'.tr} ',
TextToSpeechController>() style: AppStyle.subtitle.copyWith(
.speakText('you have a negative balance of' color: Colors.white,
.tr + fontWeight: FontWeight.bold,
'${passengerWallet.toStringAsFixed(2)}' ),
' in your' ),
.tr + TextSpan(
' ${AppInformation.appName}' text:
' wallet due to a previous trip.' '${'You have a balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${box.read(BoxName.countryCode) == 'Egypt' ? 'LE'.tr : 'JOD'.tr} ${'due to a previous trip.'.tr}',
.tr), style: AppStyle.subtitle.copyWith(
icon: const Icon(Icons.headphones)), color: Colors.white,
Text( ),
'${'you have a negative balance of'.tr}${'${passengerWallet.toStringAsFixed(2)}\n${' in your'.tr}'} ${AppInformation.appName}${' wallet due to a previous trip.'.tr}',
textAlign: TextAlign.center,
style: AppStyle.subtitle,
), ),
], ],
), ),
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(width: 8),
// ElevatedButton(
// onPressed: () {
// Get.to(() => PassengerWallet());
// },
// style: ElevatedButton.styleFrom(
// backgroundColor: Colors.white,
// foregroundColor: AppColor.redColor,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(6),
// ),
// padding: const EdgeInsets.symmetric(horizontal: 12),
// textStyle: const TextStyle(fontWeight: FontWeight.bold),
// ),
// child: Text('Top Up'.tr),
// ),
],
),
), ),
) )
: const SizedBox(); : const SizedBox();

View File

@@ -12,7 +12,6 @@ import '../../../controller/home/map_passenger_controller.dart';
import '../../../main.dart'; import '../../../main.dart';
GetBuilder<MapPassengerController> formSearchPlacesDestenation() { GetBuilder<MapPassengerController> formSearchPlacesDestenation() {
// DbSql sql = DbSql.instance;
if (box.read(BoxName.addWork).toString() == '' || if (box.read(BoxName.addWork).toString() == '' ||
box.read(BoxName.addHome).toString() == '') { box.read(BoxName.addHome).toString() == '') {
box.write(BoxName.addWork, 'addWork'); box.write(BoxName.addWork, 'addWork');
@@ -20,349 +19,271 @@ GetBuilder<MapPassengerController> formSearchPlacesDestenation() {
} }
return GetBuilder<MapPassengerController>( return GetBuilder<MapPassengerController>(
builder: (controller) => Column( builder: (controller) => Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Row(
children: [ children: [
Padding( Expanded(
padding: const EdgeInsets.all(6), child: TextFormField(
child: Column( controller: controller.placeDestinationController,
children: [ onChanged: (value) {
Container( if (controller.placeDestinationController.text.length > 2) {
width: Get.width * .9, controller.getPlaces();
height: 40, controller.changeHeightPlaces();
decoration: } else if (controller
const BoxDecoration(color: AppColor.secondaryColor), .placeDestinationController.text.isEmpty) {
child: TextField( controller.clearPlacesDestination();
decoration: InputDecoration( controller.changeHeightPlaces();
border: const OutlineInputBorder( }
borderRadius: BorderRadius.only(), },
gapPadding: 4, decoration: InputDecoration(
borderSide: BorderSide( hintText: controller.hintTextDestinationPoint,
color: AppColor.redColor, hintStyle:
width: 2, AppStyle.subtitle.copyWith(color: Colors.grey[600]),
)), prefixIcon:
suffixIcon: const Icon(Icons.search), const Icon(Icons.search, color: AppColor.primaryColor),
hintText: controller.hintTextDestinationPoint, suffixIcon: controller
hintStyle: AppStyle.title, .placeDestinationController.text.isNotEmpty
hintMaxLines: 1, ? IconButton(
prefixIcon: IconButton( icon: Icon(Icons.clear, color: Colors.grey[400]),
onPressed: () { onPressed: () {
controller.placeDestinationController.clear(); controller.placeDestinationController.clear();
controller.clearPlacesDestination(); controller.clearPlacesDestination();
controller.changeHeightPlaces();
}, },
icon: Icon( )
Icons.clear, : null,
color: Colors.red[300], contentPadding: const EdgeInsets.symmetric(
), horizontal: 16.0, vertical: 10.0),
), border: OutlineInputBorder(
), borderRadius: BorderRadius.circular(8.0),
controller: controller.placeDestinationController, borderSide: BorderSide.none,
onChanged: (value) {
if (controller
.placeDestinationController.text.length >
5) {
controller.getPlaces();
controller.changeHeightPlaces();
}
},
// onEditingComplete: () => controller.changeHeight(),
),
), ),
const SizedBox( focusedBorder: OutlineInputBorder(
height: 10, borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide(color: AppColor.primaryColor),
), ),
Container( filled: true,
decoration: AppStyle.boxDecoration1 fillColor: Colors.grey[50],
.copyWith(color: AppColor.blueColor), ),
child: InkWell( ),
onTap: () { ),
controller.changeMainBottomMenuMap(); const SizedBox(width: 8.0),
controller.changePickerShown(); IconButton(
}, onPressed: () {
child: Padding( controller.changeMainBottomMenuMap();
padding: const EdgeInsets.symmetric( controller.changePickerShown();
horizontal: 20, vertical: 4), },
child: Text( icon: Icon(Icons.location_on_outlined,
controller.isAnotherOreder color: AppColor.accentColor, size: 30),
? 'Pick from map destination'.tr tooltip: controller.isAnotherOreder
: 'Pick from map'.tr, ? 'Pick destination on map'
style: AppStyle.title : 'Pick on map',
.copyWith(color: AppColor.secondaryColor),
),
),
)),
const SizedBox(
height: 10,
),
SizedBox(
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
InkWell(
onTap: () async {
if (box.read(BoxName.addWork) == 'addWork') {
controller.workLocationFromMap = true;
controller.changeMainBottomMenuMap();
controller.changePickerShown();
} else {
controller.hintTextDestinationPoint = 'To Work';
final latLng = LatLng(
double.parse(
box.read(BoxName.addWork).split(',')[0]),
double.parse(
box.read(BoxName.addWork).split(',')[1]),
);
controller.newMyLocation =
controller.newStartPointLocation;
controller.changeMainBottomMenuMap();
await controller.getDirectionMap(
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
'${latLng.latitude},${latLng.longitude}',
);
controller.currentLocationToFormPlaces = false;
controller.placesDestination = [];
// controller.isCancelRidePageShown = true;
controller.clearPlacesStart();
controller.clearPlacesDestination();
controller.passengerStartLocationFromMap =
false;
controller.isPickerShown = false;
controller.bottomSheet();
controller.showBottomSheet1();
}
},
onLongPress: () {
Get.defaultDialog(
title:
'Do you want to change Work location'.tr,
middleText: '',
confirm: MyElevatedButton(
title: 'Yes'.tr,
onPressed: () {
Get.back();
controller.workLocationFromMap = true;
controller.changeMainBottomMenuMap();
controller.changePickerShown();
}));
},
child: Container(
width: Get.width * .25,
decoration: BoxDecoration(
color: AppColor.blueColor.withOpacity(.4),
border: Border.all()),
child: Text(
' ${box.read(BoxName.addWork)}' == 'addWork'
? 'Add Work'.tr
: 'To Work'.tr,
textAlign: TextAlign.center,
style: AppStyle.title,
),
),
),
InkWell(
onLongPress: () {
Get.defaultDialog(
title:
'Do you want to change Home location'.tr,
middleText: '',
confirm: MyElevatedButton(
title: 'Yes'.tr,
onPressed: () {
Get.back();
controller.homeLocationFromMap = true;
controller.changeMainBottomMenuMap();
controller.changePickerShown();
}));
},
onTap: () async {
if (box.read(BoxName.addHome) == 'addHome') {
controller.homeLocationFromMap = true;
controller.changeMainBottomMenuMap();
controller.changePickerShown();
} else {
controller.hintTextDestinationPoint = 'To Home';
final latLng = LatLng(
double.parse(
box.read(BoxName.addHome).split(',')[0]),
double.parse(
box.read(BoxName.addHome).split(',')[1]),
);
controller.changeMainBottomMenuMap();
// controller.newMyLocation = latLng;
await controller.getDirectionMap(
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
'${latLng.latitude},${latLng.longitude}',
);
controller.currentLocationToFormPlaces = false;
controller.placesDestination = [];
// controller.isCancelRidePageShown = true;
controller.clearPlacesStart();
controller.clearPlacesDestination();
controller.passengerStartLocationFromMap =
false;
controller.isPickerShown = false;
// controller.showBottomSheet1();
// Get.back();
controller.showBottomSheet1();
// controller.newMyLocation = latLng;
controller.update();
controller.update();
}
},
child: Container(
width: Get.width * .25,
decoration: BoxDecoration(
color: AppColor.blueColor.withOpacity(.4),
border: Border.all()),
child: Text(
style: AppStyle.title,
textAlign: TextAlign.center,
'${box.read(BoxName.addHome) == 'addHome' ? 'Add Home'.tr : "To Home".tr} '),
),
),
],
),
)
],
), //
), ),
// controller.placesDestination.isEmpty
// ? InkWell(
// onTap: () {
// controller.changeMainBottomMenuMap();
// controller.changePickerShown();
// },
// child: Text(
// 'Choose from Map'.tr,
// style:
// AppStyle.title.copyWith(color: AppColor.blueColor),
// ),
// )
// : const SizedBox(),
Container(
height: controller.placesDestination.isNotEmpty
? controller.height
: 0,
color: AppColor.secondaryColor,
child: ListView.builder(
itemCount: controller.placesDestination.length,
itemBuilder: (BuildContext context, int index) {
var res = controller.placesDestination[index];
// Extract fields with null safety
var title = res['title']?.toString() ?? 'Unknown Place';
var position = res['position'];
var latitude = position?['lat'];
var longitude = position?['lng'];
var address =
res['address']?['label'] ?? 'Unknown Address';
var categories = res['categories'] ?? [];
var primaryCategory = categories.isNotEmpty
? categories[0]['name']
: 'Unknown Category';
return InkWell(
onTap: () async {
if (latitude != null && longitude != null) {
sql.insertMapLocation({
'latitude': latitude,
'longitude': longitude,
'name': title,
'rate': 'N/A',
'createdAt': DateTime.now().toIso8601String(),
// No rating in this structure, adjust as needed
}, 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,
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
const Icon(Icons.place,
size: 20), // Fallback icon for places
IconButton(
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,
);
}
},
icon: const Icon(Icons.favorite_border),
),
],
),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
title,
style: AppStyle.title,
),
Text(
address,
style: AppStyle.subtitle,
),
Text(
primaryCategory,
style: AppStyle.subtitle,
),
],
),
),
],
),
const Divider(thickness: 1),
],
),
),
);
},
))
], ],
)); ),
),
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 ? 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.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['title']?.toString() ?? 'Unknown Place';
var position = res['position'];
var latitude = position?['lat'];
var longitude = position?['lng'];
var address = res['address']?['label'] ?? 'Unknown Address';
var categories = res['categories'] ?? [];
var primaryCategory = categories.isNotEmpty
? categories[0]['name']
: 'Unknown Category';
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) {
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();
} }

View File

@@ -9,181 +9,130 @@ import '../../../controller/home/map_passenger_controller.dart';
import '../../../main.dart'; import '../../../main.dart';
GetBuilder<MapPassengerController> formSearchPlacesStart() { GetBuilder<MapPassengerController> formSearchPlacesStart() {
// DbSql sql = DbSql.instance;
return GetBuilder<MapPassengerController>( return GetBuilder<MapPassengerController>(
builder: (controller) => Column( builder: (controller) => Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Row(
children: [ children: [
Padding( Expanded(
padding: const EdgeInsets.all(8), child: TextFormField(
child: Row( controller: controller.placeStartController,
mainAxisAlignment: MainAxisAlignment.spaceBetween, onChanged: (value) {
children: [ if (controller.placeStartController.text.length > 2) {
Container( // Reduced character limit
width: Get.width * .75, controller.getPlacesStart();
height: 40, controller.changeHeightStartPlaces();
decoration: } else if (controller.placeStartController.text.isEmpty) {
const BoxDecoration(color: AppColor.secondaryColor), controller.clearPlacesStart();
child: TextFormField( controller.changeHeightPlaces(); // Collapse if empty
decoration: InputDecoration( }
border: const OutlineInputBorder( },
borderRadius: BorderRadius.only(), decoration: InputDecoration(
gapPadding: 4, hintText: controller.hintTextStartPoint,
borderSide: BorderSide( hintStyle:
color: AppColor.redColor, AppStyle.subtitle.copyWith(color: Colors.grey[600]),
width: 2, prefixIcon:
)), const Icon(Icons.search, color: AppColor.primaryColor),
suffixIcon: const Icon(Icons.search), suffixIcon: controller.placeStartController.text.isNotEmpty
hintText: controller.hintTextStartPoint, ? IconButton(
hintStyle: AppStyle.title, icon: Icon(Icons.clear, color: Colors.grey[400]),
hintMaxLines: 1,
prefixIcon: IconButton(
onPressed: () { onPressed: () {
controller.placeStartController.clear(); controller.placeStartController.clear();
controller.clearPlacesStart(); controller.clearPlacesStart();
controller
.changeHeightPlaces(); // Collapse on clear
}, },
icon: Icon( )
Icons.clear, : null,
color: Colors.red[300], contentPadding: const EdgeInsets.symmetric(
), horizontal: 16.0, vertical: 10.0),
), border: OutlineInputBorder(
), borderRadius: BorderRadius.circular(8.0),
controller: controller.placeStartController, borderSide: BorderSide.none,
onChanged: (value) {
if (controller.placeStartController.text.length > 5) {
controller.getPlacesStart();
controller.changeHeightStartPlaces();
}
},
// onEditingComplete: () => controller.changeHeight(),
),
), ),
IconButton( focusedBorder: OutlineInputBorder(
onPressed: () { borderRadius: BorderRadius.circular(8.0),
controller.startLocationFromMap = true; borderSide: BorderSide(color: AppColor.primaryColor),
controller.changeMainBottomMenuMap();
controller.changePickerShown();
},
icon: const Icon(
Icons.map_outlined,
color: AppColor.yellowColor,
),
), ),
], filled: true,
fillColor: Colors.grey[50],
),
), ),
), ),
// controller.placesDestination.isEmpty const SizedBox(width: 8.0),
// ? InkWell( IconButton(
// onTap: () { onPressed: () {
// controller.startLocationFromMap = true; controller.startLocationFromMap = true;
// controller.changeMainBottomMenuMap(); controller.changeMainBottomMenuMap();
// controller.changePickerShown(); controller.changePickerShown();
// }, },
// child: Text( icon: Icon(Icons.location_on_outlined,
// 'Choose from Map Start Point'.tr, color: AppColor.accentColor, size: 30),
// style: tooltip: 'Choose on Map',
// AppStyle.title.copyWith(color: AppColor.blueColor), ),
// ), ],
// ) ),
// : const SizedBox(), ),
Container( AnimatedContainer(
height: duration: const Duration(milliseconds: 200),
controller.placesStart.isNotEmpty ? controller.height : 0, height: controller.placesStart.isNotEmpty ? controller.height : 0,
color: AppColor.secondaryColor, decoration: BoxDecoration(
child: ListView.builder( color: Colors.white,
itemCount: controller.placesStart.length, borderRadius: BorderRadius.circular(8.0),
itemBuilder: (BuildContext context, int index) { ),
var res = controller.placesStart[index]; margin: const EdgeInsets.symmetric(horizontal: 16.0),
return InkWell( child: ListView.separated(
onTap: () async { shrinkWrap: true,
controller.changeHeightPlaces(); physics: const NeverScrollableScrollPhysics(),
// if (controller.currentLocationToFormPlaces == true) { itemCount: controller.placesStart.length,
// controller.newStartPointLocation = separatorBuilder: (context, index) =>
// controller.myLocation; const Divider(height: 1, color: Colors.grey),
// } else { itemBuilder: (BuildContext context, int index) {
// controller.myLocation = var res = controller.placesStart[index];
// controller.newStartPointLocation; return ListTile(
// } leading: Image.network(res['icon'], width: 30, height: 30),
await sql.insertMapLocation({ title: Text(res['name'].toString(),
'latitude': res['geometry']['location']['lat'], style: AppStyle.subtitle
'longitude': res['geometry']['location']['lng'], .copyWith(fontWeight: FontWeight.w500)),
'name': res['name'].toString(), subtitle: Text(res['vicinity'].toString(),
'rate': res['rating'].toString(), style: TextStyle(color: Colors.grey[600], fontSize: 12)),
'createdAt': DateTime.now().toIso8601String(), trailing: IconButton(
}, TableName.recentLocations); icon: const Icon(Icons.favorite_border, color: Colors.grey),
onPressed: () async {
controller.convertHintTextStartNewPlaces(index); await sql.insertMapLocation({
controller.currentLocationString = res['name']; 'latitude': res['geometry']['location']['lat'],
controller.placesStart = []; 'longitude': res['geometry']['location']['lng'],
controller.placeStartController.clear(); 'name': res['name'].toString(),
}, 'rate': res['rating'].toString(),
child: Padding( }, TableName.placesFavorite);
padding: const EdgeInsets.symmetric(horizontal: 10), Toast.show(
child: Column( context,
children: [ '${res['name']} ${'Saved Successfully'.tr}',
Row( AppColor.primaryColor);
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,
)
],
),
),
);
}, },
), ),
) 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();
},
);
},
),
),
],
),
);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -15,162 +15,182 @@ import 'package:url_launcher/url_launcher.dart';
import '../../../constant/colors.dart'; import '../../../constant/colors.dart';
import '../../../controller/home/map_passenger_controller.dart'; import '../../../controller/home/map_passenger_controller.dart';
import '../../notification/notification_page.dart'; import '../../notification/notification_page.dart';
import '../../widgets/icon_widget_menu.dart';
import '../setting_page.dart'; import '../setting_page.dart';
import '../profile/passenger_profile_page.dart'; import '../profile/passenger_profile_page.dart';
class MapMenuWidget extends StatelessWidget { class MapMenuWidget extends StatelessWidget {
const MapMenuWidget({ const MapMenuWidget({super.key});
super.key,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>( return GetBuilder<MapPassengerController>(
builder: (controller) => Stack(children: [ builder: (controller) => Stack(
Positioned( children: [
right: 60, // Top Menu Bar
left: 60, Positioned(
child: Padding( top: 10, // Adjust as needed
padding: const EdgeInsets.only(right: 20), left: 0,
child: Opacity( right: 0,
alwaysIncludeSemantics: false, child: SafeArea(
opacity: 1, // Adjust the opacity value as needed child: Padding(
child: AnimatedContainer( padding: const EdgeInsets.symmetric(horizontal: 20),
width: Get.width * .6, child: Row(
decoration: AppStyle.boxDecoration mainAxisAlignment: MainAxisAlignment.spaceAround,
.copyWith(color: AppColor.blueColor), children: [
transform: Matrix4.translationValues( // GestureDetector(
controller.heightMenu * .1, 1, 1), // onTap: controller.getDrawerMenu,
curve: Curves.easeOutCubic, // child: Container(
clipBehavior: Clip.hardEdge, // padding: const EdgeInsets.all(10),
duration: const Duration(milliseconds: 300), // decoration: AppStyle.boxDecoration
height: controller.heightMenu, // .copyWith(color: AppColor.blueColor),
child: controller.heightMenuBool // child: const Icon(Icons.menu, color: Colors.white),
? Row( // ),
mainAxisAlignment: MainAxisAlignment.spaceAround, // ),
children: [ if (controller.heightMenuBool)
IconWidgetMenu( Expanded(
onpressed: () { child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
height: 50, // Fixed height for the top menu
margin: const EdgeInsets.only(left: 10),
decoration: AppStyle.boxDecoration
.copyWith(color: AppColor.blueColor),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
onPressed: () {
Get.to( Get.to(
() => const NotificationPage(), () => const NotificationPage(),
transition: Transition.circularReveal, transition: Transition.circularReveal,
); );
}, },
title: 'Notifications'.tr, icon: const Icon(Icons.notifications,
icon: Icons.notifications), color: Colors.white),
IconWidgetMenu( ),
onpressed: () { IconButton(
Get.to( onPressed: () {
() => PassengerProfilePage(), Get.to(() => PassengerProfilePage(),
transition: Transition.zoom, transition: Transition.zoom);
);
},
icon: Icons.person,
title: 'Profile'.tr,
),
IconWidgetMenu(
title: 'Home'.tr,
onpressed: () {
Get.to(
() => const SettingPage(),
transition: Transition.downToUp,
curve: Curves.easeInOutExpo,
);
}, },
icon: Icons.settings), icon: const Icon(Icons.person,
], color: Colors.white),
) ),
: const SizedBox(), // Choose the desired overlay color IconButton(
)), onPressed: () {
Get.to(() => const SettingPage(),
transition: Transition.downToUp,
curve: Curves.easeInOutExpo);
},
icon: const Icon(Icons.settings,
color: Colors.white),
),
],
),
),
),
],
),
),
),
), ),
), // Side Drawer (Main Menu)
Positioned( Positioned(
right: 5, top: 80, // Adjust as needed
top: 80, left: 10,
child: AnimatedContainer( child: AnimatedContainer(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
decoration: AppStyle.boxDecoration1,
width: controller.widthMenu, width: controller.widthMenu,
child: Column( constraints: const BoxConstraints(
mainAxisAlignment: MainAxisAlignment.spaceAround, maxWidth: 250), // Add max width constraint
children: [
IconMainPageMap(
onTap: () {
Get.to(() => const PassengerWallet());
},
title: 'My Wallet'.tr,
icon: Icons.wallet,
),
IconMainPageMap(
onTap: () async {
Get.to(() => const OrderHistory());
},
title: 'Order History'.tr,
icon: Icons.history,
),
IconMainPageMap(
onTap: () {
Get.to(() => ContactUsPage());
},
title: "Contact Us".tr,
icon: Icons.contact_page,
),
],
),
)),
Positioned(
left: 5,
top: 80,
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
decoration: AppStyle.boxDecoration1,
width: controller.widthMenu,
height: Get.height * .3,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconMainPageMap(
onTap: () async {
final String driverAppUrl;
if (defaultTargetPlatform == TargetPlatform.android) {
driverAppUrl =
'https://play.google.com/store/apps/details?id=com.sefer_driver&pli=1'; // Replace with your driver app's Play Store URL
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
driverAppUrl =
'https://apps.apple.com/app/sefer-driver/id6502189302'; // Replace with your driver app's App Store ID
} else {
// Handle other platforms or unknown platform (optional)
return;
}
if (await canLaunchUrl(Uri.parse(driverAppUrl))) { child: ClipRRect(
await launchUrl(Uri.parse(driverAppUrl)); borderRadius: BorderRadius.circular(15),
} else { child: Material(
throw 'Could not launch app store URL'; color: Colors.white, // Background color of the drawer
} child: Column(
}, mainAxisSize: MainAxisSize.min,
title: 'Driver'.tr, children: [
icon: WeatherIcons.wi_moon_14, IconMainPageMap(
onTap: () {
Get.to(() => const PassengerWallet());
},
title: 'My Wallet'.tr,
icon: Icons.wallet,
),
IconMainPageMap(
onTap: () async {
Get.to(() => const OrderHistory());
},
title: 'Order History'.tr,
icon: Icons.history,
),
IconMainPageMap(
onTap: () {
Get.to(() => ContactUsPage());
},
title: "Contact Us".tr,
icon: Icons.contact_page,
),
IconMainPageMap(
onTap: () async {
final String driverAppUrl;
if (defaultTargetPlatform == TargetPlatform.android) {
driverAppUrl =
'https://play.google.com/store/apps/details?id=your_android_driver_app_id'; // Replace with your driver app's Play Store URL
} else if (defaultTargetPlatform ==
TargetPlatform.iOS) {
driverAppUrl =
'https://apps.apple.com/app/your_ios_driver_app_id'; // Replace with your driver app's App Store ID
} else {
// Handle other platforms or unknown platform (optional)
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.',
snackPosition: SnackPosition.BOTTOM,
);
}
} catch (e) {
debugPrint('Error launching URL: $e');
Get.snackbar(
'Error',
'Could not open the link.',
snackPosition: SnackPosition.BOTTOM,
);
}
},
title: 'Driver'.tr,
icon: WeatherIcons.wi_moon_14,
),
IconMainPageMap(
onTap: () {
Get.to(() => ComplaintPage());
},
title: 'Complaint'.tr,
icon: Icons.feedback,
),
IconMainPageMap(
onTap: () {
Get.to(() => const PromosPassengerPage());
},
title: 'Promos'.tr,
icon: Icons.monetization_on,
),
],
), ),
IconMainPageMap( ),
onTap: () {
Get.to(() => ComplaintPage());
},
title: 'Complaint'.tr,
icon: Icons.feedback,
),
IconMainPageMap(
onTap: () {
Get.to(() => const PromosPassengerPage());
},
title: 'Promos'.tr,
icon: Icons.monetization_on,
),
],
), ),
)) ),
]), ),
],
),
); );
} }
} }
@@ -189,29 +209,21 @@ class IconMainPageMap extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FutureBuilder( return InkWell(
future: Future.delayed(const Duration(milliseconds: 400)), onTap: onTap,
builder: (context, snapshot) { child: Padding(
return GestureDetector( padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 1),
onTap: onTap, child: Row(
child: SizedBox( children: [
height: Get.height * .1, Icon(icon, size: 24),
width: double.maxFinite, const SizedBox(width: 16),
// decoration: AppStyle.boxDecoration, Text(
child: Padding( title.tr,
padding: const EdgeInsets.all(8.0), style: AppStyle.subtitle,
child: Column(
children: [
Icon(icon),
Text(
title.tr,
style: AppStyle.subtitle,
),
],
),
),
), ),
); ],
}); ),
),
);
} }
} }

View File

@@ -15,296 +15,252 @@ import '../../../controller/functions/toast.dart';
import '../../../controller/home/map_passenger_controller.dart'; import '../../../controller/home/map_passenger_controller.dart';
class RideBeginPassenger extends StatelessWidget { class RideBeginPassenger extends StatelessWidget {
const RideBeginPassenger({ const RideBeginPassenger({super.key});
super.key,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
ProfileController profileController = Get.put(ProfileController()); ProfileController profileController = Get.put(ProfileController());
AudioRecorderController audioController = AudioRecorderController audioController =
Get.put(AudioRecorderController()); Get.put(AudioRecorderController());
// Get.put(MapPassengerController());
return GetBuilder<MapPassengerController>(builder: (controller) { return GetBuilder<MapPassengerController>(builder: (controller) {
if (controller.statusRide == 'Begin' || !controller.statusRideFromStart) { if (controller.statusRide == 'Begin') {
return Positioned( return Positioned(
left: 10, left: 10,
right: 10, right: 10,
bottom: 10, bottom: 10,
child: Container( child: Card(
decoration: AppStyle.boxDecoration, // Wrapped in a Card
height: controller.statusRide == 'Begin' ? Get.height * .33 : 0, elevation: 5,
// width: 100, shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(15.0),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisSize: MainAxisSize.min, // Use minimum space
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
CircleAvatar( CircleAvatar(
radius: 30, radius: 30,
backgroundImage: NetworkImage( backgroundImage: NetworkImage(
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg'), '${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg',
),
), ),
Column( const SizedBox(width: 10),
children: [ Expanded(
Container( child: Column(
decoration: AppStyle.boxDecoration, crossAxisAlignment: CrossAxisAlignment.start,
child: Text( children: [
controller.driverName, Text(controller.driverName, style: AppStyle.title),
style: AppStyle.title, Row(
),
),
Container(
decoration: AppStyle.boxDecoration,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
Text( Text(controller.make, style: AppStyle.subtitle),
controller.make, const SizedBox(width: 5),
style: AppStyle.title, Text(controller.model,
), style: AppStyle.subtitle),
Text(
controller.model,
style: AppStyle.title,
),
], ],
), ),
), ],
], ),
),
Column(
children: <Widget>[
const Text(''),
Container(
decoration: AppStyle.boxDecoration,
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 4),
child: Text(
controller.licensePlate,
style: AppStyle.title,
),
),
),
],
), ),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Container( Text(
decoration: AppStyle.boxDecoration, controller.licensePlate,
child: Padding( style: AppStyle.title.copyWith(fontSize: 16),
padding: const EdgeInsets.all(3),
child: Text(
'${box.read(BoxName.carType)}',
style: AppStyle.title,
),
),
), ),
Text( Text(
'${controller.driverRate} 📈', '${box.read(BoxName.carType)}',
style: AppStyle.title, style: AppStyle.title.copyWith(fontSize: 16),
),
Text(
'${controller.driverRate} ⭐️',
style: AppStyle.title
.copyWith(color: AppColor.greenColor),
), ),
], ],
), ),
], ],
), ),
// SizedBox( const SizedBox(height: 15),
// height: 5,
// ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
InkWell( SizedBox(
onTap: () { width: Get.width * 0.18,
controller.getDialog('Arrival time'.tr, child: InkWell(
'arrival time to reach your point'.tr, () {}); onTap: () => controller.getDialog(
}, 'Arrival time'.tr,
child: Container( 'arrival time to reach your point'.tr,
width: Get.width * .15, () {},
decoration: AppStyle.boxDecoration, ),
child: Column( child: Column(
children: [ children: [
Text( const Icon(Icons.timer_outlined, size: 28),
'⏱️', Text(controller.arrivalTime,
style: AppStyle.title, style: AppStyle.title),
),
Text(
controller.arrivalTime,
style: AppStyle.title,
),
], ],
), ),
), ),
), ),
InkWell( SizedBox(
onTap: () { width: Get.width * 0.18,
controller.getDialog( child: InkWell(
'Price of trip'.tr, onTap: () => controller.getDialog(
'For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance' 'Price of trip'.tr,
.tr, () { 'For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance'
Get.back(); .tr,
}); () => Get.back(),
}, ),
child: Container(
width: Get.width * .15,
decoration: AppStyle.boxDecoration,
child: Column( child: Column(
children: [ children: [
const Icon(Icons.monetization_on, size: 28),
Text( Text(
'💵 ', '${controller.totalPassenger.toStringAsFixed(2)}',
style: AppStyle.title, style: AppStyle.title),
),
Text(
controller.totalPassenger.toStringAsFixed(2),
style: AppStyle.title,
),
], ],
), ),
), ),
), ),
Container( SizedBox(
width: Get.width * .15, width: Get.width * 0.18,
decoration: AppStyle.boxDecoration,
child: IconButton( child: IconButton(
onPressed: () => Get.to( onPressed: () => Get.to(() => ComplaintPage(),
() => ComplaintPage(), transition: Transition.downToUp),
transition: Transition.downToUp, icon: const Icon(Icons.note_add,
), color: AppColor.redColor),
icon: const Icon( tooltip: 'Add Note',
Icons.note_add,
color: AppColor.redColor,
),
tooltip: ' Add Note', // Optional tooltip for clarity
), ),
), ),
Container( SizedBox(
width: Get.width * .15, width: Get.width * 0.18,
decoration: AppStyle.boxDecoration, child: IconButton(
child: audioController.isRecording == false onPressed: () async {
? IconButton( if (audioController.isRecording == false) {
onPressed: () async { await audioController.startRecording();
await audioController.startRecording(); Toast.show(context, 'Start Record'.tr,
Toast.show(context, 'Start Record'.tr, AppColor.greenColor);
AppColor.greenColor); } else {
}, await audioController.stopRecording();
icon: const Icon( Toast.show(context, 'Record saved'.tr,
Icons.play_circle_fill_outlined, AppColor.greenColor);
color: AppColor.greenColor, }
), },
tooltip: icon: Icon(
' Add Note', // Optional tooltip for clarity audioController.isRecording == false
) ? Icons.mic_none
: IconButton( : Icons.mic_off,
onPressed: () async { color: AppColor.greenColor,
await audioController.stopRecording(); ),
Toast.show(context, 'Record saved'.tr, tooltip: audioController.isRecording == false
AppColor.greenColor); ? 'Start Recording'
}, : 'Stop Recording',
icon: const Icon( ),
Icons.stop_circle,
color: AppColor.greenColor,
),
tooltip:
' Add Note', // Optional tooltip for clarity
),
), ),
], ],
), ),
const SizedBox(height: 15),
Stack( Stack(
alignment: Alignment.center,
children: [ children: [
// StreamCounter(),
LinearProgressIndicator( LinearProgressIndicator(
backgroundColor: AppColor.accentColor, backgroundColor: AppColor.accentColor
.withOpacity(0.3), // Added background
color: controller.remainingTimeTimerRideBegin < 60 color: controller.remainingTimeTimerRideBegin < 60
? AppColor.redColor ? AppColor.redColor
: AppColor.greenColor, : AppColor.greenColor,
minHeight: 25, minHeight: 20,
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(10),
value: controller.progressTimerRideBegin.toDouble(), value: controller.progressTimerRideBegin.toDouble(),
), ),
Center( Text(
child: Text( controller.stringRemainingTimeRideBegin,
controller.stringRemainingTimeRideBegin, style: AppStyle.title.copyWith(fontSize: 14),
style: AppStyle.title, ),
),
)
], ],
), ),
const SizedBox(height: 15),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
Container( SizedBox(
decoration: AppStyle.boxDecoration, width: Get.width * 0.18,
width: Get.width * .15, child: Column(
child: IconButton( children: [
onPressed: () async { IconButton(
if (box.read(BoxName.sosPhonePassenger) == null) { onPressed: () async {
{ if (box.read(BoxName.sosPhonePassenger) ==
await profileController.updatField( null) {
'sosPhone', TextInputType.phone); await profileController.updatField(
box.write(BoxName.sosPhonePassenger, 'sosPhone', TextInputType.phone);
profileController.prfoileData['sosPhone']); box.write(
} BoxName.sosPhonePassenger,
} else { profileController
makePhoneCall('122'); .prfoileData['sosPhone']);
// box.read(BoxName.sosPhonePassenger)); } else {
} makePhoneCall('122');
}, }
icon: const Icon( },
Icons.sos_rounded, icon: const Icon(Icons.sos_rounded,
color: AppColor.redColor, color: AppColor.redColor),
), ),
Text('SOS', style: AppStyle.title),
],
), ),
), ),
Container( SizedBox(
decoration: AppStyle.boxDecoration, width: Get.width * 0.18,
width: Get.width * .15, child: Column(
child: IconButton( children: [
onPressed: () async { IconButton(
if (box.read(BoxName.sosPhonePassenger) == null || onPressed: () async {
box.read(BoxName.sosPhonePassenger) == 'sos') { if (box.read(BoxName.sosPhonePassenger) ==
{ null ||
await profileController.updatField( box.read(BoxName.sosPhonePassenger) ==
'sosPhone', TextInputType.phone); 'sos') {
box.write(BoxName.sosPhonePassenger, await profileController.updatField(
profileController.prfoileData['sosPhone']); 'sosPhone', TextInputType.phone);
} box.write(
} else { BoxName.sosPhonePassenger,
String phoneNumber = box profileController
.read(BoxName.sosPhonePassenger) .prfoileData['sosPhone']);
.toString(); } else {
// phoneNumber = phoneNumber.replaceAll('0', ''); final phoneNumber = box
var phone = box.read(BoxName.countryCode) == .read(BoxName.sosPhonePassenger)
'Egypt' .toString();
? '+2${box.read(BoxName.sosPhonePassenger)}' final phone =
: '+962${box.read(BoxName.sosPhonePassenger)}'; box.read(BoxName.countryCode) == 'Egypt'
controller.sendWhatsapp(phone); ? '+2$phoneNumber'
} : '+962$phoneNumber';
}, controller.sendWhatsapp(phone);
icon: const Icon( }
FontAwesome.whatsapp, },
color: AppColor.greenColor, icon: const Icon(FontAwesome.whatsapp,
), color: AppColor.greenColor),
),
Text('WhatsApp', style: AppStyle.title),
],
), ),
), ),
Container( SizedBox(
decoration: AppStyle.boxDecoration, width: Get.width * 0.18,
width: Get.width * .15, child: Column(
child: IconButton( children: [
onPressed: () async { IconButton(
await controller.getTokenForParent(); onPressed: () async {
}, await controller.getTokenForParent();
icon: const Icon( },
Foundation.video, icon: const Icon(Foundation.video,
color: AppColor.blueColor, color: AppColor.blueColor),
), ),
Text('Video Call', style: AppStyle.title),
],
), ),
), ),
], ],
) ),
], ],
), ),
), ),
@@ -317,6 +273,7 @@ class RideBeginPassenger extends StatelessWidget {
} }
} }
// Removed the StreamCounter widget as it's not directly part of the RideBeginPassenger UI.
class StreamCounter extends StatelessWidget { class StreamCounter extends StatelessWidget {
const StreamCounter({Key? key}) : super(key: key); const StreamCounter({Key? key}) : super(key: key);

View File

@@ -21,35 +21,83 @@ class SearchingCaptainWindow extends StatelessWidget {
left: 0, left: 0,
right: 0, right: 0,
child: Container( child: Container(
decoration: AppStyle.boxDecoration1, padding: const EdgeInsets.all(16),
height: Get.height * .25, decoration: BoxDecoration(
child: Column( color: Theme.of(context)
mainAxisAlignment: MainAxisAlignment.spaceAround, .scaffoldBackgroundColor, // Use theme color
// Use Stack for overlapping widgets borderRadius: const BorderRadius.only(
children: [ topLeft: Radius.circular(20),
// Text elements topRight: Radius.circular(20),
),
SizedBox( boxShadow: [
width: Get.width * .7, BoxShadow(
child: const LinearProgressIndicator( color: Colors.black.withOpacity(0.1),
minHeight: 6, blurRadius: 10,
backgroundColor: AppColor.yellowColor, offset: const Offset(0, -5),
color: AppColor.secondaryColor,
),
), ),
],
),
child: Column(
mainAxisSize: MainAxisSize.min, // Fit content
children: [
Text( Text(
mapPassengerController.driversStatusForSearchWindow, mapPassengerController.driversStatusForSearchWindow,
style: AppStyle.title, style: AppStyle.title.copyWith(
fontSize: 18,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
), ),
// Text( const SizedBox(height: 12),
// "We are searching for the nearest driver to you".tr,
// style: AppStyle.title,
// ),
Text( Text(
'please wait till driver accept your order'.tr, '${'We are searching for the nearest driver to you'.tr}...', // Add ellipsis
style: AppStyle.title, style: AppStyle.subtitle.copyWith(
), // Timer logic color: Colors.grey.shade600,
_buildTimer(mapPassengerController), ),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
SizedBox(
width: Get.width * 0.8,
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: LinearProgressIndicator(
minHeight: 8,
backgroundColor:
AppColor.accentColor.withOpacity(0.3),
color: AppColor.primaryColor,
valueColor: const AlwaysStoppedAnimation<Color>(
AppColor.primaryColor),
),
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.timer_outlined,
size: 16, color: Colors.grey),
const SizedBox(width: 4),
_buildTimer(mapPassengerController),
],
),
// const SizedBox(height: 8),
// ElevatedButton(
// onPressed: () {
// // Add logic to cancel the search if needed
// // mapPassengerController.cancelSearch();
// Get.back(); // Example: go back to the previous screen
// },
// style: ElevatedButton.styleFrom(
// backgroundColor: Colors.grey.shade300,
// foregroundColor: Colors.black87,
// elevation: 0,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(8),
// ),
// ),
// child: Text('Cancel Search'.tr),
// ),
], ],
), ),
), ),
@@ -60,6 +108,22 @@ class SearchingCaptainWindow extends StatelessWidget {
} }
} }
// Widget _buildTimer(MapPassengerController mapPassengerController) {
// return Obx(() {
// final remainingSeconds = mapPassengerController.searchingDuration.value;
// final minutes = (remainingSeconds ~/ 60).toString().padLeft(2, '0');
// final seconds = (remainingSeconds % 60).toString().padLeft(2, '0');
// return Text(
// '$minutes:$seconds',
// style: const TextStyle(
// fontSize: 16,
// fontWeight: FontWeight.w500,
// color: Colors.grey,
// ),
// );
// });
// }
Widget _buildTimer(MapPassengerController mapPassengerController) { Widget _buildTimer(MapPassengerController mapPassengerController) {
// Start timer at 0 // Start timer at 0
Timer? timer; Timer? timer;

View File

@@ -1,4 +1,3 @@
import 'package:SEFER/controller/home/map_passenger_controller.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:SEFER/constant/style.dart'; import 'package:SEFER/constant/style.dart';
@@ -84,16 +83,54 @@ class OrderHistory extends StatelessWidget {
), ),
zoom: 12, zoom: 12,
), ),
// bounds: LatLngBounds( // Dynamically calculate the correct LatLngBounds
// northeast: LatLng( onMapCreated:
// double.parse(rides['end_location'].toString().split(',')[0]), (GoogleMapController controller) {
// double.parse(rides['end_location'].toString().split(',')[1]), final LatLng startLocation = LatLng(
// ), double.parse(rides['start_location']
// southwest: LatLng( .toString()
// double.parse(rides['start_location'].toString().split(',')[0]), .split(',')[0]),
// double.parse(rides['start_location'].toString().split(',')[1]), double.parse(rides['start_location']
// ), .toString()
// ), .split(',')[1]),
);
final LatLng endLocation = LatLng(
double.parse(rides['end_location']
.toString()
.split(',')[0]),
double.parse(rides['end_location']
.toString()
.split(',')[1]),
);
final LatLngBounds bounds =
LatLngBounds(
northeast: LatLng(
startLocation.latitude >
endLocation.latitude
? startLocation.latitude
: endLocation.latitude,
startLocation.longitude >
endLocation.longitude
? startLocation.longitude
: endLocation.longitude,
),
southwest: LatLng(
startLocation.latitude <
endLocation.latitude
? startLocation.latitude
: endLocation.latitude,
startLocation.longitude <
endLocation.longitude
? startLocation.longitude
: endLocation.longitude,
),
);
controller.animateCamera(
CameraUpdate.newLatLngBounds(
bounds, 50));
},
zoomControlsEnabled: true, zoomControlsEnabled: true,
polylines: { polylines: {
Polyline( Polyline(

View File

@@ -25,7 +25,7 @@ class IconWidgetMenu extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Container( Container(
width: 50, width: 40,
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: AppColor.secondaryColor, color: AppColor.secondaryColor,
shape: BoxShape.circle, shape: BoxShape.circle,