barcode_scanner/lib/components/drawer_component.dart
mandreshope 63d5a21079 feat: Extracts home page drawer into reusable component
- Extracts the complex `Drawer` widget from the `HomePage` into a dedicated `DrawerComponent`. This enhances modularity, improves code readability, and allows for easier reuse of the navigation drawer across the application.
- Updates iOS project configuration files (`project.pbxproj` and `contents.xcworkspacedata`) to properly integrate CocoaPods dependencies. This typically occurs after running `pod install` and includes adding Pods frameworks, build phases, and xcconfig references.
- Updates the Flutter SDK path in VS Code settings to a newer version.
2025-07-23 16:21:59 +03:00

270 lines
8.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_riverpod/flutter_riverpod.dart';
class DrawerComponent extends ConsumerStatefulWidget {
const DrawerComponent({
super.key,
this.isOperationExpanded = true,
this.isSettingsExpanded = false,
this.selectedMenuIndex = 0,
this.selectedSubMenuIndex = 0,
});
final bool isOperationExpanded;
final bool isSettingsExpanded;
final int selectedMenuIndex;
final int selectedSubMenuIndex;
@override
ConsumerState<DrawerComponent> createState() => _DrawerComponentState();
}
class _DrawerComponentState extends ConsumerState<DrawerComponent> {
bool _isOperationExpanded = false;
bool _isSettingsExpanded = false;
@override
void initState() {
super.initState();
_isOperationExpanded = widget.isOperationExpanded;
_isSettingsExpanded = widget.isSettingsExpanded;
}
@override
Widget build(BuildContext context) {
return Drawer(
backgroundColor: AppTheme.of(context).primaryBackground,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
child: Column(
children: [
const SizedBox(height: 50),
// === Profil utilisateur
Consumer(
builder: (context, ref, child) {
final state = ref.watch(homePageModelProvider);
return ListTile(
onTap: () => ProfileRoute().push(context),
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,
),
);
},
),
const Divider(),
// === ExpansionTile Opérations
_ExpansionTileComponent(
leadingIcon: Icons.inbox,
isExpanded: _isOperationExpanded,
onExpansionChanged: (expanded) {
setState(() => _isOperationExpanded = expanded);
},
title: 'Opérations',
isActive: widget.selectedMenuIndex == 0,
children: [
_ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
leadingIcon: Icons.move_to_inbox,
isActive: widget.selectedSubMenuIndex == 0,
title: 'Réceptions',
),
_ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
leadingIcon: Icons.local_shipping,
title: 'Livraisons',
isActive: widget.selectedSubMenuIndex == 1,
),
_ListTile(
onTap: () {
Navigator.of(context).pop();
ProductListRoute().push(context);
},
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
leadingIcon: Icons.inventory,
title: 'Inventaires',
isActive: widget.selectedSubMenuIndex == 2,
),
],
),
// === Produits
_ListTile(
contentPadding: const EdgeInsetsDirectional.symmetric(
horizontal: 10,
),
leadingIcon: Icons.insert_chart,
title: "Produits",
isActive: widget.selectedMenuIndex == 1,
trailing: const Icon(Icons.keyboard_arrow_right),
),
// === Historique
_ListTile(
contentPadding: const EdgeInsetsDirectional.symmetric(
horizontal: 10,
),
leadingIcon: Icons.history,
title: "Historiques",
trailing: const Icon(Icons.keyboard_arrow_right),
isActive: widget.selectedMenuIndex == 2,
),
// === ExpansionTile Paramètres
_ExpansionTileComponent(
isActive: widget.selectedMenuIndex == 3,
isExpanded: _isSettingsExpanded,
onExpansionChanged: (expanded) {
setState(() => _isSettingsExpanded = expanded);
},
leadingIcon: Icons.settings,
title: "Paramètres",
children: [
_ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
leadingIcon: Icons.lock_open,
title: 'Connexion Odoo',
isActive: widget.selectedSubMenuIndex == 3,
),
_ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
leadingIcon: Icons.group,
title: 'Gestion des utilisateurs',
isActive: widget.selectedSubMenuIndex == 4,
),
],
),
const Spacer(),
// === Déconnexion
SafeArea(
child: ListTile(
onTap: () async {
await ref.read(loginPageModelProvider.notifier).logOut();
await UserStruct(id: '1').deleteLocalStorage();
WidgetsBinding.instance.addPostFrameCallback((_) {
SplashRoute().go(context);
});
},
leading: const Icon(Icons.logout),
title: Text(
'Se déconnecter',
style: AppTheme.of(context).bodyLarge,
),
),
),
],
),
),
);
}
}
class _ListTile extends StatelessWidget {
const _ListTile({
Key? key,
required this.title,
this.isActive = false,
this.onTap,
this.leadingIcon,
this.contentPadding,
this.trailing,
}) : super(key: key);
final bool isActive;
final String title;
final VoidCallback? onTap;
final IconData? leadingIcon;
final EdgeInsetsGeometry? contentPadding;
final Widget? trailing;
@override
Widget build(BuildContext context) {
return ListTile(
onTap: onTap,
contentPadding: contentPadding,
leading: Icon(
leadingIcon,
color: isActive ? AppTheme.of(context).primary : null,
),
title: Text(
title,
style: AppTheme.of(context).bodyLarge.copyWith(
color: isActive ? AppTheme.of(context).primary : null,
),
),
trailing: trailing,
);
}
}
class _ExpansionTileComponent extends StatelessWidget {
const _ExpansionTileComponent({
required this.title,
this.isExpanded = false,
this.onExpansionChanged,
this.isActive = false,
this.children = const <Widget>[],
this.leadingIcon,
});
final bool isExpanded;
final void Function(bool)? onExpansionChanged;
final bool isActive;
final List<Widget> children;
final String title;
final IconData? leadingIcon;
@override
Widget build(BuildContext context) {
return ExpansionTile(
initiallyExpanded: isExpanded,
onExpansionChanged: onExpansionChanged,
tilePadding: const EdgeInsetsDirectional.symmetric(horizontal: 10),
shape: LinearBorder.none,
title: Row(
children: [
Icon(
leadingIcon,
color: isActive ? AppTheme.of(context).primary : null,
),
const SizedBox(width: 12),
Expanded(
child: Text(
title,
style: AppTheme.of(context).bodyLarge.copyWith(
color: isActive ? AppTheme.of(context).primary : null,
),
),
),
],
),
trailing: Icon(
isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_right,
),
children: children,
);
}
}