parent
c47bddf151
commit
fb8777b7f8
|
After Width: | Height: | Size: 1.1 KiB |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,639 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:supplier_new/common/settings.dart';
|
||||
import 'package:supplier_new/resources/source_loctaions_model.dart';
|
||||
import '../resources/drivers_model.dart';
|
||||
import '../resources/tankers_model.dart';
|
||||
|
||||
class AssignDriverScreenNewDesign extends StatefulWidget {
|
||||
final dynamic order;
|
||||
final dynamic status;
|
||||
|
||||
const AssignDriverScreenNewDesign({
|
||||
super.key,
|
||||
this.order,
|
||||
this.status,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AssignDriverScreenNewDesign> createState() =>
|
||||
_AssignDriverScreenNewDesignState();
|
||||
}
|
||||
|
||||
class _AssignDriverScreenNewDesignState
|
||||
extends State<AssignDriverScreenNewDesign> {
|
||||
GoogleMapController? _mapController;
|
||||
|
||||
List<DriversModel> driversList = [];
|
||||
List<TankersModel> tankersList = [];
|
||||
List<SourceLocationsModel> sourceLocationsList = [];
|
||||
|
||||
DriversModel? selectedDriver;
|
||||
TankersModel? selectedTanker;
|
||||
SourceLocationsModel? selectedSource;
|
||||
|
||||
bool loading = true;
|
||||
bool routeLoading = false;
|
||||
|
||||
Set<Marker> _markers = {};
|
||||
Set<Polyline> _polylines = {};
|
||||
|
||||
String eta = '';
|
||||
String distanceText = '';
|
||||
String routeError = '';
|
||||
|
||||
static const String googleApiKey = 'AIzaSyDJpK9RVhlBejtJu9xSGfneuTN6HOfJgSM';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
loadData();
|
||||
}
|
||||
|
||||
Future<void> loadData() async {
|
||||
try {
|
||||
final d = await AppSettings.getDrivers();
|
||||
driversList = (jsonDecode(d)['data'] as List)
|
||||
.map((e) => DriversModel.fromJson(e))
|
||||
.toList();
|
||||
|
||||
final t = await AppSettings.getTankers();
|
||||
tankersList = (jsonDecode(t)['data'] as List)
|
||||
.map((e) => TankersModel.fromJson(e))
|
||||
.toList();
|
||||
|
||||
final s = await AppSettings.getSourceLoctaions();
|
||||
sourceLocationsList = (jsonDecode(s)['data'] as List)
|
||||
.map((e) => SourceLocationsModel.fromJson(e))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
debugPrint('Load error: $e');
|
||||
}
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
setState(() {
|
||||
loading = false;
|
||||
_rebuildMarkers();
|
||||
});
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_fitMap();
|
||||
});
|
||||
}
|
||||
|
||||
double? _toDouble(dynamic value) {
|
||||
if (value == null) return null;
|
||||
if (value is double) return value;
|
||||
if (value is int) return value.toDouble();
|
||||
return double.tryParse(value.toString().trim());
|
||||
}
|
||||
|
||||
LatLng? _deliveryPosition() {
|
||||
try {
|
||||
final lat = _toDouble(
|
||||
widget.order?.lat ??
|
||||
widget.order?.delivery_lat ??
|
||||
widget.order?.location_lat,
|
||||
);
|
||||
final lng = _toDouble(
|
||||
widget.order?.lng ??
|
||||
widget.order?.delivery_lng ??
|
||||
widget.order?.location_lng,
|
||||
);
|
||||
|
||||
if (lat == null || lng == null) return null;
|
||||
return LatLng(lat, lng);
|
||||
} catch (e) {
|
||||
debugPrint('Delivery parse error: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
LatLng? _sourcePosition(SourceLocationsModel source) {
|
||||
try {
|
||||
final lat = _toDouble(source.latitude);
|
||||
final lng = _toDouble(source.longitude);
|
||||
if (lat == null || lng == null) return null;
|
||||
return LatLng(lat, lng);
|
||||
} catch (e) {
|
||||
debugPrint('Source parse error: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void _rebuildMarkers() {
|
||||
final Set<Marker> markers = {};
|
||||
|
||||
final delivery = _deliveryPosition();
|
||||
if (delivery != null) {
|
||||
markers.add(
|
||||
Marker(
|
||||
markerId: const MarkerId('delivery'),
|
||||
position: delivery,
|
||||
icon: BitmapDescriptor.defaultMarkerWithHue(
|
||||
BitmapDescriptor.hueRed,
|
||||
),
|
||||
infoWindow: InfoWindow(
|
||||
title: widget.order?.building_name?.toString() ?? 'Delivery',
|
||||
snippet: 'Customer location',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
for (final source in sourceLocationsList) {
|
||||
final pos = _sourcePosition(source);
|
||||
if (pos == null) continue;
|
||||
|
||||
final bool isSelected = selectedSource?.dbId == source.dbId;
|
||||
|
||||
markers.add(
|
||||
Marker(
|
||||
markerId: MarkerId('source_${source.dbId}'),
|
||||
position: pos,
|
||||
icon: BitmapDescriptor.defaultMarkerWithHue(
|
||||
isSelected
|
||||
? BitmapDescriptor.hueViolet
|
||||
: BitmapDescriptor.hueAzure,
|
||||
),
|
||||
infoWindow: InfoWindow(
|
||||
title: source.source_name?.toString() ?? 'Source',
|
||||
snippet: isSelected ? 'Selected source' : 'Tap to select source',
|
||||
),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
selectedSource = source;
|
||||
routeError = '';
|
||||
eta = '';
|
||||
distanceText = '';
|
||||
_rebuildMarkers();
|
||||
});
|
||||
|
||||
await _loadRouteAndEta();
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_fitMap();
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_markers = markers;
|
||||
}
|
||||
|
||||
Future<void> _loadRouteAndEta() async {
|
||||
final source = selectedSource;
|
||||
final sourcePos = source == null ? null : _sourcePosition(source);
|
||||
final deliveryPos = _deliveryPosition();
|
||||
|
||||
if (sourcePos == null || deliveryPos == null) {
|
||||
setState(() {
|
||||
routeError = 'Source or delivery coordinates missing';
|
||||
_polylines = {};
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
routeLoading = true;
|
||||
routeError = '';
|
||||
});
|
||||
|
||||
try {
|
||||
await Future.wait([
|
||||
_loadDirectionsPolyline(sourcePos, deliveryPos),
|
||||
_loadEtaWithDirections(sourcePos, deliveryPos),
|
||||
]);
|
||||
} catch (e) {
|
||||
debugPrint('Route load error: $e');
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
routeError = 'Unable to load route';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
routeLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadEtaWithDirections(
|
||||
LatLng origin,
|
||||
LatLng destination,
|
||||
) async {
|
||||
try {
|
||||
final uri = Uri.parse(
|
||||
'https://maps.googleapis.com/maps/api/directions/json'
|
||||
'?origin=${origin.latitude},${origin.longitude}'
|
||||
'&destination=${destination.latitude},${destination.longitude}'
|
||||
'&mode=driving'
|
||||
'&departure_time=now'
|
||||
'&traffic_model=best_guess'
|
||||
'&key=$googleApiKey',
|
||||
);
|
||||
|
||||
final response = await http.get(uri);
|
||||
final data = jsonDecode(response.body);
|
||||
|
||||
debugPrint('Directions ETA response: $data');
|
||||
|
||||
if (data['status'] != 'OK') {
|
||||
setState(() {
|
||||
routeError = 'ETA unavailable: ${data['status']}';
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
final routes = data['routes'] as List?;
|
||||
if (routes == null || routes.isEmpty) {
|
||||
setState(() {
|
||||
routeError = 'ETA unavailable';
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
final legs = routes.first['legs'] as List?;
|
||||
if (legs == null || legs.isEmpty) {
|
||||
setState(() {
|
||||
routeError = 'ETA unavailable';
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
final leg = legs.first;
|
||||
final distance = leg['distance'];
|
||||
final duration = leg['duration'];
|
||||
final durationInTraffic = leg['duration_in_traffic'];
|
||||
|
||||
setState(() {
|
||||
distanceText = (distance?['text'] ?? '').toString();
|
||||
eta = (durationInTraffic?['text'] ?? duration?['text'] ?? '').toString();
|
||||
});
|
||||
} catch (e) {
|
||||
debugPrint('ETA error: $e');
|
||||
setState(() {
|
||||
routeError = 'ETA request failed';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _loadDirectionsPolyline(
|
||||
LatLng origin,
|
||||
LatLng destination,
|
||||
) async {
|
||||
try {
|
||||
final uri = Uri.parse(
|
||||
'https://maps.googleapis.com/maps/api/directions/json'
|
||||
'?origin=${origin.latitude},${origin.longitude}'
|
||||
'&destination=${destination.latitude},${destination.longitude}'
|
||||
'&mode=driving'
|
||||
'&departure_time=now'
|
||||
'&traffic_model=best_guess'
|
||||
'&key=$googleApiKey',
|
||||
);
|
||||
|
||||
final response = await http.get(uri);
|
||||
final data = jsonDecode(response.body);
|
||||
|
||||
debugPrint('Directions route response: $data');
|
||||
|
||||
if (data['status'] != 'OK') {
|
||||
setState(() {
|
||||
routeError = 'Route unavailable: ${data['status']}';
|
||||
_polylines = {};
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
final routes = data['routes'] as List?;
|
||||
if (routes == null || routes.isEmpty) {
|
||||
setState(() {
|
||||
routeError = 'No route found';
|
||||
_polylines = {};
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
final encoded = routes.first['overview_polyline']?['points']?.toString();
|
||||
if (encoded == null || encoded.isEmpty) {
|
||||
setState(() {
|
||||
routeError = 'Route polyline missing';
|
||||
_polylines = {};
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
final polylinePoints = PolylinePoints();
|
||||
final decoded = polylinePoints.decodePolyline(encoded);
|
||||
|
||||
final points = decoded
|
||||
.map((p) => LatLng(p.latitude, p.longitude))
|
||||
.toList();
|
||||
|
||||
if (points.isEmpty) {
|
||||
setState(() {
|
||||
routeError = 'Failed to decode route';
|
||||
_polylines = {};
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_polylines = {
|
||||
Polyline(
|
||||
polylineId: const PolylineId('source_delivery_route'),
|
||||
points: points,
|
||||
color: Colors.blue,
|
||||
width: 6,
|
||||
),
|
||||
};
|
||||
});
|
||||
} catch (e) {
|
||||
debugPrint('Polyline error: $e');
|
||||
setState(() {
|
||||
routeError = 'Route request failed';
|
||||
_polylines = {};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _fitMap() async {
|
||||
if (_mapController == null) return;
|
||||
|
||||
final List<LatLng> points = [];
|
||||
|
||||
final delivery = _deliveryPosition();
|
||||
if (delivery != null) points.add(delivery);
|
||||
|
||||
for (final source in sourceLocationsList) {
|
||||
final pos = _sourcePosition(source);
|
||||
if (pos != null) points.add(pos);
|
||||
}
|
||||
|
||||
if (points.isEmpty) return;
|
||||
|
||||
if (points.length == 1) {
|
||||
await _mapController!.animateCamera(
|
||||
CameraUpdate.newCameraPosition(
|
||||
CameraPosition(target: points.first, zoom: 14),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
double minLat = points.first.latitude;
|
||||
double maxLat = points.first.latitude;
|
||||
double minLng = points.first.longitude;
|
||||
double maxLng = points.first.longitude;
|
||||
|
||||
for (final point in points) {
|
||||
if (point.latitude < minLat) minLat = point.latitude;
|
||||
if (point.latitude > maxLat) maxLat = point.latitude;
|
||||
if (point.longitude < minLng) minLng = point.longitude;
|
||||
if (point.longitude > maxLng) maxLng = point.longitude;
|
||||
}
|
||||
|
||||
try {
|
||||
await _mapController!.animateCamera(
|
||||
CameraUpdate.newLatLngBounds(
|
||||
LatLngBounds(
|
||||
southwest: LatLng(minLat, minLng),
|
||||
northeast: LatLng(maxLat, maxLng),
|
||||
),
|
||||
80,
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
try {
|
||||
await _mapController!.animateCamera(
|
||||
CameraUpdate.newLatLngBounds(
|
||||
LatLngBounds(
|
||||
southwest: LatLng(minLat, minLng),
|
||||
northeast: LatLng(maxLat, maxLng),
|
||||
),
|
||||
80,
|
||||
),
|
||||
);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> assign() async {
|
||||
if (selectedDriver == null) {
|
||||
_msg('Select driver');
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedTanker == null) {
|
||||
_msg('Select tanker');
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedSource == null) {
|
||||
_msg('Select source from map');
|
||||
return;
|
||||
}
|
||||
|
||||
final payload = <String, dynamic>{};
|
||||
payload["tankerName"] = selectedTanker!.tanker_name;
|
||||
payload["delivery_agent"] = selectedDriver!.driver_name;
|
||||
payload["delivery_agent_mobile"] = selectedDriver!.phone_number;
|
||||
payload["water_source_location"] = selectedSource!.source_name;
|
||||
|
||||
AppSettings.preLoaderDialog(context);
|
||||
|
||||
bool status = false;
|
||||
try {
|
||||
status = await AppSettings.assignTanker(payload, widget.order.dbId);
|
||||
} catch (e) {
|
||||
debugPrint('Assign error: $e');
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (status) {
|
||||
_msg('Assigned successfully');
|
||||
Navigator.pop(context, true);
|
||||
} else {
|
||||
_msg('Assignment failed');
|
||||
}
|
||||
}
|
||||
|
||||
void _msg(String message) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(message)),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoRow(IconData icon, String text) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, size: 18),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(child: Text(text)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBottomCard() {
|
||||
return Container(
|
||||
margin: const EdgeInsets.all(15),
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
blurRadius: 10,
|
||||
color: Colors.black26,
|
||||
offset: Offset(0, 3),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
DropdownButton<DriversModel>(
|
||||
isExpanded: true,
|
||||
hint: const Text('Select Driver'),
|
||||
value: selectedDriver,
|
||||
items: driversList.map((driver) {
|
||||
return DropdownMenuItem(
|
||||
value: driver,
|
||||
child: Text(driver.driver_name?.toString() ?? 'Driver'),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedDriver = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
DropdownButton<TankersModel>(
|
||||
isExpanded: true,
|
||||
hint: const Text('Select Tanker'),
|
||||
value: selectedTanker,
|
||||
items: tankersList.map((tanker) {
|
||||
return DropdownMenuItem(
|
||||
value: tanker,
|
||||
child: Text(
|
||||
'${tanker.tanker_name} (${tanker.capacity})',
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedTanker = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_buildInfoRow(
|
||||
Icons.water_drop_outlined,
|
||||
selectedSource?.source_name?.toString() ?? 'Select source from map',
|
||||
),
|
||||
if (routeLoading) ...[
|
||||
const SizedBox(height: 8),
|
||||
const LinearProgressIndicator(),
|
||||
],
|
||||
if (distanceText.isNotEmpty || eta.isNotEmpty) ...[
|
||||
const SizedBox(height: 10),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0XFFF5F4FF),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
if (distanceText.isNotEmpty)
|
||||
_buildInfoRow(Icons.route, 'Distance: $distanceText'),
|
||||
if (eta.isNotEmpty)
|
||||
_buildInfoRow(Icons.timer_outlined, 'ETA: $eta'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
if (routeError.isNotEmpty) ...[
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
routeError,
|
||||
style: const TextStyle(
|
||||
color: Colors.red,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 12),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: assign,
|
||||
child: const Text('ASSIGN'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (loading) {
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Enterprise Dispatch Map'),
|
||||
),
|
||||
body: Stack(
|
||||
children: [
|
||||
GoogleMap(
|
||||
initialCameraPosition: CameraPosition(
|
||||
target: _deliveryPosition() ?? const LatLng(17.3850, 78.4867),
|
||||
zoom: 12,
|
||||
),
|
||||
markers: _markers,
|
||||
polylines: _polylines,
|
||||
trafficEnabled: true,
|
||||
zoomControlsEnabled: true,
|
||||
myLocationButtonEnabled: true,
|
||||
mapToolbarEnabled: false,
|
||||
onMapCreated: (controller) {
|
||||
_mapController = controller;
|
||||
Future.delayed(const Duration(milliseconds: 400), () {
|
||||
_fitMap();
|
||||
});
|
||||
},
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: _buildBottomCard(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,428 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
|
||||
class TankerOptionsDemo extends StatefulWidget {
|
||||
|
||||
@override
|
||||
State<TankerOptionsDemo> createState() => _TankerOptionsDemoState();
|
||||
|
||||
}
|
||||
|
||||
class _TankerOptionsDemoState extends State<TankerOptionsDemo> {
|
||||
|
||||
GoogleMapController? mapController;
|
||||
|
||||
LatLng customerLocation =
|
||||
LatLng(17.3850,78.4867);
|
||||
|
||||
String selectedTanker="TNK1";
|
||||
|
||||
List tankers=[
|
||||
|
||||
{
|
||||
"id":"TNK1",
|
||||
"lat":17.387,
|
||||
"lng":78.489,
|
||||
"distance":2.5,
|
||||
"eta":15,
|
||||
"status":"AVAILABLE"
|
||||
},
|
||||
|
||||
{
|
||||
"id":"TNK2",
|
||||
"lat":17.381,
|
||||
"lng":78.480,
|
||||
"distance":5,
|
||||
"eta":30,
|
||||
"status":"ON_DELIVERY",
|
||||
"availableIn":20
|
||||
},
|
||||
|
||||
{
|
||||
"id":"TNK3",
|
||||
"lat":17.370,
|
||||
"lng":78.470,
|
||||
"distance":9,
|
||||
"eta":50,
|
||||
"status":"FAR"
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
Set<Marker> markers={};
|
||||
|
||||
@override
|
||||
void initState(){
|
||||
|
||||
super.initState();
|
||||
|
||||
createMarkers();
|
||||
|
||||
}
|
||||
|
||||
void createMarkers(){
|
||||
|
||||
markers.add(
|
||||
|
||||
Marker(
|
||||
|
||||
markerId: MarkerId("customer"),
|
||||
|
||||
position: customerLocation,
|
||||
|
||||
infoWindow:
|
||||
InfoWindow(title:"Delivery Location"),
|
||||
|
||||
icon: BitmapDescriptor.defaultMarkerWithHue(
|
||||
BitmapDescriptor.hueBlue)
|
||||
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
for(var t in tankers){
|
||||
|
||||
BitmapDescriptor color;
|
||||
|
||||
if(t["status"]=="AVAILABLE"){
|
||||
|
||||
color=
|
||||
BitmapDescriptor.defaultMarkerWithHue(
|
||||
BitmapDescriptor.hueGreen);
|
||||
|
||||
}
|
||||
|
||||
else if(t["status"]=="ON_DELIVERY"){
|
||||
|
||||
color=
|
||||
BitmapDescriptor.defaultMarkerWithHue(
|
||||
BitmapDescriptor.hueOrange);
|
||||
|
||||
}
|
||||
|
||||
else{
|
||||
|
||||
color=
|
||||
BitmapDescriptor.defaultMarkerWithHue(
|
||||
BitmapDescriptor.hueRed);
|
||||
|
||||
}
|
||||
|
||||
markers.add(
|
||||
|
||||
Marker(
|
||||
|
||||
markerId: MarkerId(t["id"]),
|
||||
|
||||
position: LatLng(
|
||||
t["lat"],
|
||||
t["lng"]
|
||||
),
|
||||
|
||||
infoWindow:
|
||||
InfoWindow(
|
||||
|
||||
title:t["id"],
|
||||
|
||||
snippet:
|
||||
"ETA ${t["eta"]} min"
|
||||
|
||||
),
|
||||
|
||||
icon:color
|
||||
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
setState(() {});
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context){
|
||||
|
||||
return Scaffold(
|
||||
|
||||
appBar: AppBar(
|
||||
|
||||
title:
|
||||
Text("Select Tanker"),
|
||||
|
||||
backgroundColor:
|
||||
Colors.white,
|
||||
|
||||
),
|
||||
|
||||
body:
|
||||
|
||||
Column(
|
||||
|
||||
children:[
|
||||
|
||||
Container(
|
||||
|
||||
height:300,
|
||||
|
||||
child:
|
||||
|
||||
GoogleMap(
|
||||
|
||||
initialCameraPosition:
|
||||
|
||||
CameraPosition(
|
||||
|
||||
target:
|
||||
customerLocation,
|
||||
|
||||
zoom:13
|
||||
|
||||
),
|
||||
|
||||
markers:markers,
|
||||
|
||||
),
|
||||
|
||||
),
|
||||
|
||||
Expanded(
|
||||
|
||||
child:
|
||||
|
||||
ListView(
|
||||
|
||||
children:
|
||||
|
||||
tankers.map((t){
|
||||
|
||||
return tankerCard(t);
|
||||
|
||||
}).toList(),
|
||||
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
],
|
||||
|
||||
),
|
||||
|
||||
bottomNavigationBar:
|
||||
|
||||
Container(
|
||||
|
||||
padding:EdgeInsets.all(12),
|
||||
|
||||
child:
|
||||
|
||||
ElevatedButton(
|
||||
|
||||
style:
|
||||
|
||||
ElevatedButton.styleFrom(
|
||||
|
||||
backgroundColor:
|
||||
Colors.green
|
||||
|
||||
),
|
||||
|
||||
onPressed:(){
|
||||
|
||||
Navigator.pop(context);
|
||||
|
||||
},
|
||||
|
||||
child:
|
||||
|
||||
Text("Confirm Selection")
|
||||
|
||||
),
|
||||
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
Widget tankerCard(var tanker){
|
||||
|
||||
Color color;
|
||||
|
||||
if(tanker["status"]=="AVAILABLE"){
|
||||
|
||||
color=Colors.green;
|
||||
|
||||
}
|
||||
|
||||
else if(tanker["status"]=="ON_DELIVERY"){
|
||||
|
||||
color=Colors.orange;
|
||||
|
||||
}
|
||||
|
||||
else{
|
||||
|
||||
color=Colors.red;
|
||||
|
||||
}
|
||||
|
||||
return GestureDetector(
|
||||
|
||||
onTap:(){
|
||||
|
||||
selectedTanker=tanker["id"];
|
||||
|
||||
setState(() {});
|
||||
|
||||
},
|
||||
|
||||
child:
|
||||
|
||||
Container(
|
||||
|
||||
margin:
|
||||
EdgeInsets.all(10),
|
||||
|
||||
padding:
|
||||
EdgeInsets.all(12),
|
||||
|
||||
decoration:
|
||||
|
||||
BoxDecoration(
|
||||
|
||||
borderRadius:
|
||||
BorderRadius.circular(10),
|
||||
|
||||
border:
|
||||
|
||||
Border.all(
|
||||
|
||||
color:
|
||||
|
||||
selectedTanker==tanker["id"]
|
||||
|
||||
?
|
||||
|
||||
Colors.green
|
||||
|
||||
:
|
||||
|
||||
Colors.grey
|
||||
|
||||
),
|
||||
|
||||
),
|
||||
|
||||
child:
|
||||
|
||||
Column(
|
||||
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
|
||||
children:[
|
||||
|
||||
Row(
|
||||
|
||||
children:[
|
||||
|
||||
Text(
|
||||
|
||||
tanker["id"],
|
||||
|
||||
style:
|
||||
|
||||
TextStyle(
|
||||
|
||||
fontSize:18,
|
||||
|
||||
fontWeight:
|
||||
FontWeight.bold
|
||||
|
||||
),
|
||||
|
||||
),
|
||||
|
||||
Spacer(),
|
||||
|
||||
Container(
|
||||
|
||||
padding:
|
||||
EdgeInsets.all(6),
|
||||
|
||||
decoration:
|
||||
|
||||
BoxDecoration(
|
||||
|
||||
color:
|
||||
color,
|
||||
|
||||
borderRadius:
|
||||
BorderRadius.circular(5)
|
||||
|
||||
),
|
||||
|
||||
child:
|
||||
|
||||
Text(
|
||||
|
||||
tanker["status"],
|
||||
|
||||
style:
|
||||
|
||||
TextStyle(
|
||||
color:Colors.white)
|
||||
|
||||
),
|
||||
|
||||
)
|
||||
|
||||
],
|
||||
|
||||
),
|
||||
|
||||
SizedBox(height:8),
|
||||
|
||||
Text(
|
||||
"Distance : ${tanker["distance"]} km"),
|
||||
|
||||
Text(
|
||||
"ETA : ${tanker["eta"]} min"),
|
||||
|
||||
if(tanker["status"]=="ON_DELIVERY")
|
||||
|
||||
Text(
|
||||
"Available in ${tanker["availableIn"]} min"),
|
||||
|
||||
if(tanker["status"]=="FAR")
|
||||
|
||||
Text(
|
||||
"⚠ Transport charges higher"),
|
||||
|
||||
SizedBox(height:6),
|
||||
|
||||
if(tanker["status"]=="AVAILABLE")
|
||||
|
||||
Text(
|
||||
"BEST OPTION",
|
||||
|
||||
style:
|
||||
|
||||
TextStyle(
|
||||
color:Colors.green)
|
||||
|
||||
)
|
||||
|
||||
],
|
||||
|
||||
),
|
||||
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in new issue