mandreshope b1a4005235 feat: Adds user image field and profile page
Adds an `image` field to the user data structure to support profile pictures.

Introduces a new profile page and sets up navigation from the home screen.

Changes the product list page provider to auto dispose for improved resource management.
2025-07-04 12:17:13 +03:00

228 lines
7.6 KiB
Dart

import 'package:barcode_scanner/backend/schema/user/user_struct.dart';
import 'package:barcode_scanner/pages/home_page/home_page_model.dart';
import 'package:barcode_scanner/pages/login_page/login_page_model.dart';
import 'package:barcode_scanner/router/go_router_builder.dart';
import 'package:barcode_scanner/router/go_secure_router_builder.dart';
import 'package:barcode_scanner/themes/app_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class HomePage extends ConsumerStatefulWidget {
const HomePage({super.key});
@override
ConsumerState<ConsumerStatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends ConsumerState<HomePage> {
@override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
ref.read(homePageModelProvider.notifier).getUserConnected();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(
backgroundColor: AppTheme.of(context).primaryBackground,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
child: Column(
children: [
SizedBox(height: 50),
Consumer(
builder: (context, ref, child) {
final state = ref.watch(homePageModelProvider);
return ListTile(
contentPadding: EdgeInsets.zero,
leading: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: AppTheme.of(context).secondaryBackground,
borderRadius: BorderRadius.circular(60),
),
),
title: Text(
state.user?.fullName ?? '',
style: AppTheme.of(context).titleMedium,
),
subtitle: Text(
state.user?.email ?? '',
style: AppTheme.of(context).bodyMedium,
),
);
},
),
Divider(),
ListTile(
onTap: () {
ProfileRoute().push(context);
},
leading: Icon(Icons.person),
title: Text(
'Mon Profil',
style: AppTheme.of(context).bodyLarge,
),
),
ListTile(
onTap: () {
Navigator.of(context).pop();
ProductListRoute().push(context);
},
leading: Icon(Icons.inventory),
title: Text(
'Inventaire',
style: AppTheme.of(context).bodyLarge,
),
),
Spacer(),
SafeArea(
child: ListTile(
onTap: () async {
await ref.read(loginPageModelProvider.notifier).logOut();
await UserStruct(id: '1').deleteLocalStorage();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
SplashRoute().go(context);
});
},
leading: Icon(Icons.logout),
title: Text(
'Se deconnecter',
style: AppTheme.of(context).bodyLarge,
),
),
),
],
),
),
),
backgroundColor: AppTheme.of(context).primaryBackground,
appBar: AppBar(
title: Text('Barcode Scanner', style: AppTheme.of(context).titleLarge),
centerTitle: true,
backgroundColor: AppTheme.of(context).primaryBackground,
actions: [],
),
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
/// HEADER ICON
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: AppTheme.of(context).primary,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Color(0x225F3DFF),
blurRadius: 20,
offset: Offset(0, 12),
),
],
),
child: const Center(
child: Icon(
Icons.qr_code_scanner_rounded,
color: Colors.white,
size: 50,
),
),
),
const SizedBox(height: 24),
/// TITLE
const Text(
'Barcode Scanner',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
/// SUBTITLE
const Text(
'Scannez facilement tous vos code barre\nen quelques secondes',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16, color: Colors.grey),
),
const SizedBox(height: 36),
/// SCANNER PREVIEW AREA (placeholder)
Container(
width: 260,
height: 200,
padding: const EdgeInsets.all(40),
decoration: BoxDecoration(
color: AppTheme.of(context).alternate,
borderRadius: BorderRadius.circular(24),
boxShadow: const [
BoxShadow(
color: Color(0x11000000),
blurRadius: 10,
offset: Offset(0, 8),
),
],
),
child: Icon(
Icons.qr_code_2_rounded,
size: 60,
color: AppTheme.of(context).primaryText,
),
),
const SizedBox(height: 16),
const Text(
'Pointez votre caméra vers le code\nbarre',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey),
),
const SizedBox(height: 40),
/// START BUTTON
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: () {
ScannerRoute().push(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.of(context).primary,
padding: const EdgeInsets.symmetric(vertical: 18),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
icon: const Icon(
Icons.qr_code_scanner_rounded,
color: Colors.white,
size: 30,
),
label: const Text(
'Commencer le scan',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
),
],
),
),
),
);
}
}