Aidra Driver 1.3.5+68
Aidra Driver - Your path to green energy
Loading...
Searching...
No Matches
stations_map_view.dart
Go to the documentation of this file.
1import 'package:flutter/material.dart';
2import 'package:flutter_screenutil/flutter_screenutil.dart';
3import 'package:google_maps_flutter/google_maps_flutter.dart';
4import 'dart:async';
5import 'dart:ui' as ui;
6
7import '../../../../core/UI/theme/color_palette.dart';
8import '../../../../core/UI/widgets/custom_scaffold.dart';
9import '../../models/driver_request.dart';
10
11class StationsMapViewScreen extends StatefulWidget {
12 final List<Station> stations;
13
15 super.key,
16 required this.stations,
17 });
18
19 @override
20 State<StationsMapViewScreen> createState() => _StationsMapViewScreenState();
21}
22
23class _StationsMapViewScreenState extends State<StationsMapViewScreen>
24 with SingleTickerProviderStateMixin {
25 GoogleMapController? _mapController;
26 Map<MarkerId, Marker> _markers = {};
27 bool _isMapLoaded = false;
29 late AnimationController _animationController;
31 [
32 {
33 "featureType": "poi",
34 "elementType": "labels.icon",
35 "stylers": [
36 {
37 "visibility": "off"
38 }
39 ]
40 },
41 {
42 "featureType": "transit",
43 "stylers": [
44 {
45 "visibility": "off"
46 }
47 ]
48 }
49 ]
50 ''';
51
52 @override
53 void initState() {
54 super.initState();
55 _animationController = AnimationController(
56 vsync: this,
57 duration: const Duration(milliseconds: 300),
58 );
60 }
61
62 @override
63 void dispose() {
64 _animationController.dispose();
65 super.dispose();
66 }
67
68 Future<void> _createMarkers() async {
69 final markers = <MarkerId, Marker>{};
70
71 for (int i = 0; i < widget.stations.length; i++) {
72 final station = widget.stations[i];
73
74 final markerId = MarkerId(station.id);
75
76 final marker = Marker(
77 markerId: markerId,
78 position: LatLng(station.latitude, station.longitude),
79 infoWindow: InfoWindow(
80 title: station.name,
81 snippet: '${station.quantityInLiters.toInt()}L - ${station.address}',
82 onTap: () {
83 _showStationDetails(station);
84 },
85 ),
86 icon: await _getMarkerBitmap(i + 1),
87 onTap: () {
88 setState(() {
90 });
91 },
92 );
93
94 markers[markerId] = marker;
95 }
96
97 setState(() {
98 _markers = markers;
99 });
100 }
101
102 Future<BitmapDescriptor> _getMarkerBitmap(int number) async {
103 final size = 35.sp;
104 final pictureRecorder = ui.PictureRecorder();
105 final canvas = Canvas(pictureRecorder);
106 final paint = Paint()
108 ..style = PaintingStyle.fill;
109
110 // Draw marker circle
111 canvas.drawCircle(
112 Offset(size / 2, size / 2),
113 size / 2,
114 paint,
115 );
116
117 // Draw border
118 paint
119 ..color = Colors.white
120 ..style = PaintingStyle.stroke
121 ..strokeWidth = 2;
122
123 canvas.drawCircle(
124 Offset(size / 2, size / 2),
125 size / 2 - 1,
126 paint,
127 );
128
129 // Draw number
130 final textPainter = TextPainter(
131 text: TextSpan(
132 text: number.toString(),
133 style: TextStyle(
134 color: Colors.white,
135 fontSize: 12.sp,
136 fontWeight: FontWeight.bold,
137 ),
138 ),
139 textDirection: TextDirection.ltr,
140 );
141
142 textPainter.layout();
143 textPainter.paint(
144 canvas,
145 Offset(
146 (size - textPainter.width) / 2,
147 (size - textPainter.height) / 2,
148 ),
149 );
150
151 final img = await pictureRecorder.endRecording().toImage(
152 size.toInt(),
153 size.toInt(),
154 );
155 final data = await img.toByteData(format: ui.ImageByteFormat.png);
156
157 return BitmapDescriptor.bytes(data!.buffer.asUint8List(), height: 35.sp);
158 }
159
161 showDialog(
162 context: context,
163 builder: (BuildContext context) {
164 return AlertDialog(
165 shape: RoundedRectangleBorder(
166 borderRadius: BorderRadius.circular(16.r),
167 ),
168 title: Row(
169 children: [
170 Container(
171 padding: EdgeInsets.all(8.sp),
172 decoration: BoxDecoration(
173 color: ColorPalette.lightGreen.withValues(alpha: 0.1),
174 borderRadius: BorderRadius.circular(8.r),
175 ),
176 child: Icon(
177 Icons.local_gas_station,
179 size: 20.sp,
180 ),
181 ),
182 SizedBox(width: 12.w),
183 Expanded(
184 child: Text(
185 station.name,
186 style: TextStyle(
187 fontSize: 16.sp,
188 fontWeight: FontWeight.w600,
190 ),
191 ),
192 ),
193 ],
194 ),
195 content: Column(
196 mainAxisSize: MainAxisSize.min,
197 crossAxisAlignment: CrossAxisAlignment.start,
198 children: [
199 _buildDetailRow('Station ID', station.id),
200 SizedBox(height: 8.h),
201 _buildDetailRow('Address', station.address),
202 SizedBox(height: 8.h),
204 'Quantity', '${station.quantityInLiters.toInt()}L'),
205 SizedBox(height: 8.h),
206 _buildDetailRow('Coordinates',
207 '${station.latitude.toStringAsFixed(4)}, ${station.longitude.toStringAsFixed(4)}'),
208 ],
209 ),
210 actions: [
211 TextButton(
212 onPressed: () => Navigator.of(context).pop(),
213 child: Text(
214 'Close',
215 style: TextStyle(
217 fontSize: 14.sp,
218 ),
219 ),
220 ),
221 ],
222 );
223 },
224 );
225 }
226
228 return Row(
229 crossAxisAlignment: CrossAxisAlignment.start,
230 children: [
231 SizedBox(
232 width: 80.w,
233 child: Text(
234 '$label:',
235 style: TextStyle(
236 fontSize: 12.sp,
237 fontWeight: FontWeight.w600,
239 ),
240 ),
241 ),
242 Expanded(
243 child: Text(
244 value,
245 style: TextStyle(
246 fontSize: 12.sp,
248 ),
249 ),
250 ),
251 ],
252 );
253 }
254
255 @override
256 Widget build(BuildContext context) {
257 LatLng initialPosition =
258 const LatLng(24.7136, 46.6753); // Riyadh, Saudi Arabia
259
260 if (widget.stations.isNotEmpty) {
261 final firstStation = widget.stations.first;
262 initialPosition = LatLng(firstStation.latitude, firstStation.longitude);
263 }
264
265 return CustomScaffold(
266 title: 'Stations Map',
267 backgroundColor: ColorPalette.antiFlashWhite,
268 body: Stack(
269 children: [
270 GoogleMap(
271 style: mapStyle,
272 initialCameraPosition: CameraPosition(
273 target: initialPosition,
274 zoom: 10,
275 ),
276 markers: Set<Marker>.of(_markers.values),
277 onMapCreated: (GoogleMapController controller) {
278 _mapController = controller;
279 setState(() {
280 _isMapLoaded = true;
281 });
282 },
283 myLocationEnabled: true,
284 myLocationButtonEnabled: false,
285 zoomControlsEnabled: false,
286 mapToolbarEnabled: false,
287 compassEnabled: true,
288 onTap: (_) {
289 if (_selectedMarkerIndex != -1) {
290 setState(() {
292 });
293 }
294 },
295 ),
296 if (!_isMapLoaded)
297 Container(
298 color: Colors.white.withValues(alpha: 0.7),
299 child: const Center(
300 child: CircularProgressIndicator(),
301 ),
302 ),
303 // Map control buttons
304 Positioned(
305 right: 16,
306 bottom: 16,
307 child: Column(
308 mainAxisSize: MainAxisSize.min,
309 children: [
311 icon: Icons.add,
312 tooltip: 'Zoom In',
313 onPressed: () {
314 _mapController?.animateCamera(CameraUpdate.zoomIn());
315 },
316 ),
317 SizedBox(height: 8.h),
319 icon: Icons.remove,
320 tooltip: 'Zoom Out',
321 onPressed: () {
322 _mapController?.animateCamera(CameraUpdate.zoomOut());
323 },
324 ),
325 ],
326 ),
327 ),
328 ],
329 ),
330 );
331 }
332
334 required IconData icon,
335 required String tooltip,
336 required VoidCallback onPressed,
337 }) {
338 return Container(
339 width: 40.w,
340 height: 40.h,
341 decoration: BoxDecoration(
343 borderRadius: BorderRadius.circular(8.r),
344 boxShadow: [
345 BoxShadow(
346 color: Colors.black.withValues(alpha: 0.1),
347 blurRadius: 4,
348 offset: const Offset(0, 2),
349 ),
350 ],
351 ),
352 child: Material(
353 color: Colors.transparent,
354 child: InkWell(
355 borderRadius: BorderRadius.circular(8.r),
357 child: Icon(
358 icon,
359 size: 20.sp,
361 ),
362 ),
363 ),
364 );
365 }
366}
override void initState()
override void dispose()
class App extends StatefulWidget build(BuildContext context)
Definition app.dart:31
AuthGuard _()
static const darkGrey
static const lightGreen
static const white
static const antiFlashWhite
static const grey
override State< StationsMapViewScreen > createState()
const StationsMapViewScreen({ super.key, required this.stations, })
final List< Station > stations
final String address
final String name
final String id
late AnimationController _animationController
int _selectedMarkerIndex
Future< void > _createMarkers() async
Future< BitmapDescriptor > _getMarkerBitmap(int number) async
final Widget child
final EdgeInsets padding
override void paint(Canvas canvas, Size size)
class Partner String
final String mapStyle
class EndLocationChooserScreen extends StatefulWidget _mapController
final Color color
Definition failures.dart:1
final VoidCallback onPressed
final String tooltip
Widget _buildDetailRow({ required IconData icon, required String label, required String value, })
final VoidCallback onTap
final String title
Set< Marker > _markers
void _showStationDetails(Station station)
Widget _buildMapButton({ required IconData icon, required String tooltip, required VoidCallback onPressed, })
final String label
style Text( '${ 'scheduling.reference'.tr()}:${collection.internalCode}', style:Theme.of(context).textTheme.bodySmall,)
style SizedBox(height:2.h)
style Column(crossAxisAlignment:CrossAxisAlignment.end, children:[Container(padding:EdgeInsets.symmetric(horizontal:8.w, vertical:4.h), decoration:BoxDecoration(color:ColorPalette.tiffanyBlue.withValues(alpha:0.1), borderRadius:BorderRadius.circular(12),), child:Text(collection.type ?? '', style:Theme.of(context).textTheme.bodySmall?.copyWith(color:ColorPalette.tiffanyBlue, fontWeight:FontWeight.bold,),),),],)