Aidra Driver 1.3.5+68
Aidra Driver - Your path to green energy
Loading...
Searching...
No Matches
check_in_screen.dart
Go to the documentation of this file.
1import 'package:flutter_svg/svg.dart';
2import 'package:flutter/material.dart';
3import 'package:flutter_bloc/flutter_bloc.dart';
4import 'package:go_router/go_router.dart';
5import 'package:shimmer/shimmer.dart';
6
7import '../../../../../core/common/models/check_in_status_model.dart';
8import '../../../../../core/constants/assets.dart';
9import '../../../../../core/router/routes.dart';
10import '../../../../../core/services/check_in_service.dart';
11import '../../../../../core/ui/theme/color_palette.dart';
12import '../../../../../core/ui/widgets/custom_slider.dart';
13import '../../../../../core/ui/widgets/custom_scaffold.dart';
14import '../../bloc/authentication_bloc/authentication_bloc.dart';
15import '../../../../../features/home/presentation/bloc/home_bloc.dart';
16import '../../../../../features/home/domain/entities/res/res_schedule_status_entity.dart';
17
18class CheckInScreen extends StatefulWidget {
19 const CheckInScreen({super.key});
20
21 @override
22 State<CheckInScreen> createState() => _CheckInScreenState();
23}
24
25class _CheckInScreenState extends State<CheckInScreen> {
27 bool isLoading = true;
29 bool isCheckingIn = false;
31
32 @override
33 void initState() {
34 super.initState();
35 final authState = context.read<AuthenticationBloc>().state;
36 if (authState is AuthenticationInitialState) {
37 context.read<AuthenticationBloc>().add(LoadSessionEvent());
38 } else if (authState is AuthenticatedState) {
39 _loadAssignedVehicle(authState);
40 }
41 }
42
43 Future<void> _loadAssignedVehicle(AuthenticatedState authState) async {
44 setState(() {
45 isLoading = true;
46 errorMessage = null;
47 });
48
49 try {
50 final checkInStatus = await _checkInService.getCheckInStatus(
51 userId: authState.session.uid ?? 0,
52 );
53
54 setState(() {
55 assignedVehicle = checkInStatus;
56 isLoading = false;
57 });
58 } catch (e) {
59 setState(() {
60 errorMessage = "Failed to load assigned vehicle: ${e.toString()}";
61 isLoading = false;
62 });
63 }
64 }
65
66 @override
67 Widget build(BuildContext context) {
68 return MultiBlocListener(
69 listeners: [
70 BlocListener<AuthenticationBloc, AuthenticationState>(
71 listenWhen: (previous, current) => current is AuthenticatedState || current is AuthenticationFailureState || current is AuthenticationInitialState,
72 listener: (context, state) {
73 if (state is AuthenticatedState) {
75 }
76 },
77 ),
78 BlocListener<HomeBloc, HomeState>(
79 listener: (context, state) {
80 if (state is ScheduleStatusLoaded) {
81 if (state.status == ScheduleStatus.empty) {
82 context.go(Routes.startLocationChooserScreen.route);
83 } else if (state.status == ScheduleStatus.validated) {
84 context.go(Routes.homeScreen.route);
85 } else if (state.status == ScheduleStatus.draft) {
86 context.go(Routes.scheduleConfirmationScreen.route);
87 }
88 } else if (state is ScheduleStatusError) {
89 context.go(Routes.homeScreen.route);
90 }
91 },
92 ),
93 ],
94 child: CustomScaffold(
95 backgroundColor: ColorPalette.antiFlashWhite,
96 body: SingleChildScrollView(
97 child: Padding(
98 padding: const EdgeInsets.symmetric(horizontal: 24.0),
100 children: [
101 const SizedBox(height: 48),
102 // Logo
103 Row(
104 mainAxisAlignment: MainAxisAlignment.center,
105 children: [
106 SvgPicture.asset(
108 width: 32,
109 height: 32,
110 ),
111 ],
112 ),
113 const SizedBox(height: 40),
114 // Vehicle Display
116 const SizedBox(height: 24),
117 // Map Container
118 SvgPicture.asset(Assets.environmentalEarth, width: 190),
119 const SizedBox(height: 24),
120 // Thank you text
121 RichText(
122 textAlign: TextAlign.center,
123 text: TextSpan(
124 style: TextStyle(
125 fontSize: 16,
126 height: 1.5,
127 color: Colors.grey[600],
128 ),
129 children: const [
130 TextSpan(
131 text: 'Thanks for your daily environmental impact',
132 ),
133 TextSpan(
134 text: ' 🙏\n',
135 ),
136 TextSpan(
137 text: "let's check in and start our day",
138 ),
139 ],
140 ),
141 ),
142 const SizedBox(height: 50),
143 if (isCheckingIn) ...[
144 Container(
145 padding: const EdgeInsets.symmetric(vertical: 20),
146 child: Column(
147 children: [
148 CircularProgressIndicator(
149 valueColor: AlwaysStoppedAnimation<Color>(ColorPalette.lightGreen),
150 ),
151 const SizedBox(height: 16),
152 Text(
153 'Checking in...',
154 style: TextStyle(
155 fontSize: 16,
156 fontWeight: FontWeight.w500,
157 color: Colors.grey[600],
158 ),
159 ),
160 const SizedBox(height: 4),
161 Text(
162 'Please wait while we verify your location',
163 style: TextStyle(
164 fontSize: 14,
165 color: Colors.grey[500],
166 ),
167 ),
168 ],
169 ),
170 ),
171 ] else ...[
172 CustomSlider(
173 action: (p0) => _performCheckIn(),
174 text: "> > CHECK IN",
175 ),
176 ],
177 const SizedBox(height: 32),
178 ],
179 ),
180 ),
181 ),
182 ),
183 );
184 }
185
187 if (isLoading) {
188 return _buildLoadingDisplay();
189 } else if (errorMessage != null) {
191 } else if (assignedVehicle != null) {
193 } else {
194 return _buildNoVehicleDisplay();
195 }
196 }
197
199 return Container(
200 decoration: BoxDecoration(
201 color: Colors.white,
202 borderRadius: BorderRadius.circular(16),
203 boxShadow: [
204 BoxShadow(
205 color: Colors.black.withValues(alpha: 0.05),
206 blurRadius: 10,
207 offset: const Offset(0, 2),
208 ),
209 ],
210 ),
211 padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
212 child: Column(
213 crossAxisAlignment: CrossAxisAlignment.start,
214 children: [
215 Row(
216 children: [
217 Icon(Icons.directions_car, color: ColorPalette.lightGreen),
218 const SizedBox(width: 12),
219 Text(
220 'Your Assigned Vehicle',
221 style: TextStyle(
222 color: Colors.grey[600],
223 fontSize: 14,
224 fontWeight: FontWeight.w500,
225 ),
226 ),
227 ],
228 ),
229 const SizedBox(height: 12),
230 Row(
231 children: [
232 Expanded(
233 child: Text(
234 vehicle.immatriculation,
235 style: const TextStyle(
236 fontSize: 18,
237 fontWeight: FontWeight.w600,
238 color: Color(0xFF1A1A1A),
239 ),
240 ),
241 ),
242 Container(
243 padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
244 decoration: BoxDecoration(
245 color: ColorPalette.lightGreen.withValues(alpha: 0.1),
246 borderRadius: BorderRadius.circular(12),
247 ),
248 child: Text(
249 'ID: ${vehicle.vehicleId}',
250 style: TextStyle(
251 fontSize: 12,
252 fontWeight: FontWeight.w500,
254 ),
255 ),
256 ),
257 ],
258 ),
259 ],
260 ),
261 );
262 }
263
264 void _performCheckIn() async {
265 if (isCheckingIn) return;
266
267 final authState = context.read<AuthenticationBloc>().state;
268 if (authState is! AuthenticatedState) {
269 _showError('Authentication required');
270 return;
271 }
272
273 setState(() {
274 isCheckingIn = true;
275 errorMessage = null;
276 });
277
278 try {
279 final success = await _checkInService.saveCheckInStatus(
280 vehicleId: assignedVehicle!.vehicleId,
281 immatriculation: assignedVehicle!.immatriculation,
282 driverId: authState.session.uid ?? 0,
283 );
284
285 if (success) {
286 if (mounted) {
287 // Check schedule status after successful check-in
288 final now = DateTime.now();
289 final dateString = '${now.day.toString().padLeft(2, '0')}/${now.month.toString().padLeft(2, '0')}/${now.year}';
290 context.read<HomeBloc>().add(LoadScheduleStatusEvent(
291 driverId: authState.session.uid ?? 0,
292 date: dateString,
293 ));
294 }
295 } else {
296 _showError('Failed to check in. Please ensure location services are enabled and try again.');
297 }
298 } catch (e) {
299 _showError('Check-in failed: ${e.toString()}');
300 } finally {
301 if (mounted) {
302 setState(() {
303 isCheckingIn = false;
304 });
305 }
306 }
307 }
308
310 setState(() {
312 });
313
314 ScaffoldMessenger.of(context).showSnackBar(
315 SnackBar(
316 content: Text(message),
317 backgroundColor: Colors.red,
318 duration: const Duration(seconds: 3),
319 ),
320 );
321 }
322
324 return Shimmer.fromColors(
325 baseColor: Colors.grey[300]!,
326 highlightColor: Colors.grey[100]!,
327 child: Container(
328 height: 80,
329 decoration: BoxDecoration(
330 color: Colors.white,
331 borderRadius: BorderRadius.circular(16),
332 ),
333 ),
334 );
335 }
336
338 return Container(
339 decoration: BoxDecoration(
340 color: Colors.white,
341 borderRadius: BorderRadius.circular(16),
342 boxShadow: [
343 BoxShadow(
344 color: Colors.black.withValues(alpha: 0.05),
345 blurRadius: 10,
346 offset: const Offset(0, 2),
347 ),
348 ],
349 ),
350 child: Padding(
351 padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
352 child: Column(
353 crossAxisAlignment: CrossAxisAlignment.start,
354 children: [
355 Row(
356 children: [
357 const Icon(Icons.error_outline, color: Colors.red, size: 18),
358 const SizedBox(width: 8),
359 Expanded(
360 child: Text(
361 'Error loading assigned vehicle',
362 style: const TextStyle(
363 color: Colors.red,
364 fontWeight: FontWeight.w500,
365 ),
366 overflow: TextOverflow.ellipsis,
367 ),
368 ),
369 ],
370 ),
371 if (errorMessage.isNotEmpty) ...[
372 const SizedBox(height: 4),
373 Text(
375 style: TextStyle(
376 color: Colors.grey[600],
377 fontSize: 14,
378 ),
379 maxLines: 2,
380 overflow: TextOverflow.ellipsis,
381 ),
382 ],
383 const SizedBox(height: 8),
384 Align(
385 alignment: Alignment.centerRight,
386 child: TextButton(
387 onPressed: () {
388 final authState = context.read<AuthenticationBloc>().state;
389 if (authState is AuthenticatedState) {
390 _loadAssignedVehicle(authState);
391 }
392 },
393 style: TextButton.styleFrom(
394 padding:
395 const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
396 minimumSize: Size.zero,
397 ),
398 child: const Text('Retry'),
399 ),
400 ),
401 ],
402 ),
403 ),
404 );
405 }
406
408 return Container(
409 decoration: BoxDecoration(
410 color: Colors.white,
411 borderRadius: BorderRadius.circular(16),
412 boxShadow: [
413 BoxShadow(
414 color: Colors.black.withValues(alpha: 0.05),
415 blurRadius: 10,
416 offset: const Offset(0, 2),
417 ),
418 ],
419 ),
420 child: Padding(
421 padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
422 child: Row(
423 children: [
424 Icon(Icons.car_rental, color: Colors.grey[400]),
425 const SizedBox(width: 8),
426 Expanded(
427 child: Text(
428 'No vehicle assigned to you',
429 style: TextStyle(
430 color: Colors.grey[400],
431 fontSize: 16,
432 fontWeight: FontWeight.w400,
433 ),
434 overflow: TextOverflow.ellipsis,
435 ),
436 ),
437 ],
438 ),
439 ),
440 );
441 }
442}
override void initState()
class App extends StatefulWidget build(BuildContext context)
Definition app.dart:31
const AuthenticationFailureState({required this.failure})
sealed class CheckInOutEvent extends Equatable userId
String errorMessage
void _performCheckIn() async
Future< void > _loadAssignedVehicle(AuthenticatedState authState) async
bool isLoading
Widget _buildVehicleDisplay()
Widget _buildAssignedVehicleDisplay(CheckInStatusModel vehicle)
final CheckInService _checkInService
class CheckInScreen extends StatefulWidget assignedVehicle
Widget _buildErrorDisplay(String errorMessage)
Widget _buildNoVehicleDisplay()
Widget _buildLoadingDisplay()
bool isCheckingIn
void _showError(String message)
static const String aidraLogo
Definition assets.dart:15
static const String environmentalEarth
Definition assets.dart:14
static const lightGreen
static const antiFlashWhite
const CheckInScreen({super.key})
override State< CheckInScreen > createState()
final Widget child
final EdgeInsets padding
class Partner String
final Color color
Definition failures.dart:1
final String message
Definition failures.dart:0
const LoadScheduleStatusEvent({ required this.driverId, required this.date, })
final String date
const ScheduleStatusLoaded({required this.status})
final VoidCallback onPressed
Routes
Definition routes.dart:30
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,),),),],)