24-12/26/1
This commit is contained in:
@@ -575,7 +575,7 @@ class MapPassengerController extends GetxController {
|
||||
void getDrawerMenu() {
|
||||
heightMenuBool = !heightMenuBool;
|
||||
widthMapTypeAndTraffic = heightMenuBool == true ? 0 : 50;
|
||||
heightMenu = heightMenuBool == true ? 70 : 0;
|
||||
heightMenu = heightMenuBool == true ? 80 : 0;
|
||||
widthMenu = heightMenuBool == true ? 110 : 0;
|
||||
update();
|
||||
}
|
||||
@@ -3160,7 +3160,7 @@ class MapPassengerController extends GetxController {
|
||||
} else {
|
||||
isMainBottomMenuMap = !isMainBottomMenuMap;
|
||||
mainBottomMenuMapHeight =
|
||||
isMainBottomMenuMap == true ? Get.height * .2 : Get.height * .55;
|
||||
isMainBottomMenuMap == true ? Get.height * .2 : Get.height * .7;
|
||||
isWayPointSheet = false;
|
||||
if (heightMenuBool == true) {
|
||||
getDrawerMenu();
|
||||
@@ -4074,7 +4074,7 @@ class MapPassengerController extends GetxController {
|
||||
LatLngBounds(northeast: northeast, southwest: southwest);
|
||||
|
||||
// Fit the camera to the bounds
|
||||
var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData, 100);
|
||||
var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData, 130);
|
||||
mapController!.animateCamera(cameraUpdate);
|
||||
|
||||
// getDistanceFromText(data[0]['distance']['text']);
|
||||
@@ -4132,117 +4132,51 @@ class MapPassengerController extends GetxController {
|
||||
}
|
||||
|
||||
Future<void> _animatePolyline(List<LatLng> coordinates) async {
|
||||
// Initial animation
|
||||
polyLines.clear();
|
||||
List<LatLng> animatedPoints = [];
|
||||
const int totalAnimations = 7;
|
||||
|
||||
// Draw initial polyline
|
||||
for (int i = 0; i < coordinates.length; i++) {
|
||||
animatedPoints.add(coordinates[i]);
|
||||
polyLines.clear();
|
||||
polyLines.add(
|
||||
Polyline(
|
||||
polylineId: const PolylineId('animated_route'),
|
||||
points: List<LatLng>.from(animatedPoints),
|
||||
width: 4,
|
||||
color: AppColor.primaryColor,
|
||||
endCap: Cap.roundCap,
|
||||
startCap: Cap.roundCap,
|
||||
geodesic: true,
|
||||
),
|
||||
);
|
||||
|
||||
update();
|
||||
await Future.delayed(const Duration(milliseconds: 1));
|
||||
Color getAnimationColor(int cycle) {
|
||||
switch (cycle) {
|
||||
case 0:
|
||||
return AppColor.primaryColor;
|
||||
case 1:
|
||||
return AppColor.writeColor;
|
||||
case 2:
|
||||
return AppColor.primaryColor;
|
||||
default:
|
||||
return AppColor.primaryColor;
|
||||
}
|
||||
}
|
||||
|
||||
// Color change animations
|
||||
for (int cycle = 0; cycle < 6; cycle++) {
|
||||
// Change to green
|
||||
for (int cycle = 0; cycle < totalAnimations; cycle++) {
|
||||
polyLines.clear();
|
||||
polyLines.add(
|
||||
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));
|
||||
List<LatLng> animatedPoints = [];
|
||||
|
||||
// Change back to primary color
|
||||
polyLines.clear();
|
||||
polyLines.add(
|
||||
Polyline(
|
||||
polylineId: const PolylineId('animated_route'),
|
||||
points: coordinates,
|
||||
width: 4,
|
||||
color: AppColor.writeColor,
|
||||
endCap: Cap.roundCap,
|
||||
startCap: Cap.roundCap,
|
||||
geodesic: true,
|
||||
),
|
||||
);
|
||||
update();
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
for (int i = 0; i < coordinates.length; i++) {
|
||||
animatedPoints.add(coordinates[i]);
|
||||
polyLines.clear();
|
||||
polyLines.add(
|
||||
Polyline(
|
||||
polylineId: const PolylineId('animated_route'),
|
||||
points: List<LatLng>.from(animatedPoints),
|
||||
width: 4,
|
||||
color: getAnimationColor(cycle),
|
||||
endCap: Cap.roundCap,
|
||||
startCap: Cap.roundCap,
|
||||
geodesic: true,
|
||||
),
|
||||
);
|
||||
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) {
|
||||
// Split the address into parts
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,461 +37,297 @@ class LoginPage extends StatelessWidget {
|
||||
isleading: false,
|
||||
body: [
|
||||
if (box.read(BoxName.agreeTerms) != 'agreed')
|
||||
agreedPage()
|
||||
_buildAgreementPage(controller)
|
||||
else if (box.read(BoxName.countryCode) == null)
|
||||
CountryPicker()
|
||||
_buildCountryPicker()
|
||||
else if (box.read(BoxName.locationPermission) != 'true')
|
||||
locationPermissionDialog()
|
||||
_buildLocationPermissionDialog(controller)
|
||||
else
|
||||
SingleChildScrollView(
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
_buildLoginContent(controller, authController),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Padding agreedPage() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: SingleChildScrollView(
|
||||
Widget _buildLoginContent(
|
||||
LoginController controller, AuthController authController) {
|
||||
return SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/notepad.png',
|
||||
width: Get.width * .2,
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * .7,
|
||||
child: Text(
|
||||
'Accept Ride\'s Terms & Review Privacy Notice'.tr,
|
||||
style: AppStyle.headTitle2,
|
||||
),
|
||||
),
|
||||
],
|
||||
Image.asset(
|
||||
'assets/images/logo.gif',
|
||||
height: Get.width * 0.4,
|
||||
width: Get.width * 0.4,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
text:
|
||||
'By selecting "I Agree" below, I have reviewed and agree to the Terms of Use and acknowledge the '
|
||||
.tr,
|
||||
style: AppStyle.title,
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: 'Privacy Notice'.tr,
|
||||
style: const TextStyle(
|
||||
decoration: TextDecoration.underline,
|
||||
color: AppColor.blueColor),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
Get.defaultDialog(
|
||||
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(height: 32),
|
||||
if (Platform.isIOS && controller.isTest == 0)
|
||||
_buildEmailPasswordForm(controller)
|
||||
else
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24.0),
|
||||
child: Text(
|
||||
'Sign in for a seamless experience'.tr,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () async => await GoogleSignInHelper().signInFromLogin(),
|
||||
child: _buildSocialButton(
|
||||
icon: FontAwesome.google,
|
||||
text: 'Sign In with Google'.tr,
|
||||
color: AppColor.redColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 100,
|
||||
),
|
||||
GetBuilder<LoginController>(
|
||||
builder: (controller) => Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Checkbox.adaptive(
|
||||
autofocus: true,
|
||||
tristate: true,
|
||||
splashRadius: 25,
|
||||
activeColor: AppColor.primaryColor,
|
||||
value: controller.isAgreeTerms,
|
||||
onChanged: (value) => controller.changeAgreeTerm(),
|
||||
),
|
||||
Text(
|
||||
'I Agree'.tr,
|
||||
style: controller.isAgreeTerms
|
||||
? AppStyle.title
|
||||
: AppStyle.title
|
||||
.copyWith(color: AppColor.accentColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
MyElevatedButton(
|
||||
title: 'Submit'.tr,
|
||||
onPressed: () => controller.saveAgreementTerms()),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
if (!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(),
|
||||
);
|
||||
} else {
|
||||
Get.snackbar('User not found'.tr, '',
|
||||
backgroundColor: AppColor.redColor);
|
||||
}
|
||||
},
|
||||
child: _buildSocialButton(
|
||||
icon: Icons.apple,
|
||||
text: 'Sign in with Apple'.tr,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
)
|
||||
const SizedBox(height: 40),
|
||||
GestureDetector(
|
||||
onTap: () => Get.to(() => ContactUsPage()),
|
||||
child: Text(
|
||||
'Need assistance? Contact us'.tr,
|
||||
style: AppStyle.subtitle.copyWith(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
locationPermissionDialog() {
|
||||
return GetBuilder<LoginController>(builder: (controller) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Container(
|
||||
height: Get.height * .4,
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Center(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Text(
|
||||
'We use your precise location to find the nearest available driver and provide accurate pickup and dropoff information. You can manage this in Settings.'
|
||||
.tr,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// Optionally, navigate to app settings for manual permission control
|
||||
openAppSettings();
|
||||
},
|
||||
child: Text(
|
||||
"Open Settings".tr,
|
||||
style: const TextStyle(color: AppColor.blueColor),
|
||||
Widget _buildSocialButton({
|
||||
required IconData icon,
|
||||
required String text,
|
||||
required Color color,
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon, color: Colors.white),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
text,
|
||||
style: const TextStyle(
|
||||
color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEmailPasswordForm(LoginController controller) {
|
||||
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,
|
||||
// 'You can just manage your account!'.tr, () {
|
||||
// Get.back();
|
||||
// Get.to(() {
|
||||
// PassengerProfilePage();
|
||||
// });
|
||||
// });
|
||||
// } else {
|
||||
await controller.getLocationPermission();
|
||||
// }
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAgreementPage(LoginController controller) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ListTile(
|
||||
leading: Image.asset('assets/images/notepad.png', width: 40),
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class MapPagePassenger extends StatelessWidget {
|
||||
Get.put(MapPassengerController());
|
||||
Get.put(MyMenuController());
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
checkForUpdate(context);
|
||||
// checkForUpdate(context);
|
||||
});
|
||||
|
||||
return Scaffold(
|
||||
@@ -53,7 +53,8 @@ class MapPagePassenger extends StatelessWidget {
|
||||
// const HeaderDestination(),
|
||||
const BurcMoney(),
|
||||
const PromoCode(),
|
||||
const ApplyOrderWidget(), const MapMenuWidget(),
|
||||
const ApplyOrderWidget(),
|
||||
const MapMenuWidget(),
|
||||
// hexagonClipper(),
|
||||
const CancelRidePageShow(),
|
||||
CashConfirmPageShown(),
|
||||
|
||||
@@ -18,472 +18,34 @@ class ApplyOrderWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Color _parseColor(String colorHex) {
|
||||
if (colorHex.isEmpty) {
|
||||
return Colors.grey; // Fallback for empty color
|
||||
}
|
||||
|
||||
// Ensure the string starts with '0xff' for ARGB format
|
||||
if (colorHex.isEmpty) return Colors.grey;
|
||||
String processedHex = colorHex.replaceFirst('#', '0xff').trim();
|
||||
|
||||
if (!processedHex.startsWith('0xff')) {
|
||||
processedHex = '0xff$processedHex'; // Add '0xff' if missing
|
||||
}
|
||||
|
||||
return Color(int.parse(processedHex));
|
||||
return Color(int.parse(processedHex.startsWith('0xff')
|
||||
? processedHex
|
||||
: '0xff$processedHex'));
|
||||
}
|
||||
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
if (controller.statusRide == 'Apply' &&
|
||||
controller.isSearchingWindow == false) {
|
||||
// double _height = Get.height * .2;
|
||||
if (controller.statusRide == 'Apply' && !controller.isSearchingWindow) {
|
||||
return Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
height: Get.height * .36,
|
||||
child: ListView(
|
||||
decoration: BoxDecoration(
|
||||
// More modern BoxDecoration
|
||||
color: Theme.of(context).cardColor,
|
||||
borderRadius:
|
||||
const BorderRadius.vertical(top: Radius.circular(20)),
|
||||
boxShadow: [BoxShadow(blurRadius: 10, color: Colors.black12)],
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
if (box.read(BoxName.carType) == 'Speed' ||
|
||||
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,
|
||||
),
|
||||
],
|
||||
)
|
||||
_buildPriceInfo(context, controller),
|
||||
const SizedBox(height: 16),
|
||||
_buildDriverInfoCard(context, controller, _parseColor),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -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 {
|
||||
const DriverArrivePassengerAndWaitMinute({
|
||||
super.key,
|
||||
});
|
||||
const DriverArrivePassengerAndWaitMinute({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
return Stack(
|
||||
return Column(
|
||||
children: [
|
||||
LinearProgressIndicator(
|
||||
backgroundColor: AppColor.accentColor,
|
||||
color: controller.remainingTimeDriverWaitPassenger5Minute < 60
|
||||
? AppColor.redColor
|
||||
: AppColor.greenColor,
|
||||
minHeight: 25,
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
value:
|
||||
controller.progressTimerDriverWaitPassenger5Minute.toDouble(),
|
||||
child: LinearProgressIndicator(
|
||||
backgroundColor: AppColor.accentColor.withOpacity(0.3),
|
||||
color: controller.remainingTimeDriverWaitPassenger5Minute < 60
|
||||
? AppColor.redColor
|
||||
: AppColor.greenColor,
|
||||
minHeight: 20,
|
||||
value:
|
||||
controller.progressTimerDriverWaitPassenger5Minute.toDouble(),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'The driver waiting you in picked location .'.tr,
|
||||
style: AppStyle.subtitle,
|
||||
textAlign: TextAlign.center,
|
||||
const SizedBox(height: 4),
|
||||
Center(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${'Driver is waiting at pickup.'.tr} ',
|
||||
style: AppStyle.subtitle),
|
||||
TextSpan(
|
||||
text: controller
|
||||
.stringRemainingTimeDriverWaitPassenger5Minute,
|
||||
style: AppStyle.title),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Text(
|
||||
controller.stringRemainingTimeDriverWaitPassenger5Minute,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
)
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
@@ -539,77 +352,50 @@ class DriverArrivePassengerAndWaitMinute extends StatelessWidget {
|
||||
}
|
||||
|
||||
class TimeDriverToPassenger extends StatelessWidget {
|
||||
const TimeDriverToPassenger({
|
||||
super.key,
|
||||
});
|
||||
const TimeDriverToPassenger({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
return controller.isDriverInPassengerWay == false ||
|
||||
controller.timeToPassengerFromDriverAfterApplied > 0
|
||||
? Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1),
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
width: Get.width * .7,
|
||||
height: 15,
|
||||
// color: AppColor.yellowColor,
|
||||
),
|
||||
Stack(
|
||||
? Column(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
child: LinearProgressIndicator(
|
||||
backgroundColor: AppColor.accentColor.withOpacity(0.3),
|
||||
color: controller
|
||||
.remainingTimeToPassengerFromDriverAfterApplied <
|
||||
60
|
||||
? AppColor.redColor
|
||||
: AppColor.greenColor,
|
||||
minHeight: 20,
|
||||
value: controller
|
||||
.progressTimerToPassengerFromDriverAfterApplied
|
||||
.toDouble()
|
||||
.clamp(0.0, 1.0),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Center(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
LinearProgressIndicator(
|
||||
backgroundColor: AppColor.accentColor,
|
||||
color: controller
|
||||
.remainingTimeToPassengerFromDriverAfterApplied <
|
||||
60
|
||||
? AppColor.redColor
|
||||
: AppColor.greenColor,
|
||||
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
|
||||
}
|
||||
}(),
|
||||
TextSpan(
|
||||
text: '${'Driver is on the way'.tr} ',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
TextSpan(
|
||||
text: controller.stringRemainingTimeToPassenger,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
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();
|
||||
});
|
||||
|
||||
@@ -102,20 +102,13 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
mapPassengerController.isBottomSheetShown &&
|
||||
mapPassengerController.rideConfirm == false
|
||||
? Positioned(
|
||||
bottom: 0,
|
||||
bottom: 15,
|
||||
left: 8,
|
||||
right: 8,
|
||||
child: Container(
|
||||
height: Get.height * .3,
|
||||
height: Get.height * .32,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
AppColor.secondaryColor,
|
||||
AppColor.secondaryColor,
|
||||
],
|
||||
),
|
||||
color: AppColor.secondaryColor,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
@@ -130,6 +123,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
@@ -139,7 +133,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(1.0),
|
||||
child: SizedBox(
|
||||
height: Get.height * .22, // Adjust height as needed
|
||||
child: ListView.separated(
|
||||
@@ -478,73 +472,101 @@ class PromoCode extends StatelessWidget {
|
||||
Get.put(BlinkingController());
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (mapPassengerController) {
|
||||
return mapPassengerController.data.isNotEmpty &&
|
||||
mapPassengerController.isBottomSheetShown &&
|
||||
mapPassengerController.rideConfirm == false &&
|
||||
mapPassengerController.promoTaken == false
|
||||
? GetBuilder<BlinkingController>(builder: (blinkingController) {
|
||||
blinkingController.startBlinking();
|
||||
return Positioned(
|
||||
right: 5,
|
||||
bottom: Get.height * 0.36,
|
||||
child: Obx(() {
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
width: 70, // Circle size
|
||||
height: 70,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: blinkingController.isLightOn.value
|
||||
? Colors.yellow
|
||||
: Colors.grey, // Light on/off effect
|
||||
border: Border.all(
|
||||
color: blinkingController
|
||||
.borderColor.value, // Animated border color
|
||||
width: 3,
|
||||
),
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
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,
|
||||
),
|
||||
final showPromoButton = mapPassengerController.data.isNotEmpty &&
|
||||
mapPassengerController.isBottomSheetShown &&
|
||||
!mapPassengerController.rideConfirm &&
|
||||
!mapPassengerController.promoTaken;
|
||||
|
||||
return showPromoButton
|
||||
? GetBuilder<BlinkingController>(
|
||||
builder: (blinkingController) {
|
||||
blinkingController.startBlinking();
|
||||
return Positioned(
|
||||
right: 16, // Adjusted from 5 for better spacing
|
||||
bottom: Get.height * 0.36,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Get.defaultDialog(
|
||||
title: 'Apply Promo Code'.tr, // More engaging title
|
||||
content: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Form(
|
||||
key: mapPassengerController.promoFormKey,
|
||||
child: MyTextForm(
|
||||
controller: mapPassengerController.promo,
|
||||
label: 'Promo Code'.tr, // Shortened label
|
||||
hint: 'Enter your promo code'
|
||||
.tr, // More friendly hint
|
||||
type: TextInputType.name,
|
||||
// style: AppStyle.normalTextBlack, // Apply consistent style
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Ok'.tr,
|
||||
onPressed: () {
|
||||
if (mapPassengerController
|
||||
.promoFormKey.currentState!
|
||||
.validate()) {
|
||||
mapPassengerController
|
||||
.applyPromoCodeToPassenger(context);
|
||||
Get.back();
|
||||
}
|
||||
}));
|
||||
},
|
||||
icon: const Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.local_offer, size: 24), // Promo icon
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
"Promo",
|
||||
style: TextStyle(
|
||||
fontSize: 12, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Apply'.tr, // Shortened button title
|
||||
onPressed: () {
|
||||
if (mapPassengerController
|
||||
.promoFormKey.currentState!
|
||||
.validate()) {
|
||||
mapPassengerController
|
||||
.applyPromoCodeToPassenger(context);
|
||||
Get.back();
|
||||
}
|
||||
},
|
||||
),
|
||||
cancel: OutlinedButton(
|
||||
onPressed: () => Get.back(),
|
||||
child: Text('Cancel'.tr),
|
||||
),
|
||||
);
|
||||
},
|
||||
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();
|
||||
},
|
||||
);
|
||||
@@ -559,51 +581,89 @@ class BurcMoney extends StatelessWidget {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (mapPassengerController) {
|
||||
final passengerWallet =
|
||||
double.tryParse(box.read(BoxName.passengerWalletTotal)) ??
|
||||
0.0; // Handle potential parsing errors
|
||||
double.tryParse(box.read(BoxName.passengerWalletTotal)) ?? 0.0;
|
||||
|
||||
return mapPassengerController.data.isNotEmpty &&
|
||||
mapPassengerController.isBottomSheetShown &&
|
||||
!mapPassengerController.rideConfirm
|
||||
!mapPassengerController.rideConfirm &&
|
||||
passengerWallet < 0.0 // Simplified condition
|
||||
? Positioned(
|
||||
bottom: Get.height * .41,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (passengerWallet < 0.0) // Use if statement for clarity
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration.copyWith(
|
||||
color: AppColor.redColor.withOpacity(.3),
|
||||
),
|
||||
height: 50,
|
||||
width: Get.width,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
left: 16, // Add left margin for better positioning
|
||||
right: 16, // Add right margin
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.redColor
|
||||
.withOpacity(0.8), // More prominent color
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () 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),
|
||||
icon: const Icon(Icons.headphones)),
|
||||
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,
|
||||
TextSpan(
|
||||
text: '${'Negative Balance:'.tr} ',
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
'${'You have a balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${box.read(BoxName.countryCode) == 'Egypt' ? 'LE'.tr : 'JOD'.tr} ${'due to a previous trip.'.tr}',
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTap: () async =>
|
||||
await Get.find<TextToSpeechController>().speakText(
|
||||
'${'you have a negative balance of'.tr}${passengerWallet.toStringAsFixed(2)}${' in your'.tr} ${AppInformation.appName}${' wallet due to a previous trip.'.tr}'),
|
||||
child: const Icon(
|
||||
Icons.headphones,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(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();
|
||||
|
||||
@@ -12,7 +12,6 @@ import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../../main.dart';
|
||||
|
||||
GetBuilder<MapPassengerController> formSearchPlacesDestenation() {
|
||||
// DbSql sql = DbSql.instance;
|
||||
if (box.read(BoxName.addWork).toString() == '' ||
|
||||
box.read(BoxName.addHome).toString() == '') {
|
||||
box.write(BoxName.addWork, 'addWork');
|
||||
@@ -20,349 +19,271 @@ GetBuilder<MapPassengerController> formSearchPlacesDestenation() {
|
||||
}
|
||||
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => Column(
|
||||
builder: (controller) => Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: Get.width * .9,
|
||||
height: 40,
|
||||
decoration:
|
||||
const BoxDecoration(color: AppColor.secondaryColor),
|
||||
child: TextField(
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.only(),
|
||||
gapPadding: 4,
|
||||
borderSide: BorderSide(
|
||||
color: AppColor.redColor,
|
||||
width: 2,
|
||||
)),
|
||||
suffixIcon: const Icon(Icons.search),
|
||||
hintText: controller.hintTextDestinationPoint,
|
||||
hintStyle: AppStyle.title,
|
||||
hintMaxLines: 1,
|
||||
prefixIcon: IconButton(
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: controller.placeDestinationController,
|
||||
onChanged: (value) {
|
||||
if (controller.placeDestinationController.text.length > 2) {
|
||||
controller.getPlaces();
|
||||
controller.changeHeightPlaces();
|
||||
} else if (controller
|
||||
.placeDestinationController.text.isEmpty) {
|
||||
controller.clearPlacesDestination();
|
||||
controller.changeHeightPlaces();
|
||||
}
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: controller.hintTextDestinationPoint,
|
||||
hintStyle:
|
||||
AppStyle.subtitle.copyWith(color: Colors.grey[600]),
|
||||
prefixIcon:
|
||||
const Icon(Icons.search, color: AppColor.primaryColor),
|
||||
suffixIcon: controller
|
||||
.placeDestinationController.text.isNotEmpty
|
||||
? IconButton(
|
||||
icon: Icon(Icons.clear, color: Colors.grey[400]),
|
||||
onPressed: () {
|
||||
controller.placeDestinationController.clear();
|
||||
controller.clearPlacesDestination();
|
||||
controller.changeHeightPlaces();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.clear,
|
||||
color: Colors.red[300],
|
||||
),
|
||||
),
|
||||
),
|
||||
controller: controller.placeDestinationController,
|
||||
onChanged: (value) {
|
||||
if (controller
|
||||
.placeDestinationController.text.length >
|
||||
5) {
|
||||
controller.getPlaces();
|
||||
controller.changeHeightPlaces();
|
||||
}
|
||||
},
|
||||
// onEditingComplete: () => controller.changeHeight(),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0, vertical: 10.0),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderSide: BorderSide(color: AppColor.primaryColor),
|
||||
),
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration1
|
||||
.copyWith(color: AppColor.blueColor),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.changePickerShown();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 4),
|
||||
child: Text(
|
||||
controller.isAnotherOreder
|
||||
? 'Pick from map destination'.tr
|
||||
: 'Pick from map'.tr,
|
||||
style: AppStyle.title
|
||||
.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} '),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
), //
|
||||
filled: true,
|
||||
fillColor: Colors.grey[50],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8.0),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.changePickerShown();
|
||||
},
|
||||
icon: Icon(Icons.location_on_outlined,
|
||||
color: AppColor.accentColor, size: 30),
|
||||
tooltip: controller.isAnotherOreder
|
||||
? 'Pick destination on map'
|
||||
: 'Pick on map',
|
||||
),
|
||||
// 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();
|
||||
}
|
||||
|
||||
@@ -9,181 +9,130 @@ import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../../main.dart';
|
||||
|
||||
GetBuilder<MapPassengerController> formSearchPlacesStart() {
|
||||
// DbSql sql = DbSql.instance;
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => Column(
|
||||
builder: (controller) => Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
width: Get.width * .75,
|
||||
height: 40,
|
||||
decoration:
|
||||
const BoxDecoration(color: AppColor.secondaryColor),
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.only(),
|
||||
gapPadding: 4,
|
||||
borderSide: BorderSide(
|
||||
color: AppColor.redColor,
|
||||
width: 2,
|
||||
)),
|
||||
suffixIcon: const Icon(Icons.search),
|
||||
hintText: controller.hintTextStartPoint,
|
||||
hintStyle: AppStyle.title,
|
||||
hintMaxLines: 1,
|
||||
prefixIcon: IconButton(
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: controller.placeStartController,
|
||||
onChanged: (value) {
|
||||
if (controller.placeStartController.text.length > 2) {
|
||||
// Reduced character limit
|
||||
controller.getPlacesStart();
|
||||
controller.changeHeightStartPlaces();
|
||||
} else if (controller.placeStartController.text.isEmpty) {
|
||||
controller.clearPlacesStart();
|
||||
controller.changeHeightPlaces(); // Collapse if empty
|
||||
}
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: controller.hintTextStartPoint,
|
||||
hintStyle:
|
||||
AppStyle.subtitle.copyWith(color: Colors.grey[600]),
|
||||
prefixIcon:
|
||||
const Icon(Icons.search, color: AppColor.primaryColor),
|
||||
suffixIcon: controller.placeStartController.text.isNotEmpty
|
||||
? IconButton(
|
||||
icon: Icon(Icons.clear, color: Colors.grey[400]),
|
||||
onPressed: () {
|
||||
controller.placeStartController.clear();
|
||||
controller.clearPlacesStart();
|
||||
controller
|
||||
.changeHeightPlaces(); // Collapse on clear
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.clear,
|
||||
color: Colors.red[300],
|
||||
),
|
||||
),
|
||||
),
|
||||
controller: controller.placeStartController,
|
||||
onChanged: (value) {
|
||||
if (controller.placeStartController.text.length > 5) {
|
||||
controller.getPlacesStart();
|
||||
controller.changeHeightStartPlaces();
|
||||
}
|
||||
},
|
||||
// onEditingComplete: () => controller.changeHeight(),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0, vertical: 10.0),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
controller.startLocationFromMap = true;
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.changePickerShown();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.map_outlined,
|
||||
color: AppColor.yellowColor,
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderSide: BorderSide(color: AppColor.primaryColor),
|
||||
),
|
||||
],
|
||||
filled: true,
|
||||
fillColor: Colors.grey[50],
|
||||
),
|
||||
),
|
||||
),
|
||||
// controller.placesDestination.isEmpty
|
||||
// ? InkWell(
|
||||
// onTap: () {
|
||||
// controller.startLocationFromMap = true;
|
||||
// controller.changeMainBottomMenuMap();
|
||||
// controller.changePickerShown();
|
||||
// },
|
||||
// child: Text(
|
||||
// 'Choose from Map Start Point'.tr,
|
||||
// style:
|
||||
// AppStyle.title.copyWith(color: AppColor.blueColor),
|
||||
// ),
|
||||
// )
|
||||
// : const SizedBox(),
|
||||
Container(
|
||||
height:
|
||||
controller.placesStart.isNotEmpty ? controller.height : 0,
|
||||
color: AppColor.secondaryColor,
|
||||
child: ListView.builder(
|
||||
itemCount: controller.placesStart.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
var res = controller.placesStart[index];
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
controller.changeHeightPlaces();
|
||||
// if (controller.currentLocationToFormPlaces == true) {
|
||||
// controller.newStartPointLocation =
|
||||
// controller.myLocation;
|
||||
// } else {
|
||||
// controller.myLocation =
|
||||
// controller.newStartPointLocation;
|
||||
// }
|
||||
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();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
Image.network(
|
||||
res['icon'],
|
||||
width: 20,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await sql.insertMapLocation({
|
||||
'latitude': res['geometry']
|
||||
['location']['lat'],
|
||||
'longitude': res['geometry']
|
||||
['location']['lng'],
|
||||
'name': res['name'].toString(),
|
||||
'rate': res['rating'].toString(),
|
||||
}, TableName.placesFavorite);
|
||||
Toast.show(
|
||||
context,
|
||||
'${res['name']} ${'Saved Sucssefully'.tr}',
|
||||
AppColor.primaryColor);
|
||||
},
|
||||
icon: const Icon(Icons.favorite_border),
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Text(
|
||||
res['name'].toString(),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
res['vicinity'].toString(),
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Text(
|
||||
'rate',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
res['rating'].toString(),
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(
|
||||
thickness: 1,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
const SizedBox(width: 8.0),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
controller.startLocationFromMap = true;
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.changePickerShown();
|
||||
},
|
||||
icon: Icon(Icons.location_on_outlined,
|
||||
color: AppColor.accentColor, size: 30),
|
||||
tooltip: 'Choose on Map',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
height: controller.placesStart.isNotEmpty ? controller.height : 0,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: controller.placesStart.length,
|
||||
separatorBuilder: (context, index) =>
|
||||
const Divider(height: 1, color: Colors.grey),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
var res = controller.placesStart[index];
|
||||
return ListTile(
|
||||
leading: Image.network(res['icon'], width: 30, height: 30),
|
||||
title: Text(res['name'].toString(),
|
||||
style: AppStyle.subtitle
|
||||
.copyWith(fontWeight: FontWeight.w500)),
|
||||
subtitle: Text(res['vicinity'].toString(),
|
||||
style: TextStyle(color: Colors.grey[600], fontSize: 12)),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.favorite_border, color: Colors.grey),
|
||||
onPressed: () async {
|
||||
await sql.insertMapLocation({
|
||||
'latitude': res['geometry']['location']['lat'],
|
||||
'longitude': res['geometry']['location']['lng'],
|
||||
'name': res['name'].toString(),
|
||||
'rate': res['rating'].toString(),
|
||||
}, TableName.placesFavorite);
|
||||
Toast.show(
|
||||
context,
|
||||
'${res['name']} ${'Saved Successfully'.tr}',
|
||||
AppColor.primaryColor);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
onTap: () async {
|
||||
controller.changeHeightPlaces();
|
||||
await sql.insertMapLocation({
|
||||
'latitude': res['geometry']['location']['lat'],
|
||||
'longitude': res['geometry']['location']['lng'],
|
||||
'name': res['name'].toString(),
|
||||
'rate': res['rating'].toString(),
|
||||
'createdAt': DateTime.now().toIso8601String(),
|
||||
}, TableName.recentLocations);
|
||||
|
||||
controller.convertHintTextStartNewPlaces(index);
|
||||
controller.currentLocationString = res['name'];
|
||||
controller.placesStart = [];
|
||||
controller.placeStartController.clear();
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,162 +15,182 @@ import 'package:url_launcher/url_launcher.dart';
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../notification/notification_page.dart';
|
||||
import '../../widgets/icon_widget_menu.dart';
|
||||
import '../setting_page.dart';
|
||||
import '../profile/passenger_profile_page.dart';
|
||||
|
||||
class MapMenuWidget extends StatelessWidget {
|
||||
const MapMenuWidget({
|
||||
super.key,
|
||||
});
|
||||
const MapMenuWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<MapPassengerController>(
|
||||
builder: (controller) => Stack(children: [
|
||||
Positioned(
|
||||
right: 60,
|
||||
left: 60,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 20),
|
||||
child: Opacity(
|
||||
alwaysIncludeSemantics: false,
|
||||
opacity: 1, // Adjust the opacity value as needed
|
||||
child: AnimatedContainer(
|
||||
width: Get.width * .6,
|
||||
decoration: AppStyle.boxDecoration
|
||||
.copyWith(color: AppColor.blueColor),
|
||||
transform: Matrix4.translationValues(
|
||||
controller.heightMenu * .1, 1, 1),
|
||||
curve: Curves.easeOutCubic,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
height: controller.heightMenu,
|
||||
child: controller.heightMenuBool
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
IconWidgetMenu(
|
||||
onpressed: () {
|
||||
builder: (controller) => Stack(
|
||||
children: [
|
||||
// Top Menu Bar
|
||||
Positioned(
|
||||
top: 10, // Adjust as needed
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
// GestureDetector(
|
||||
// onTap: controller.getDrawerMenu,
|
||||
// child: Container(
|
||||
// padding: const EdgeInsets.all(10),
|
||||
// decoration: AppStyle.boxDecoration
|
||||
// .copyWith(color: AppColor.blueColor),
|
||||
// child: const Icon(Icons.menu, color: Colors.white),
|
||||
// ),
|
||||
// ),
|
||||
if (controller.heightMenuBool)
|
||||
Expanded(
|
||||
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(
|
||||
() => const NotificationPage(),
|
||||
transition: Transition.circularReveal,
|
||||
);
|
||||
},
|
||||
title: 'Notifications'.tr,
|
||||
icon: Icons.notifications),
|
||||
IconWidgetMenu(
|
||||
onpressed: () {
|
||||
Get.to(
|
||||
() => PassengerProfilePage(),
|
||||
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: const Icon(Icons.notifications,
|
||||
color: Colors.white),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Get.to(() => PassengerProfilePage(),
|
||||
transition: Transition.zoom);
|
||||
},
|
||||
icon: Icons.settings),
|
||||
],
|
||||
)
|
||||
: const SizedBox(), // Choose the desired overlay color
|
||||
)),
|
||||
icon: const Icon(Icons.person,
|
||||
color: Colors.white),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Get.to(() => const SettingPage(),
|
||||
transition: Transition.downToUp,
|
||||
curve: Curves.easeInOutExpo);
|
||||
},
|
||||
icon: const Icon(Icons.settings,
|
||||
color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 5,
|
||||
top: 80,
|
||||
// Side Drawer (Main Menu)
|
||||
Positioned(
|
||||
top: 80, // Adjust as needed
|
||||
left: 10,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
width: controller.widthMenu,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
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;
|
||||
}
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 250), // Add max width constraint
|
||||
|
||||
if (await canLaunchUrl(Uri.parse(driverAppUrl))) {
|
||||
await launchUrl(Uri.parse(driverAppUrl));
|
||||
} else {
|
||||
throw 'Could not launch app store URL';
|
||||
}
|
||||
},
|
||||
title: 'Driver'.tr,
|
||||
icon: WeatherIcons.wi_moon_14,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
child: Material(
|
||||
color: Colors.white, // Background color of the drawer
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
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,
|
||||
),
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: Future.delayed(const Duration(milliseconds: 400)),
|
||||
builder: (context, snapshot) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: SizedBox(
|
||||
height: Get.height * .1,
|
||||
width: double.maxFinite,
|
||||
// decoration: AppStyle.boxDecoration,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(icon),
|
||||
Text(
|
||||
title.tr,
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 1),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, size: 24),
|
||||
const SizedBox(width: 16),
|
||||
Text(
|
||||
title.tr,
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
);
|
||||
});
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,296 +15,252 @@ import '../../../controller/functions/toast.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
|
||||
class RideBeginPassenger extends StatelessWidget {
|
||||
const RideBeginPassenger({
|
||||
super.key,
|
||||
});
|
||||
const RideBeginPassenger({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ProfileController profileController = Get.put(ProfileController());
|
||||
AudioRecorderController audioController =
|
||||
Get.put(AudioRecorderController());
|
||||
// Get.put(MapPassengerController());
|
||||
|
||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||
if (controller.statusRide == 'Begin' || !controller.statusRideFromStart) {
|
||||
if (controller.statusRide == 'Begin') {
|
||||
return Positioned(
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 10,
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
height: controller.statusRide == 'Begin' ? Get.height * .33 : 0,
|
||||
// width: 100,
|
||||
child: Card(
|
||||
// Wrapped in a Card
|
||||
elevation: 5,
|
||||
shape:
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
mainAxisSize: MainAxisSize.min, // Use minimum space
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 30,
|
||||
backgroundImage: NetworkImage(
|
||||
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg'),
|
||||
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg',
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: Text(
|
||||
controller.driverName,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(controller.driverName, style: AppStyle.title),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
controller.make,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
controller.model,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(controller.make, style: AppStyle.subtitle),
|
||||
const SizedBox(width: 5),
|
||||
Text(controller.model,
|
||||
style: AppStyle.subtitle),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3),
|
||||
child: Text(
|
||||
'${box.read(BoxName.carType)}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
controller.licensePlate,
|
||||
style: AppStyle.title.copyWith(fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
'${controller.driverRate} 📈',
|
||||
style: AppStyle.title,
|
||||
'${box.read(BoxName.carType)}',
|
||||
style: AppStyle.title.copyWith(fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
'${controller.driverRate} ⭐️',
|
||||
style: AppStyle.title
|
||||
.copyWith(color: AppColor.greenColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
// SizedBox(
|
||||
// height: 5,
|
||||
// ),
|
||||
const SizedBox(height: 15),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
controller.getDialog('Arrival time'.tr,
|
||||
'arrival time to reach your point'.tr, () {});
|
||||
},
|
||||
child: Container(
|
||||
width: Get.width * .15,
|
||||
decoration: AppStyle.boxDecoration,
|
||||
SizedBox(
|
||||
width: Get.width * 0.18,
|
||||
child: InkWell(
|
||||
onTap: () => controller.getDialog(
|
||||
'Arrival time'.tr,
|
||||
'arrival time to reach your point'.tr,
|
||||
() {},
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'⏱️',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
controller.arrivalTime,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const Icon(Icons.timer_outlined, size: 28),
|
||||
Text(controller.arrivalTime,
|
||||
style: AppStyle.title),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
controller.getDialog(
|
||||
'Price of trip'.tr,
|
||||
'For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance'
|
||||
.tr, () {
|
||||
Get.back();
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
width: Get.width * .15,
|
||||
decoration: AppStyle.boxDecoration,
|
||||
SizedBox(
|
||||
width: Get.width * 0.18,
|
||||
child: InkWell(
|
||||
onTap: () => controller.getDialog(
|
||||
'Price of trip'.tr,
|
||||
'For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance'
|
||||
.tr,
|
||||
() => Get.back(),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
const Icon(Icons.monetization_on, size: 28),
|
||||
Text(
|
||||
'💵 ',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
controller.totalPassenger.toStringAsFixed(2),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
'${controller.totalPassenger.toStringAsFixed(2)}',
|
||||
style: AppStyle.title),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: Get.width * .15,
|
||||
decoration: AppStyle.boxDecoration,
|
||||
SizedBox(
|
||||
width: Get.width * 0.18,
|
||||
child: IconButton(
|
||||
onPressed: () => Get.to(
|
||||
() => ComplaintPage(),
|
||||
transition: Transition.downToUp,
|
||||
),
|
||||
icon: const Icon(
|
||||
Icons.note_add,
|
||||
color: AppColor.redColor,
|
||||
),
|
||||
tooltip: ' Add Note', // Optional tooltip for clarity
|
||||
onPressed: () => Get.to(() => ComplaintPage(),
|
||||
transition: Transition.downToUp),
|
||||
icon: const Icon(Icons.note_add,
|
||||
color: AppColor.redColor),
|
||||
tooltip: 'Add Note',
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: Get.width * .15,
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: audioController.isRecording == false
|
||||
? IconButton(
|
||||
onPressed: () async {
|
||||
await audioController.startRecording();
|
||||
Toast.show(context, 'Start Record'.tr,
|
||||
AppColor.greenColor);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.play_circle_fill_outlined,
|
||||
color: AppColor.greenColor,
|
||||
),
|
||||
tooltip:
|
||||
' Add Note', // Optional tooltip for clarity
|
||||
)
|
||||
: IconButton(
|
||||
onPressed: () async {
|
||||
await audioController.stopRecording();
|
||||
Toast.show(context, 'Record saved'.tr,
|
||||
AppColor.greenColor);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.stop_circle,
|
||||
color: AppColor.greenColor,
|
||||
),
|
||||
tooltip:
|
||||
' Add Note', // Optional tooltip for clarity
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * 0.18,
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
if (audioController.isRecording == false) {
|
||||
await audioController.startRecording();
|
||||
Toast.show(context, 'Start Record'.tr,
|
||||
AppColor.greenColor);
|
||||
} else {
|
||||
await audioController.stopRecording();
|
||||
Toast.show(context, 'Record saved'.tr,
|
||||
AppColor.greenColor);
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
audioController.isRecording == false
|
||||
? Icons.mic_none
|
||||
: Icons.mic_off,
|
||||
color: AppColor.greenColor,
|
||||
),
|
||||
tooltip: audioController.isRecording == false
|
||||
? 'Start Recording'
|
||||
: 'Stop Recording',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
// StreamCounter(),
|
||||
LinearProgressIndicator(
|
||||
backgroundColor: AppColor.accentColor,
|
||||
backgroundColor: AppColor.accentColor
|
||||
.withOpacity(0.3), // Added background
|
||||
color: controller.remainingTimeTimerRideBegin < 60
|
||||
? AppColor.redColor
|
||||
: AppColor.greenColor,
|
||||
minHeight: 25,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
minHeight: 20,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
value: controller.progressTimerRideBegin.toDouble(),
|
||||
),
|
||||
Center(
|
||||
child: Text(
|
||||
controller.stringRemainingTimeRideBegin,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
)
|
||||
Text(
|
||||
controller.stringRemainingTimeRideBegin,
|
||||
style: AppStyle.title.copyWith(fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
width: Get.width * .15,
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
if (box.read(BoxName.sosPhonePassenger) == null) {
|
||||
{
|
||||
await profileController.updatField(
|
||||
'sosPhone', TextInputType.phone);
|
||||
box.write(BoxName.sosPhonePassenger,
|
||||
profileController.prfoileData['sosPhone']);
|
||||
}
|
||||
} else {
|
||||
makePhoneCall('122');
|
||||
// box.read(BoxName.sosPhonePassenger));
|
||||
}
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.sos_rounded,
|
||||
color: AppColor.redColor,
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * 0.18,
|
||||
child: Column(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
if (box.read(BoxName.sosPhonePassenger) ==
|
||||
null) {
|
||||
await profileController.updatField(
|
||||
'sosPhone', TextInputType.phone);
|
||||
box.write(
|
||||
BoxName.sosPhonePassenger,
|
||||
profileController
|
||||
.prfoileData['sosPhone']);
|
||||
} else {
|
||||
makePhoneCall('122');
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.sos_rounded,
|
||||
color: AppColor.redColor),
|
||||
),
|
||||
Text('SOS', style: AppStyle.title),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
width: Get.width * .15,
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
if (box.read(BoxName.sosPhonePassenger) == null ||
|
||||
box.read(BoxName.sosPhonePassenger) == 'sos') {
|
||||
{
|
||||
await profileController.updatField(
|
||||
'sosPhone', TextInputType.phone);
|
||||
box.write(BoxName.sosPhonePassenger,
|
||||
profileController.prfoileData['sosPhone']);
|
||||
}
|
||||
} else {
|
||||
String phoneNumber = box
|
||||
.read(BoxName.sosPhonePassenger)
|
||||
.toString();
|
||||
// phoneNumber = phoneNumber.replaceAll('0', '');
|
||||
var phone = box.read(BoxName.countryCode) ==
|
||||
'Egypt'
|
||||
? '+2${box.read(BoxName.sosPhonePassenger)}'
|
||||
: '+962${box.read(BoxName.sosPhonePassenger)}';
|
||||
controller.sendWhatsapp(phone);
|
||||
}
|
||||
},
|
||||
icon: const Icon(
|
||||
FontAwesome.whatsapp,
|
||||
color: AppColor.greenColor,
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * 0.18,
|
||||
child: Column(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
if (box.read(BoxName.sosPhonePassenger) ==
|
||||
null ||
|
||||
box.read(BoxName.sosPhonePassenger) ==
|
||||
'sos') {
|
||||
await profileController.updatField(
|
||||
'sosPhone', TextInputType.phone);
|
||||
box.write(
|
||||
BoxName.sosPhonePassenger,
|
||||
profileController
|
||||
.prfoileData['sosPhone']);
|
||||
} else {
|
||||
final phoneNumber = box
|
||||
.read(BoxName.sosPhonePassenger)
|
||||
.toString();
|
||||
final phone =
|
||||
box.read(BoxName.countryCode) == 'Egypt'
|
||||
? '+2$phoneNumber'
|
||||
: '+962$phoneNumber';
|
||||
controller.sendWhatsapp(phone);
|
||||
}
|
||||
},
|
||||
icon: const Icon(FontAwesome.whatsapp,
|
||||
color: AppColor.greenColor),
|
||||
),
|
||||
Text('WhatsApp', style: AppStyle.title),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
width: Get.width * .15,
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
await controller.getTokenForParent();
|
||||
},
|
||||
icon: const Icon(
|
||||
Foundation.video,
|
||||
color: AppColor.blueColor,
|
||||
),
|
||||
SizedBox(
|
||||
width: Get.width * 0.18,
|
||||
child: Column(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await controller.getTokenForParent();
|
||||
},
|
||||
icon: const Icon(Foundation.video,
|
||||
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 {
|
||||
const StreamCounter({Key? key}) : super(key: key);
|
||||
|
||||
|
||||
@@ -21,35 +21,83 @@ class SearchingCaptainWindow extends StatelessWidget {
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
height: Get.height * .25,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
// Use Stack for overlapping widgets
|
||||
children: [
|
||||
// Text elements
|
||||
|
||||
SizedBox(
|
||||
width: Get.width * .7,
|
||||
child: const LinearProgressIndicator(
|
||||
minHeight: 6,
|
||||
backgroundColor: AppColor.yellowColor,
|
||||
color: AppColor.secondaryColor,
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.scaffoldBackgroundColor, // Use theme color
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20),
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, -5),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min, // Fit content
|
||||
children: [
|
||||
Text(
|
||||
mapPassengerController.driversStatusForSearchWindow,
|
||||
style: AppStyle.title,
|
||||
style: AppStyle.title.copyWith(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
// Text(
|
||||
// "We are searching for the nearest driver to you".tr,
|
||||
// style: AppStyle.title,
|
||||
// ),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'please wait till driver accept your order'.tr,
|
||||
style: AppStyle.title,
|
||||
), // Timer logic
|
||||
_buildTimer(mapPassengerController),
|
||||
'${'We are searching for the nearest driver to you'.tr}...', // Add ellipsis
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
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) {
|
||||
// Start timer at 0
|
||||
Timer? timer;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:SEFER/controller/home/map_passenger_controller.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:SEFER/constant/style.dart';
|
||||
@@ -84,16 +83,54 @@ class OrderHistory extends StatelessWidget {
|
||||
),
|
||||
zoom: 12,
|
||||
),
|
||||
// bounds: LatLngBounds(
|
||||
// northeast: LatLng(
|
||||
// double.parse(rides['end_location'].toString().split(',')[0]),
|
||||
// double.parse(rides['end_location'].toString().split(',')[1]),
|
||||
// ),
|
||||
// southwest: LatLng(
|
||||
// double.parse(rides['start_location'].toString().split(',')[0]),
|
||||
// double.parse(rides['start_location'].toString().split(',')[1]),
|
||||
// ),
|
||||
// ),
|
||||
// Dynamically calculate the correct LatLngBounds
|
||||
onMapCreated:
|
||||
(GoogleMapController controller) {
|
||||
final LatLng startLocation = LatLng(
|
||||
double.parse(rides['start_location']
|
||||
.toString()
|
||||
.split(',')[0]),
|
||||
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,
|
||||
polylines: {
|
||||
Polyline(
|
||||
|
||||
@@ -25,7 +25,7 @@ class IconWidgetMenu extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 50,
|
||||
width: 40,
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColor.secondaryColor,
|
||||
shape: BoxShape.circle,
|
||||
|
||||
Reference in New Issue
Block a user