0% found this document useful (0 votes)
3 views9 pages

Customer Trip Container

The document is a Flutter widget called CustomTripContainer that displays trip details and allows users to share, update, delete, or activate/deactivate a trip. It includes a bottom sheet for sharing trip information via phone or email, with validation for input fields. The widget also provides visual indicators for trip status and organizes trip data such as vehicle number, source, destination, and timestamps in a structured layout.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views9 pages

Customer Trip Container

The document is a Flutter widget called CustomTripContainer that displays trip details and allows users to share, update, delete, or activate/deactivate a trip. It includes a bottom sheet for sharing trip information via phone or email, with validation for input fields. The widget also provides visual indicators for trip status and organizes trip data such as vehicle number, source, destination, and timestamps in a structured layout.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 9

import 'package:flutter/material.

dart';
import 'package:iconsax/iconsax.dart';
import 'package:intl/intl.dart';
import 'package:skeletonizer/skeletonizer.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:google_fonts/google_fonts.dart';

import '../../Features/Trip/Cubit/GetMyTrips_State.dart';
import '../../Helper/constants.dart';
import '../../Helper/customToast.dart';
import '../../Helper/imageConstants.dart';

class CustomTripContainer extends StatefulWidget {


final String name;
final bool? status;
final TripDetailsList data;
final Function? viewFunction;
final Function? updateFunction;
final Function? deleteFunction;
final Function? deActiveFunction;
final Function(String contact, String email)? shareTrip; // Updated

const CustomTripContainer({
Key? key,
required this.name,
this.viewFunction,
this.updateFunction,
this.deleteFunction,
this.deActiveFunction,
this.shareTrip,
this.status,
required this.data,
}) : super(key: key);

@override
State<CustomTripContainer> createState() => _CustomTripContainerState();
}

class _CustomTripContainerState extends State<CustomTripContainer> {


bool? isUpdate;

@override
void initState() {
// TODO: implement initState
super.initState();
}

_ShareTripBottomSheet(BuildContext context) {
final _formKey = GlobalKey<FormState>();
final _emailController = TextEditingController();
final _contactController = TextEditingController();
ValueNotifier<String> _selectedOption =
ValueNotifier<String>('phone'); // To track selected option

showModalBottomSheet(
enableDrag: true,
isDismissible: true,
context: context,
useSafeArea: true,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(25.0)),
),
backgroundColor: Colors.white,
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.only(
left: 16.0,
right: 16.0,
top: 16.0,
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Share Trip',
style: Theme.of(context).textTheme.labelMedium,
),
SizedBox(height: 20.h),
ValueListenableBuilder<String>(
valueListenable: _selectedOption,
builder: (context, value, _) {
return Column(
children: [
TextFormField(
controller: _contactController,
style: Theme.of(context).textTheme.bodySmall,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
labelText: 'Phone Number',
labelStyle:
Theme.of(context).textTheme.labelSmall,
prefixIcon: Icon(Icons.phone),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(14.0),
),
),
validator: (value) {
// Validation for phone number
if (value != null && value.isNotEmpty) {
if (!RegExp(r'^\d{10,14}$').hasMatch(value)) {
return 'Enter a valid phone number (10-14
digits)';
}
}
return null;
},
),
SizedBox(
height: 10.h,
),
TextFormField(
controller: _emailController,
style: Theme.of(context).textTheme.bodySmall,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
labelStyle:
Theme.of(context).textTheme.labelSmall,
prefixIcon: Icon(Icons.email),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(14.0),
),
),
validator: (value) {
// Validation for email
if (value != null && value.isNotEmpty) {
if (!RegExp(
r'^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]+')
.hasMatch(value)) {
return 'Enter a valid email';
}
}
return null;
},
),
],
);
},
),
SizedBox(height: 20.h),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
style: ButtonStyle(
minimumSize:
WidgetStateProperty.all<Size>(Size(90, 40)),
shape:
WidgetStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0).r,
),
),
backgroundColor:
WidgetStateProperty.all<Color>(Colors.red),
),
child: Text(
'Cancel',
style: Theme.of(context).textTheme.headlineSmall,
),
),
SizedBox(width: 10.w),
ElevatedButton(
onPressed: () async {
if ((_contactController.text.isEmpty &&
_emailController.text.isEmpty)) {
/*ScaffoldMessenger.of(context).showSnackBar(
SnackBar(,content: Text('Please enter either contact
number or email')),
);*/
showErrorToast(
'Please enter contact number and email');
return;
}

if (_formKey.currentState!.validate()) {
if (widget.shareTrip != null) {
await widget.shareTrip!(_contactController.text,
_emailController.text);
Navigator.pop(context);
}
}
},
style: ButtonStyle(
minimumSize:
WidgetStateProperty.all<Size>(Size(90, 40)),
shape:
WidgetStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
backgroundColor:
WidgetStateProperty.all<Color>(Colors.blue),
),
child: Text(
'Share Trip',
style: Theme.of(context).textTheme.headlineSmall,
),
),
],
),
SizedBox(height: 10.h),
],
),
),
),
);
},
);
}

Widget statusIndicator() {
final color = widget.status == true ? Constants.on : Constants.ErrorText;
return Container(
height: 10.h,
width: 10.w,
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
);
}

@override
Widget build(BuildContext context) {
var currentTimestamp =
DateTime.fromMillisecondsSinceEpoch(widget.data.actualEndTime==null||
widget.data.actualStartTime==null?widget.data.startTime!:widget.data.actualEndTime!
* 1000);
var endTime =
DateTime.fromMillisecondsSinceEpoch(widget.data.actualEndTime==null||
widget.data.actualStartTime==null?widget.data.endTime!:widget.data.actualEndTime! *
1000);

return Column(
children: [
Padding(
padding: const EdgeInsets.only(
left: 10.0, right: 10.0, bottom: 0, top: 5.0)
.r,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(07).r,
border: Border.all(color: Colors.white, width: 2.w),
color: Colors.white70,
),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15).r,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 10.h,
),
Row(
children: [
Skeleton.shade(child: statusIndicator()),
Text(
" Trip Id :${widget.data.tripID.toString()}",
style: Theme.of(context).textTheme.labelMedium,
),
Spacer(),
/* IconButton(
onPressed: () async {
final result = await _ShareTripBottomSheet(context);
if (result != null) {
String contact = result['contact'];
String email = result['email'];
if (widget.shareTrip != null) {
widget.shareTrip!(contact, email);
}
}
},
icon: Icon(
Icons.share,
color: Colors.blue,
size: 20,
),
),*/
PopupMenuButton<String>(
offset: Offset(0, 30),
itemBuilder: (BuildContext context) {
List<PopupMenuItem<String>> menuItems = [];

if (widget.data.actualEndTime==null||
widget.data.actualStartTime==null) {
// Add Update option
menuItems.add(
PopupMenuItem(
onTap: () {
widget.updateFunction!();
},
value: 'edit',
child: SizedBox(
width: 130.w,
child: Row(
children: [
Icon(
Iconsax.edit,
size: 20,
color: Colors.black,
),
SizedBox(width: 10),
Text(
'Update',
style:
Theme.of(context).textTheme.bodyMedium,
),
],
),
),
),
);

// Add Activate/Deactivate option


menuItems.add(
PopupMenuItem(
onTap: () {
widget.deActiveFunction!();
},
value: 'active',
child: SizedBox(
width: 130.w,
child: Row(
children: [
Icon(
Iconsax.refresh,
size: 20,
color: Colors.black,
),
SizedBox(width: 10),
Text(
widget.status! ? 'Deactivate' : 'Activate',
style:
Theme.of(context).textTheme.bodyMedium,
),
],
),
),
),
);
}

// Add Delete option


menuItems.add(
PopupMenuItem(
onTap: () {
widget.deleteFunction!();
},
value: 'Delete',
child: SizedBox(
width: 130.w,
child: Row(
children: [
Icon(
Icons.delete_outline,
color: Colors.black,
size: 20,
),
SizedBox(width: 10.w),
Text(
'Delete',
style:
Theme.of(context).textTheme.bodyMedium,
),
],
),
),
),
);

return menuItems;
},
child: Image.asset(
ImageConstants.dots,
height: 22.h,
),
),

SizedBox(
height: 33.h,
),
],
),
SizedBox(
height: 10.h,
),
Row(
children: [
Text(
"Vehicle No : ",
style: Theme.of(context).textTheme.labelMedium,
),
Text(
"${widget.data.vehicleNumber!.toUpperCase() ?? ''}",style:
TextStyle(fontWeight: FontWeight.bold,),
// style: Theme.of(context).textTheme.bodySmall,
),
],
),
SizedBox(height: 10.h),
Row(children: [
Icon(Icons.radio_button_checked, color: Colors.green,size: 15),
SizedBox(width: 5.w), Text(
'Source:',style: TextStyle(fontWeight: FontWeight.bold,color:
Colors.green),
//style: Theme.of(context).textTheme.labelMedium,
),

]),
Column(crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 22,top: 01),
child: Text(
"${widget.data.source!}",
maxLines: 3,
style: Theme.of(context).textTheme.bodySmall,
),
),
],
),
SizedBox(height: 10.h),
Row(
children: [
Icon(Icons.radio_button_checked, color: Colors.red,size:
15,),
SizedBox(width: 5.w),
Text(
'Destination:',style: TextStyle(fontWeight:
FontWeight.bold,color: Colors.red),
//style: Theme.of(context).textTheme.labelMedium,
),
],
),
Column(
children: [
Padding(
padding: EdgeInsets.only(left: 22,top: 01),
child: Text(
"${widget.data.destination!}",
maxLines: 3,
style: Theme.of(context).textTheme.bodySmall,
),
),
],
),
Divider(height: 14, color: Colors.grey),
Row(
children: [
Icon(
Icons.timelapse,
color: Colors.black,
size: 20,
),
SizedBox(
width: 5.w,
),
Text(
widget.data.actualEndTime==null||
widget.data.actualStartTime==null?"Start Date & Time":"Actual start date",
style: Theme.of(context).textTheme.labelMedium,
),
Spacer(),
Text(
'${DateFormat('dd/MM/yyyy, hh:mm
a').format(currentTimestamp)}',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
SizedBox(height: 10.h),
Row(
children: [
Icon(
Icons.timelapse,
color: Colors.black,
size: 20,
),
SizedBox(
width: 5.w,
),
Text(
widget.data.actualEndTime==null||
widget.data.actualStartTime==null?"End Date & Time":"Actual end date",
style: Theme.of(context).textTheme.labelMedium,
),
Spacer(),
Text(
'${DateFormat('dd/MM/yyyy, hh:mm a').format(endTime)}',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
SizedBox(height: 10.h),
],
),
),
),
),
],
);
}
}

You might also like