1import 'package:easy_localization/easy_localization.dart';
2import 'package:flutter/material.dart';
3import 'package:flutter_bloc/flutter_bloc.dart';
5import '../../core/api/api_client.dart';
6import '../../core/services/service_locator.dart';
7import '../../core/services/user_info_service.dart';
8import '../../core/ui/theme/color_palette.dart';
9import '../../core/ui/widgets/custom_scaffold.dart';
10import '../../core/ui/widgets/logo_header.dart';
11import '../auth/presentation/bloc/authentication_bloc/authentication_bloc.dart';
12import 'models/document_model.dart';
13import 'screens/pdf_viewer_screen.dart';
14import 'services/document_service.dart';
20 State<ProfileSettingsScreen>
createState() => _ProfileSettingsScreenState();
23class _ProfileSettingsScreenState
extends State<ProfileSettingsScreen> {
39 final authState = context.read<AuthenticationBloc>().state;
40 if (authState is AuthenticatedState) {
42 path:
'dashboardDriver?userId=${authState.session.uid}&period=month',
45 if (response != null && response[
'doneVolume'] != null && mounted) {
47 _engagement = (response[
'doneVolume'] as num).toDouble();
52 print(
'Error loading engagement: $e');
64 final authState = context.read<AuthenticationBloc>().state;
65 if (authState is AuthenticatedState) {
80 print(
'Error loading documents: $e');
85 Widget
build(BuildContext context) {
86 return CustomScaffold(
88 isLeadingVisible:
false,
89 body: SingleChildScrollView(
90 physics:
const BouncingScrollPhysics(),
91 padding:
const EdgeInsets.only(right: 20, left: 20, bottom: 32),
93 crossAxisAlignment: CrossAxisAlignment.start,
95 LogoHeader(
title:
'settings.title'.tr()),
110 padding:
const EdgeInsets.all(20),
111 decoration: BoxDecoration(
112 gradient: LinearGradient(
117 begin: Alignment.topLeft,
118 end: Alignment.bottomRight,
120 borderRadius: BorderRadius.circular(16),
123 color: Colors.black.withValues(alpha: 0.03),
125 offset:
const Offset(0, 4),
132 crossAxisAlignment: CrossAxisAlignment.start,
140 decoration: BoxDecoration(
141 shape: BoxShape.circle,
142 gradient:
const LinearGradient(
144 begin: Alignment.topLeft,
145 end: Alignment.bottomRight,
151 offset:
const Offset(0, 4),
155 padding:
const EdgeInsets.all(2),
156 child:
const CircleAvatar(
159 Icons.person_outline,
171 decoration: BoxDecoration(
173 shape: BoxShape.circle,
180 color: Colors.black.withValues(alpha: 0.1),
182 offset:
const Offset(0, 2),
194 crossAxisAlignment: CrossAxisAlignment.start,
198 style:
const TextStyle(
200 fontWeight: FontWeight.w700,
209 style:
const TextStyle(
221 (index) =>
const Padding(
222 padding: EdgeInsets.only(right: 2),
231 padding: EdgeInsets.only(right: 2),
242 fontWeight: FontWeight.bold,
257 icon:
const Icon(Icons.logout,
color: Colors.white),
259 'settings.sign_out'.tr(),
260 style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
262 style: ElevatedButton.styleFrom(
264 minimumSize:
const Size(
double.infinity, 45),
265 shape: RoundedRectangleBorder(
266 borderRadius: BorderRadius.circular(12),
279 padding:
const EdgeInsets.symmetric(vertical: 20, horizontal: 16),
280 decoration: BoxDecoration(
282 borderRadius: BorderRadius.circular(16),
285 color: Colors.black.withValues(alpha: 0.05),
287 offset:
const Offset(0, 4),
292 mainAxisAlignment: MainAxisAlignment.spaceBetween,
295 icon: Icons.track_changes,
296 title:
'settings.target'.tr(),
302 icon: Icons.attach_money,
303 title:
'settings.balance'.tr(),
309 icon: Icons.people_outline,
310 title:
'settings.engagement'.tr(),
311 value:
'${engagement.toStringAsFixed(0)} KG',
323 color: Colors.grey.withValues(alpha: 0.2),
328 required IconData
icon,
331 required Color
color,
338 padding:
const EdgeInsets.all(12),
339 decoration: BoxDecoration(
341 shape: BoxShape.circle,
346 offset:
const Offset(0, 3),
355 style:
const TextStyle(
363 style:
const TextStyle(
366 fontWeight: FontWeight.bold,
376 crossAxisAlignment: CrossAxisAlignment.start,
380 margin:
const EdgeInsets.only(bottom: 20),
381 padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
382 decoration: BoxDecoration(
384 borderRadius: BorderRadius.circular(12),
393 padding:
const EdgeInsets.all(8),
394 decoration: BoxDecoration(
396 shape: BoxShape.circle,
399 Icons.description_outlined,
406 'settings.documents'.tr(),
409 fontWeight: FontWeight.bold,
420 child: CircularProgressIndicator(
427 'No documents available',
436 physics:
const NeverScrollableScrollPhysics(),
437 gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
439 childAspectRatio: 0.85,
440 crossAxisSpacing: 16,
444 itemBuilder: (context, index) {
445 final document = documents[index];
451 if (document.name.toLowerCase().contains(
'id') ||
452 document.name.toLowerCase().contains(
'personal')) {
453 icon = Icons.badge_outlined;
454 color = ColorPalette.blue;
455 }
else if (document.name.toLowerCase().contains(
'licence') ||
456 document.name.toLowerCase().contains(
'driver')) {
457 icon = Icons.drive_eta_outlined;
458 color = ColorPalette.tiffanyBlue;
459 }
else if (document.name.toLowerCase().contains(
'waybill') ||
460 document.name.toLowerCase().contains(
'naql')) {
461 icon = Icons.receipt_long_outlined;
462 color = ColorPalette.lightGreen;
463 }
else if (document.name.toLowerCase().contains(
'company') ||
464 document.name.toLowerCase().contains(
'authorization')) {
465 icon = Icons.business_outlined;
466 color = ColorPalette.orange;
468 icon = Icons.insert_drive_file_outlined;
469 color = ColorPalette.lightGreen;
473 title: document.name,
478 _openDocument(document, context);
491 builder: (context) => PDFViewerScreen(document: document),
498 required Color
color,
499 required VoidCallback
onTap,
500 IconData
icon = Icons.insert_drive_file_outlined,
502 return GestureDetector(
505 decoration: BoxDecoration(
507 borderRadius: BorderRadius.circular(16),
510 color: Colors.black.withValues(alpha: 0.05),
512 offset:
const Offset(0, 4),
521 mainAxisAlignment: MainAxisAlignment.center,
524 padding:
const EdgeInsets.all(16),
525 decoration: BoxDecoration(
527 shape: BoxShape.circle,
537 padding:
const EdgeInsets.symmetric(horizontal: 8),
540 style:
const TextStyle(
543 fontWeight: FontWeight.w600,
545 textAlign: TextAlign.center,
547 overflow: TextOverflow.ellipsis,
552 padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
553 decoration: BoxDecoration(
555 borderRadius: BorderRadius.circular(12),
562 fontWeight: FontWeight.w500,
573 final bool? confirm = await showDialog<bool>(
575 builder: (BuildContext context) {
578 content:
Text(
'settings.confirm_logout'.tr()),
581 onPressed: () => Navigator.of(context).pop(
false),
585 onPressed: () => Navigator.of(context).pop(
true),
594 if (confirm ==
true) {
595 if (context.mounted) context.read<AuthenticationBloc>().add(SignOutEvent());
override void initState()
class App extends StatefulWidget build(BuildContext context)
static final UserInfoService instance
class DocumentsScreen extends StatefulWidget documents
Widget _buildMetricsRow(double engagement)
Future< void > _fetchDocuments() async
Widget _buildMetricItem({ required IconData icon, required String title, required String value, required Color color, })
Widget _buildProfileHeader()
Future< void > _handleLogout(BuildContext context) async
Future< void > _fetchEngagement() async
Widget _buildDocumentItem({ required String title, required Color color, required VoidCallback onTap, IconData icon=Icons.insert_drive_file_outlined, })
void _openDocument(DocumentModel document, BuildContext context)
class ProfileSettingsScreen extends StatefulWidget _documentService
final ApiClient _apiClient
Widget _buildDocumentsSection(BuildContext context, List< DocumentModel > documents, bool isLoading)
List< DocumentModel > _documents
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,),),),],)