Files
Fondex-Driver/lib/app/cab_screen/cab_home_screen.dart
2025-12-08 23:25:00 +05:00

1282 lines
65 KiB
Dart

import 'package:driver/app/chat_screens/chat_screen.dart';
import 'package:driver/constant/constant.dart';
import 'package:driver/constant/show_toast_dialog.dart';
import 'package:driver/controllers/cab_dashboard_controller.dart';
import 'package:driver/controllers/cab_home_controller.dart';
import 'package:driver/models/user_model.dart';
import 'package:driver/themes/app_them_data.dart';
import 'package:driver/themes/responsive.dart';
import 'package:driver/themes/round_button_fill.dart';
import 'package:driver/themes/theme_controller.dart';
import 'package:driver/utils/fire_store_utils.dart';
import 'package:driver/utils/utils.dart';
import 'package:driver/widget/my_separator.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart' as flutterMap;
import 'package:flutter_svg/flutter_svg.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:timelines_plus/timelines_plus.dart';
class CabHomeScreen extends StatelessWidget {
const CabHomeScreen({super.key});
@override
Widget build(BuildContext context) {
final themeController = Get.find<ThemeController>();
final isDark = themeController.isDark.value;
final dashController = Get.put(CabDashBoardController());
return GetX(
init: CabHomeController(),
builder: (controller) {
return Scaffold(
body: controller.isLoading.value
? Constant.loader()
: Constant.isDriverVerification == true && Constant.userModel!.isDocumentVerify == false
? Obx(() {
final isDark = themeController.isDark.value;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
decoration: ShapeDecoration(
color: isDark ? AppThemeData.grey700 : AppThemeData.grey200,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.all(20),
child: SvgPicture.asset("assets/icons/ic_document.svg"),
),
),
const SizedBox(
height: 12,
),
Text(
"Document Verification in Pending".tr,
style: TextStyle(
color: isDark ? AppThemeData.grey100 : AppThemeData.grey800,
fontSize: 22,
fontFamily: AppThemeData.semiBold),
),
const SizedBox(
height: 5,
),
Text(
"Your documents are being reviewed. We will notify you once the verification is complete.".tr,
textAlign: TextAlign.center,
style: TextStyle(
color: isDark ? AppThemeData.grey50 : AppThemeData.grey500, fontSize: 16, fontFamily: AppThemeData.bold),
),
const SizedBox(
height: 20,
),
RoundedButtonFill(
title: "View Status".tr,
width: 55,
height: 5.5,
color: AppThemeData.primary300,
textColor: AppThemeData.grey50,
onPress: () async {
CabDashBoardController dashBoardController = Get.put(CabDashBoardController());
dashBoardController.drawerIndex.value = 4;
},
),
],
),
);
})
: Column(
children: [
Obx(() {
final user = dashController.userModel.value;
final controllerOwner = controller.ownerModel.value;
final num wallet = user.walletAmount ?? 0.0;
final num ownerWallet = controllerOwner.walletAmount ?? 0.0;
final String? ownerId = user.ownerId;
final num minDeposit = double.parse(Constant.minimumDepositToRideAccept);
// 🧠 Logic:
// If individual driver → check driver's own wallet
// If owner driver → check owner's wallet
if ((ownerId == null || ownerId.isEmpty) && wallet < minDeposit) {
// Individual driver case
return Padding(
padding: const EdgeInsets.only(bottom: 10, left: 10, right: 10),
child: Container(
decoration: BoxDecoration(
color: AppThemeData.danger50,
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"${'You must have at least'.tr} ${Constant.amountShow(amount: Constant.minimumDepositToRideAccept.toString())} ${'in your wallet to receive orders'.tr}",
style: TextStyle(
color: AppThemeData.grey900,
fontSize: 14,
fontFamily: AppThemeData.semiBold,
),
),
),
),
);
} else if (ownerId != null && ownerId.isNotEmpty && ownerWallet < minDeposit) {
// Owner-driver case
return Padding(
padding: const EdgeInsets.only(bottom: 10, left: 10, right: 10),
child: Container(
decoration: BoxDecoration(
color: AppThemeData.danger50,
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Your owner doesn't have the minimum wallet amount to receive orders. Please contact your owner.".tr,
style: TextStyle(
color: AppThemeData.grey900,
fontSize: 14,
fontFamily: AppThemeData.semiBold,
),
),
),
),
);
} else {
return const SizedBox();
}
}),
Expanded(
child: Constant.mapType == "inappmap"
? Stack(
children: [
Constant.selectedMapType == "osm"
? Obx(() {
// Schedule a post-frame callback to ensure the FlutterMap has been built
// before we attempt to move the map to the driver's location.
WidgetsBinding.instance.addPostFrameCallback((_) {
try {
controller.animateToSource();
} catch (_) {}
});
return flutterMap.FlutterMap(
mapController: controller.osmMapController,
options: flutterMap.MapOptions(
// center the OSM map on the controller's current position (updated by controller)
initialCenter: controller.current.value,
initialZoom: 12,
),
children: [
flutterMap.TileLayer(
urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: const ['a', 'b', 'c'],
userAgentPackageName: 'com.emart.app',
),
// Always show osmMarkers (driver/current marker + pickup/dropoff when available)
flutterMap.MarkerLayer(markers: controller.osmMarkers),
if (controller.routePoints.isNotEmpty && controller.currentOrder.value.id != null)
flutterMap.PolylineLayer(
polylines: [
flutterMap.Polyline(
points: controller.routePoints,
strokeWidth: 7.0,
color: AppThemeData.primary300,
),
],
),
],
);
})
: GoogleMap(
onMapCreated: (mapController) {
controller.mapController = mapController;
controller.mapController!.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(Constant.locationDataFinal?.latitude ?? 0.0,
Constant.locationDataFinal?.longitude ?? 0.0),
zoom: 15,
bearing: double.parse('${controller.driverModel.value.rotation ?? '0.0'}')),
),
);
},
myLocationEnabled: true,
myLocationButtonEnabled: true,
mapType: MapType.normal,
zoomControlsEnabled: true,
polylines: Set<Polyline>.of(controller.polyLines.values),
markers: controller.markers.values.toSet(),
initialCameraPosition: CameraPosition(
zoom: 15,
target: LatLng(controller.driverModel.value.location?.latitude ?? 0.0,
controller.driverModel.value.location?.longitude ?? 0.0),
),
),
if (Constant.mapType == "inappmap" && Constant.selectedMapType == "osm")
Positioned(
top: 20,
right: 20,
child: FloatingActionButton(
heroTag: 'center_osm',
onPressed: () {
try {
controller.animateToSource();
} catch (e) {
// ignore
}
},
child: const Icon(Icons.my_location),
),
),
],
)
: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SvgPicture.asset("assets/images/ic_location_map.svg"),
const SizedBox(
height: 10,
),
Text(
"${'Navigate with'.tr} ${Constant.mapType == "google" ? "Google Map" : Constant.mapType == "googleGo" ? "Google Go" : Constant.mapType == "waze" ? "Waze Map" : Constant.mapType == "mapswithme" ? "MapsWithMe Map" : Constant.mapType == "yandexNavi" ? "VandexNavi Map" : Constant.mapType == "yandexMaps" ? "Vandex Map" : ""}",
style: TextStyle(
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
fontSize: 22,
fontFamily: AppThemeData.semiBold),
),
Text(
"${'Easily find your destination with a single tap redirect to'.tr} ${Constant.mapType == "google" ? "Google Map" : Constant.mapType == "googleGo" ? "Google Go" : Constant.mapType == "waze" ? "Waze Map" : Constant.mapType == "mapswithme" ? "MapsWithMe Map" : Constant.mapType == "yandexNavi" ? "VandexNavi Map" : Constant.mapType == "yandexMaps" ? "Vandex Map" : ""} ${'for seamless navigation.'.tr}",
textAlign: TextAlign.center,
style: TextStyle(
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
fontSize: 16,
fontFamily: AppThemeData.regular),
),
const SizedBox(
height: 30,
),
RoundedButtonFill(
title:
"${'Redirect'} ${Constant.mapType == "google" ? "Google Map" : Constant.mapType == "googleGo" ? "Google Go" : Constant.mapType == "waze" ? "Waze Map" : Constant.mapType == "mapswithme" ? "MapsWithMe Map" : Constant.mapType == "yandexNavi" ? "VandexNavi Map" : Constant.mapType == "yandexMaps" ? "Vandex Map" : ""}"
.tr,
width: 55,
height: 5.5,
color: AppThemeData.primary300,
textColor: AppThemeData.grey50,
onPress: () async {
if (controller.currentOrder.value.id != null) {
if (controller.currentOrder.value.status != Constant.driverPending) {
if (controller.currentOrder.value.status == Constant.orderShipped) {
Utils.redirectMap(
name: controller.currentOrder.value.sourceLocationName.toString(),
latitude: controller.currentOrder.value.sourceLocation!.latitude ?? 0.0,
longLatitude: controller.currentOrder.value.sourceLocation!.longitude ?? 0.0);
} else if (controller.currentOrder.value.status == Constant.orderInTransit) {
Utils.redirectMap(
name: controller.currentOrder.value.destinationLocationName.toString(),
latitude: controller.currentOrder.value.destinationLocation!.latitude ?? 0.0,
longLatitude: controller.currentOrder.value.destinationLocation!.longitude ?? 0.0);
}
} else {
Utils.redirectMap(
name: controller.currentOrder.value.sourceLocationName.toString(),
latitude: controller.currentOrder.value.sourceLocation!.latitude ?? 0.0,
longLatitude: controller.currentOrder.value.sourceLocation!.longitude ?? 0.0);
}
}
},
),
],
),
),
),
Obx(
() => controller.currentOrder.value.id != null && controller.currentOrder.value.status == Constant.driverPending
? showDriverBottomSheet(isDark, controller)
: Container(),
),
Obx(
() => controller.shouldShowOrderSheet ? buildOrderActionsCard(isDark, controller) : const SizedBox(),
),
// Obx(
// () => controller.currentOrder.value.id != null && controller.currentOrder.value.status != Constant.driverPending
// ? buildOrderActionsCard(isDark, controller)
// : Container(),
// ),
],
),
);
},
);
}
Padding showDriverBottomSheet(bool isDark, CabHomeController controller) {
double distanceInMeters = Geolocator.distanceBetween(
controller.currentOrder.value.sourceLocation!.latitude ?? 0.0,
controller.currentOrder.value.sourceLocation!.longitude ?? 0.0,
controller.currentOrder.value.destinationLocation!.latitude ?? 0.0,
controller.currentOrder.value.destinationLocation!.longitude ?? 0.0);
double kilometer = distanceInMeters / 1000;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: ShapeDecoration(
color: isDark ? AppThemeData.grey900 : AppThemeData.grey50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Timeline.tileBuilder(
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
theme: TimelineThemeData(
nodePosition: 0,
// indicatorPosition: 0,
),
builder: TimelineTileBuilder.connected(
contentsAlign: ContentsAlign.basic,
indicatorBuilder: (context, index) {
return index == 0
? Container(
decoration: ShapeDecoration(
color: AppThemeData.primary50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.all(10),
child: SvgPicture.asset(
"assets/icons/ic_building.svg",
colorFilter: ColorFilter.mode(AppThemeData.primary300, BlendMode.srcIn),
),
),
)
: Container(
decoration: ShapeDecoration(
color: AppThemeData.carRent50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.all(10),
child: SvgPicture.asset(
"assets/icons/ic_location.svg",
colorFilter: ColorFilter.mode(AppThemeData.primary300, BlendMode.srcIn),
),
),
);
},
connectorBuilder: (context, index, connectorType) {
return const DashedLineConnector(
color: AppThemeData.grey300,
gap: 3,
);
},
contentsBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: index == 0
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
controller.currentOrder.value.author!.fullName(),
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
fontSize: 16,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
),
),
Text(
"${controller.currentOrder.value.sourceLocationName}",
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.medium,
fontSize: 14,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
),
),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Destination".tr,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
fontSize: 16,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
),
),
Text(
controller.currentOrder.value.destinationLocationName.toString(),
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.medium,
fontSize: 14,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
),
),
],
),
);
},
itemCount: 2,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: MySeparator(color: isDark ? AppThemeData.grey700 : AppThemeData.grey200),
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
"Trip Distance".tr,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.regular,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
fontSize: 16,
),
),
),
Text(
"${double.parse(kilometer.toString()).toStringAsFixed(2)} ${Constant.distanceType}",
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
fontSize: 16,
),
),
],
),
const SizedBox(
height: 5,
),
controller.currentOrder.value.tipAmount == null ||
controller.currentOrder.value.tipAmount!.isEmpty ||
double.parse(controller.currentOrder.value.tipAmount.toString()) <= 0
? const SizedBox()
: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
"Tips".tr,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.regular,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
fontSize: 16,
),
),
),
Text(
Constant.amountShow(amount: controller.currentOrder.value.tipAmount),
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
fontSize: 16,
),
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
"Ride Type".tr,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.regular,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
fontSize: 16,
),
),
),
Text(
controller.currentOrder.value.rideType ?? '',
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
fontSize: 16,
),
),
],
),
const SizedBox(
height: 5,
),
const SizedBox(
height: 10,
),
Row(
children: [
Expanded(
child: RoundedButtonFill(
title: "Reject".tr,
width: 24,
height: 5.5,
borderRadius: 10,
color: AppThemeData.danger300,
textColor: AppThemeData.grey50,
onPress: () {
controller.rejectOrder();
},
),
),
const SizedBox(
width: 10,
),
Expanded(
child: RoundedButtonFill(
title: "Accept".tr,
width: 24,
height: 5.5,
borderRadius: 10,
color: AppThemeData.success400,
textColor: AppThemeData.grey50,
onPress: () {
if (controller.driverModel.value.ownerId != null && controller.driverModel.value.ownerId!.isNotEmpty) {
if (controller.ownerModel.value.walletAmount != null &&
controller.ownerModel.value.walletAmount! >= double.parse(Constant.minimumDepositToRideAccept)) {
controller.acceptOrder();
} else {
ShowToastDialog.showToast(
"Your owner has to maintain minimum {amount} wallet balance to accept the cab booking. Please contact your owner"
.trParams({"amount": Constant.ownerMinimumDepositToRideAccept.toString()}).tr);
}
} else {
if (controller.driverModel.value.walletAmount! >= double.parse(Constant.minimumDepositToRideAccept)) {
controller.acceptOrder();
} else {
ShowToastDialog.showToast("You don't have sufficient balance in your wallet.");
}
}
},
),
)
],
),
const SizedBox(
height: 10,
),
],
),
),
),
);
}
Container buildOrderActionsCard(isDark, CabHomeController controller) {
double totalAmount = 0.0;
double discount = 0.0;
double subTotal = 0.0;
double taxAmount = 0.0;
subTotal = double.parse(controller.currentOrder.value.subTotal.toString());
discount = double.parse(controller.currentOrder.value.discount ?? '0.0');
if (controller.currentOrder.value.taxSetting != null) {
for (var element in controller.currentOrder.value.taxSetting!) {
taxAmount = (taxAmount + Constant.calculateTax(amount: (subTotal - discount).toString(), taxModel: element));
}
}
totalAmount = (subTotal - discount) + taxAmount;
return Container(
color: isDark ? AppThemeData.grey900 : AppThemeData.grey50,
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
controller.currentOrder.value.status == Constant.orderShipped ||
controller.currentOrder.value.status == Constant.driverAccepted
? Row(
children: [
Container(
decoration: ShapeDecoration(
color: AppThemeData.primary50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.all(10),
child: SvgPicture.asset(
"assets/icons/ic_building.svg",
colorFilter: ColorFilter.mode(AppThemeData.primary300, BlendMode.srcIn),
),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
controller.currentOrder.value.author!.fullName(),
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
fontSize: 16,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
),
),
Text(
"${controller.currentOrder.value.sourceLocationName}",
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.medium,
fontSize: 14,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
),
),
],
),
),
const SizedBox(
width: 10,
),
Column(
children: [
InkWell(
onTap: () {
Constant.makePhoneCall(controller.currentOrder.value.author!.phoneNumber.toString());
},
child: Container(
width: 38,
height: 38,
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: isDark ? AppThemeData.grey700 : AppThemeData.grey200),
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset("assets/icons/ic_phone_call.svg"),
),
),
),
SizedBox(
height: 10,
),
InkWell(
onTap: () async {
ShowToastDialog.showLoader("Please wait".tr);
UserModel? customer =
await FireStoreUtils.getUserProfile(controller.currentOrder.value.authorID.toString());
UserModel? driver =
await FireStoreUtils.getUserProfile(controller.currentOrder.value.driverId.toString());
ShowToastDialog.closeLoader();
Get.to(const ChatScreen(), arguments: {
"customerName": customer!.fullName(),
"restaurantName": driver!.fullName(),
"orderId": controller.currentOrder.value.id,
"restaurantId": driver.id,
"customerId": customer.id,
"customerProfileImage": customer.profilePictureURL ?? "",
"restaurantProfileImage": driver.profilePictureURL ?? "",
"token": customer.fcmToken,
"chatType": "Driver",
});
},
child: Container(
width: 42,
height: 42,
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: isDark ? AppThemeData.grey700 : AppThemeData.grey200),
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset("assets/icons/ic_wechat.svg"),
),
),
)
],
),
],
)
: Timeline.tileBuilder(
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
theme: TimelineThemeData(
nodePosition: 0,
// indicatorPosition: 0,
),
builder: TimelineTileBuilder.connected(
contentsAlign: ContentsAlign.basic,
indicatorBuilder: (context, index) {
return index == 0
? Container(
decoration: ShapeDecoration(
color: AppThemeData.primary50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.all(10),
child: SvgPicture.asset(
"assets/icons/ic_building.svg",
colorFilter: ColorFilter.mode(AppThemeData.primary300, BlendMode.srcIn),
),
),
)
: Container(
decoration: ShapeDecoration(
color: AppThemeData.carRent50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.all(10),
child: SvgPicture.asset(
"assets/icons/ic_location.svg",
colorFilter: ColorFilter.mode(AppThemeData.primary300, BlendMode.srcIn),
),
),
);
},
connectorBuilder: (context, index, connectorType) {
return const DashedLineConnector(
color: AppThemeData.grey300,
gap: 3,
);
},
contentsBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: index == 0
? Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
controller.currentOrder.value.author!.fullName(),
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
fontSize: 16,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
),
),
Text(
"${controller.currentOrder.value.sourceLocationName}",
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.medium,
fontSize: 14,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
),
),
],
),
),
const SizedBox(
width: 5,
),
InkWell(
onTap: () {
Constant.makePhoneCall(controller.currentOrder.value.author!.phoneNumber.toString());
},
child: Container(
width: 42,
height: 42,
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: isDark ? AppThemeData.grey700 : AppThemeData.grey200),
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset("assets/icons/ic_phone_call.svg"),
),
),
),
],
)
: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Destination".tr,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
fontSize: 16,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
),
),
Text(
controller.currentOrder.value.destinationLocationName.toString(),
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.medium,
fontSize: 14,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
),
),
],
),
),
const SizedBox(
width: 5,
),
InkWell(
onTap: () async {
ShowToastDialog.showLoader("Please wait".tr);
UserModel? customer =
await FireStoreUtils.getUserProfile(controller.currentOrder.value.authorID.toString());
UserModel? driver =
await FireStoreUtils.getUserProfile(controller.currentOrder.value.driverId.toString());
ShowToastDialog.closeLoader();
Get.to(const ChatScreen(), arguments: {
"customerName": customer!.fullName(),
"restaurantName": driver!.fullName(),
"orderId": controller.currentOrder.value.id,
"restaurantId": driver.id,
"customerId": customer.id,
"customerProfileImage": customer.profilePictureURL ?? "",
"restaurantProfileImage": driver.profilePictureURL ?? "",
"token": customer.fcmToken,
"chatType": "Driver",
});
},
child: Container(
width: 42,
height: 42,
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: isDark ? AppThemeData.grey700 : AppThemeData.grey200),
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset("assets/icons/ic_wechat.svg"),
),
),
)
],
),
);
},
itemCount: 2,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: MySeparator(color: isDark ? AppThemeData.grey700 : AppThemeData.grey200),
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
"Payment Type".tr,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.regular,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
fontSize: 16,
),
),
),
Text(
controller.currentOrder.value.paymentMethod!.toLowerCase() == "cod" ? "Cash on delivery".tr : "Online".tr,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
fontSize: 16,
),
),
],
),
const SizedBox(
height: 5,
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
"Ride Type".tr,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.regular,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
fontSize: 16,
),
),
),
Text(
controller.currentOrder.value.rideType ?? '',
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
fontSize: 16,
),
),
],
),
const SizedBox(
height: 5,
),
controller.currentOrder.value.paymentMethod!.toLowerCase() == "cod"
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
"Collect Payment from customer".tr,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.regular,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
fontSize: 16,
),
),
),
Text(
Constant.amountShow(amount: totalAmount.toString()),
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
fontSize: 16,
),
),
],
)
: const SizedBox(),
const SizedBox(
height: 5,
),
controller.currentOrder.value.tipAmount == null ||
controller.currentOrder.value.tipAmount!.isEmpty ||
double.parse(controller.currentOrder.value.tipAmount.toString()) <= 0
? const SizedBox()
: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
"Tips".tr,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.regular,
color: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
fontSize: 16,
),
),
),
Text(
Constant.amountShow(amount: controller.currentOrder.value.tipAmount),
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.semiBold,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
fontSize: 16,
),
),
],
),
const SizedBox(
height: 10,
),
],
),
),
InkWell(
onTap: () async {
if (controller.currentOrder.value.status == Constant.orderShipped ||
controller.currentOrder.value.status == Constant.driverAccepted) {
showVerifyPassengerDialog(Get.context!, isDark, controller);
} else {
if (controller.currentOrder.value.paymentMethod!.toLowerCase() == "cod") {
showConfirmCashPaymentDialog(Get.context!, isDark, onConfirm: () {
controller.completeRide();
});
} else if (controller.currentOrder.value.paymentStatus == true) {
controller.completeRide();
} else {
ShowToastDialog.showToast("Customer payment is pending".tr);
}
}
},
child: Container(
color: AppThemeData.primary300,
width: Responsive.width(100, Get.context!),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Text(
controller.currentOrder.value.status == Constant.orderShipped ||
controller.currentOrder.value.status == Constant.driverAccepted
? Constant.enableOTPTripStart
? "Verify Code to customer".tr
: "Pickup Customer".tr
: "Complete Ride".tr,
textAlign: TextAlign.center,
style: TextStyle(
color: isDark ? AppThemeData.grey50 : AppThemeData.grey50,
fontSize: 16,
fontFamily: AppThemeData.semiBold,
fontWeight: FontWeight.w400,
),
),
),
),
)
],
),
);
}
void showVerifyPassengerDialog(BuildContext context, bool isDark, CabHomeController controller) {
if (Constant.enableOTPTripStart == false) {
controller.onRideStatus();
return;
}
TextEditingController otpController = TextEditingController();
Get.dialog(
Dialog(
backgroundColor: isDark
? AppThemeData.greyDark50 // 👈 dark background
: AppThemeData.grey50,
insetPadding: const EdgeInsets.symmetric(horizontal: 20), // keeps margin around
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: Container(
width: Responsive.width(90, context),
constraints: BoxConstraints(
maxWidth: Responsive.width(90, context),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Expanded(
child: Text("Verify Passenger".tr,
style:
AppThemeData.boldTextStyle(fontSize: 22, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900))),
InkWell(
onTap: () {
Get.back();
},
child: Icon(Icons.close),
)
],
),
SizedBox(height: 8),
Text(
"Enter the OTP shared by the customer to begin the trip".tr,
textAlign: TextAlign.start,
style: AppThemeData.mediumTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900, fontSize: 14),
),
SizedBox(height: 20),
PinCodeTextField(
length: 4,
appContext: context,
keyboardType: TextInputType.phone,
enablePinAutofill: true,
hintCharacter: "-",
hintStyle: TextStyle(color: isDark ? AppThemeData.grey50 : AppThemeData.grey900, fontFamily: AppThemeData.regular),
textStyle: TextStyle(color: isDark ? AppThemeData.grey50 : AppThemeData.grey900, fontFamily: AppThemeData.regular),
pinTheme: PinTheme(
fieldHeight: 50,
fieldWidth: 50,
inactiveFillColor: isDark ? AppThemeData.grey800 : AppThemeData.grey100,
selectedFillColor: isDark ? AppThemeData.grey800 : AppThemeData.grey100,
activeFillColor: isDark ? AppThemeData.grey800 : AppThemeData.grey100,
inactiveColor: isDark ? AppThemeData.grey800 : AppThemeData.grey100,
disabledColor: isDark ? AppThemeData.grey800 : AppThemeData.grey100,
selectedColor: AppThemeData.primary300,
activeColor: AppThemeData.primary300,
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.all(Radius.circular(10)),
),
cursorColor: AppThemeData.primary300,
enableActiveFill: true,
controller: otpController,
onCompleted: (v) async {},
onChanged: (value) {},
),
SizedBox(height: 25),
RoundedButtonFill(
title: "Start Ride".tr,
height: 5.5,
color: AppThemeData.primary300,
textColor: AppThemeData.grey50,
onPress: () async {
if (otpController.text.length < 4) {
ShowToastDialog.showToast("Please enter valid OTP".tr);
return;
}
if (otpController.text != controller.currentOrder.value.otpCode) {
ShowToastDialog.showToast("Please enter valid OTP".tr);
return;
}
controller.onRideStatus();
},
)
],
),
),
),
),
barrierDismissible: true,
);
}
void showConfirmCashPaymentDialog(BuildContext context, bool isDark, {required VoidCallback onConfirm}) {
Get.dialog(
Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
insetPadding: const EdgeInsets.symmetric(horizontal: 20),
backgroundColor: isDark
? AppThemeData.greyDark50 // 👈 dark background
: AppThemeData.grey50, // 👈 light background
child: Container(
width: MediaQuery.of(context).size.width * 0.9,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Title
Row(
children: [
Expanded(
child: Text(
"Confirm Cash Payment".tr,
style: AppThemeData.boldTextStyle(
fontSize: 20,
color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900,
),
),
),
InkWell(
onTap: () => Get.back(),
child: const Icon(Icons.close, size: 22),
)
],
),
const SizedBox(height: 12),
// Message
Text(
"Are you sure you received the cash from the passenger?".tr,
style: AppThemeData.mediumTextStyle(
fontSize: 14,
color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey700,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
// Buttons
Row(
children: [
Expanded(
child: RoundedButtonFill(
title: "Cancel".tr,
color: isDark ? AppThemeData.grey600 : AppThemeData.grey300,
textColor: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
height: 5,
onPress: () {
Get.back();
},
),
),
const SizedBox(width: 12),
Expanded(
child: RoundedButtonFill(
title: "Complete Ride".tr,
color: AppThemeData.driverApp300,
textColor: AppThemeData.grey50,
height: 5,
onPress: () {
Get.back();
onConfirm();
},
// onPress: () {
// if (controller.currentOrder.value.paymentStatus == true) {
// Get.back();
// onConfirm();
// } else {
// ShowToastDialog.showToast("Customer payment is pending".tr);
// }
// },
),
),
],
)
],
),
),
),
barrierDismissible: false,
);
}
}