perf: optimization des rebuilds (ValueNotifier pour calendrier/container_form, Selector pour pages de gestion et mon compte)
This commit is contained in:
@@ -51,7 +51,7 @@ class _CalendarPageState extends State<CalendarPage> {
|
|||||||
int _searchRequestId = 0;
|
int _searchRequestId = 0;
|
||||||
bool _isMobileSearchVisible = false;
|
bool _isMobileSearchVisible = false;
|
||||||
bool _isRefreshing = false;
|
bool _isRefreshing = false;
|
||||||
double _detailsPaneFraction = 0.35;
|
final ValueNotifier<double> _detailsPaneFraction = ValueNotifier<double>(0.35);
|
||||||
String? _lastLoadedUserId;
|
String? _lastLoadedUserId;
|
||||||
bool _initialLoadScheduled = false;
|
bool _initialLoadScheduled = false;
|
||||||
|
|
||||||
@@ -207,6 +207,7 @@ class _CalendarPageState extends State<CalendarPage> {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
_searchDebounce?.cancel();
|
_searchDebounce?.cancel();
|
||||||
_searchController.dispose();
|
_searchController.dispose();
|
||||||
|
_detailsPaneFraction.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -817,12 +818,10 @@ class _CalendarPageState extends State<CalendarPage> {
|
|||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
onHorizontalDragUpdate: (details) {
|
onHorizontalDragUpdate: (details) {
|
||||||
setState(() {
|
_detailsPaneFraction.value = _clampDetailsPaneFraction(
|
||||||
_detailsPaneFraction = _clampDetailsPaneFraction(
|
_detailsPaneFraction.value - (details.delta.dx / totalWidth),
|
||||||
_detailsPaneFraction - (details.delta.dx / totalWidth),
|
|
||||||
totalWidth,
|
totalWidth,
|
||||||
);
|
);
|
||||||
});
|
|
||||||
},
|
},
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: _desktopResizeHandleWidth,
|
width: _desktopResizeHandleWidth,
|
||||||
@@ -935,8 +934,11 @@ class _CalendarPageState extends State<CalendarPage> {
|
|||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
final totalWidth = constraints.maxWidth;
|
final totalWidth = constraints.maxWidth;
|
||||||
|
return ValueListenableBuilder<double>(
|
||||||
|
valueListenable: _detailsPaneFraction,
|
||||||
|
builder: (context, fraction, child) {
|
||||||
final detailsPaneFraction =
|
final detailsPaneFraction =
|
||||||
_clampDetailsPaneFraction(_detailsPaneFraction, totalWidth);
|
_clampDetailsPaneFraction(fraction, totalWidth);
|
||||||
final detailsWidth = totalWidth * detailsPaneFraction;
|
final detailsWidth = totalWidth * detailsPaneFraction;
|
||||||
final calendarWidth =
|
final calendarWidth =
|
||||||
totalWidth - _desktopResizeHandleWidth - detailsWidth;
|
totalWidth - _desktopResizeHandleWidth - detailsWidth;
|
||||||
@@ -957,6 +959,8 @@ class _CalendarPageState extends State<CalendarPage> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMobileLayout(List<EventModel> filteredEvents) {
|
Widget _buildMobileLayout(List<EventModel> filteredEvents) {
|
||||||
@@ -1194,7 +1198,7 @@ class _CalendarPageState extends State<CalendarPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!hasEvents)
|
if (!hasEvents)
|
||||||
Center(
|
const Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Aucun événement ne démarre à cette date'),
|
'Aucun événement ne démarre à cette date'),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
// Form fields
|
// Form fields
|
||||||
ContainerType _selectedType = ContainerType.flightCase;
|
ContainerType _selectedType = ContainerType.flightCase;
|
||||||
EquipmentStatus _selectedStatus = EquipmentStatus.available;
|
EquipmentStatus _selectedStatus = EquipmentStatus.available;
|
||||||
bool _autoGenerateId = true;
|
final ValueNotifier<bool> _autoGenerateIdNotifier = ValueNotifier<bool>(true);
|
||||||
final Set<String> _selectedEquipmentIds = {};
|
final Set<String> _selectedEquipmentIds = {};
|
||||||
|
|
||||||
bool _isEditing = false;
|
bool _isEditing = false;
|
||||||
@@ -61,11 +61,11 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
_heightController.text = container.height?.toString() ?? '';
|
_heightController.text = container.height?.toString() ?? '';
|
||||||
_notesController.text = container.notes ?? '';
|
_notesController.text = container.notes ?? '';
|
||||||
_selectedEquipmentIds.addAll(container.equipmentIds);
|
_selectedEquipmentIds.addAll(container.equipmentIds);
|
||||||
_autoGenerateId = false;
|
_autoGenerateIdNotifier.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateIdFromName() {
|
void _updateIdFromName() {
|
||||||
if (_autoGenerateId && !_isEditing) {
|
if (_autoGenerateIdNotifier.value && !_isEditing) {
|
||||||
final name = _nameController.text;
|
final name = _nameController.text;
|
||||||
if (name.isNotEmpty) {
|
if (name.isNotEmpty) {
|
||||||
final baseId = IdGenerator.generateContainerId(
|
final baseId = IdGenerator.generateContainerId(
|
||||||
@@ -78,7 +78,7 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _updateIdFromType() {
|
void _updateIdFromType() {
|
||||||
if (_autoGenerateId && !_isEditing) {
|
if (_autoGenerateIdNotifier.value && !_isEditing) {
|
||||||
final name = _nameController.text;
|
final name = _nameController.text;
|
||||||
if (name.isNotEmpty) {
|
if (name.isNotEmpty) {
|
||||||
final baseId = IdGenerator.generateContainerId(
|
final baseId = IdGenerator.generateContainerId(
|
||||||
@@ -123,7 +123,10 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// ID
|
// ID
|
||||||
Row(
|
ValueListenableBuilder<bool>(
|
||||||
|
valueListenable: _autoGenerateIdNotifier,
|
||||||
|
builder: (context, autoGenerateId, child) {
|
||||||
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -135,7 +138,7 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
prefixIcon: Icon(Icons.qr_code),
|
prefixIcon: Icon(Icons.qr_code),
|
||||||
),
|
),
|
||||||
enabled: !_autoGenerateId || _isEditing,
|
enabled: !autoGenerateId || _isEditing,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'Veuillez entrer un identifiant';
|
return 'Veuillez entrer un identifiant';
|
||||||
@@ -149,23 +152,23 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
_autoGenerateId ? Icons.lock : Icons.lock_open,
|
autoGenerateId ? Icons.lock : Icons.lock_open,
|
||||||
color: _autoGenerateId ? AppColors.rouge : Colors.grey,
|
color: autoGenerateId ? AppColors.rouge : Colors.grey,
|
||||||
),
|
),
|
||||||
tooltip: _autoGenerateId
|
tooltip: autoGenerateId
|
||||||
? 'Génération automatique'
|
? 'Génération automatique'
|
||||||
: 'Saisie manuelle',
|
: 'Saisie manuelle',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
_autoGenerateIdNotifier.value = !autoGenerateId;
|
||||||
_autoGenerateId = !_autoGenerateId;
|
if (_autoGenerateIdNotifier.value) {
|
||||||
if (_autoGenerateId) {
|
|
||||||
_updateIdFromName();
|
_updateIdFromName();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
@@ -632,6 +635,7 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
_widthController.dispose();
|
_widthController.dispose();
|
||||||
_heightController.dispose();
|
_heightController.dispose();
|
||||||
_notesController.dispose();
|
_notesController.dispose();
|
||||||
|
_autoGenerateIdNotifier.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ class _EquipmentManagementPageState extends State<EquipmentManagementPage>
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: CustomAppBar(
|
: const CustomAppBar(
|
||||||
title: 'Gestion du matériel',
|
title: 'Gestion du matériel',
|
||||||
),
|
),
|
||||||
drawer: const MainDrawer(currentPage: '/equipment_management'),
|
drawer: const MainDrawer(currentPage: '/equipment_management'),
|
||||||
|
|||||||
@@ -75,14 +75,15 @@ class _MaintenanceManagementPageState extends State<MaintenanceManagementPage> {
|
|||||||
title: 'Gestion des maintenances',
|
title: 'Gestion des maintenances',
|
||||||
),
|
),
|
||||||
drawer: const MainDrawer(currentPage: '/maintenance_management'),
|
drawer: const MainDrawer(currentPage: '/maintenance_management'),
|
||||||
body: Consumer<MaintenanceProvider>(
|
body: Selector<MaintenanceProvider, ({bool isLoading, List<MaintenanceModel> maintenances})>(
|
||||||
builder: (context, maintenanceProvider, _) {
|
selector: (context, provider) => (isLoading: provider.isLoading, maintenances: provider.maintenances),
|
||||||
if (maintenanceProvider.isLoading) {
|
builder: (context, data, _) {
|
||||||
|
if (data.isLoading) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
}
|
}
|
||||||
|
|
||||||
final filteredMaintenances = _getFilteredMaintenances(
|
final filteredMaintenances = _getFilteredMaintenances(
|
||||||
maintenanceProvider.maintenances,
|
data.maintenances,
|
||||||
);
|
);
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
@@ -91,7 +92,7 @@ class _MaintenanceManagementPageState extends State<MaintenanceManagementPage> {
|
|||||||
_buildFilterChips(),
|
_buildFilterChips(),
|
||||||
|
|
||||||
// Statistiques
|
// Statistiques
|
||||||
_buildStatsCards(maintenanceProvider),
|
_buildStatsCards(data.maintenances),
|
||||||
|
|
||||||
// Liste des maintenances
|
// Liste des maintenances
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -148,10 +149,10 @@ class _MaintenanceManagementPageState extends State<MaintenanceManagementPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStatsCards(MaintenanceProvider provider) {
|
Widget _buildStatsCards(List<MaintenanceModel> maintenances) {
|
||||||
final upcoming = provider.maintenances.where((m) => !m.isCompleted && !m.isOverdue).length;
|
final upcoming = maintenances.where((m) => !m.isCompleted && !m.isOverdue).length;
|
||||||
final overdue = provider.maintenances.where((m) => m.isOverdue).length;
|
final overdue = maintenances.where((m) => m.isOverdue).length;
|
||||||
final completed = provider.maintenances.where((m) => m.isCompleted).length;
|
final completed = maintenances.where((m) => m.isCompleted).length;
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
|||||||
@@ -17,10 +17,9 @@ class MyAccountPage extends StatelessWidget {
|
|||||||
title: 'Mon compte',
|
title: 'Mon compte',
|
||||||
),
|
),
|
||||||
drawer: const MainDrawer(currentPage: '/my_account'),
|
drawer: const MainDrawer(currentPage: '/my_account'),
|
||||||
body: Consumer<LocalUserProvider>(
|
body: Selector<LocalUserProvider, UserModel?>(
|
||||||
builder: (context, userProvider, child) {
|
selector: (context, provider) => provider.currentUser,
|
||||||
final user = userProvider.currentUser;
|
builder: (context, user, child) {
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
}
|
}
|
||||||
@@ -73,7 +72,7 @@ class MyAccountPage extends StatelessWidget {
|
|||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
userProvider.updateUserData(
|
context.read<LocalUserProvider>().updateUserData(
|
||||||
firstName: firstNameController.text,
|
firstName: firstNameController.text,
|
||||||
lastName: lastNameController.text,
|
lastName: lastNameController.text,
|
||||||
phoneNumber: phoneController.text,
|
phoneNumber: phoneController.text,
|
||||||
|
|||||||
@@ -51,12 +51,13 @@ class _UserManagementPageState extends State<UserManagementPage> {
|
|||||||
title: 'Gestion des utilisateurs',
|
title: 'Gestion des utilisateurs',
|
||||||
),
|
),
|
||||||
drawer: const MainDrawer(currentPage: '/account_management'),
|
drawer: const MainDrawer(currentPage: '/account_management'),
|
||||||
body: Consumer<UsersProvider>(
|
body: Selector<UsersProvider, ({bool isLoading, List<UserModel> users})>(
|
||||||
builder: (context, usersProvider, child) {
|
selector: (context, provider) => (isLoading: provider.isLoading, users: provider.users),
|
||||||
if (usersProvider.isLoading) {
|
builder: (context, data, child) {
|
||||||
|
if (data.isLoading) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
}
|
}
|
||||||
final users = usersProvider.users;
|
final users = data.users;
|
||||||
if (users.isEmpty) {
|
if (users.isEmpty) {
|
||||||
return const Center(child: Text("Aucun utilisateur trouvé"));
|
return const Center(child: Text("Aucun utilisateur trouvé"));
|
||||||
}
|
}
|
||||||
@@ -92,7 +93,7 @@ class _UserManagementPageState extends State<UserManagementPage> {
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (_) => EditUserDialog(user: user)),
|
builder: (_) => EditUserDialog(user: user)),
|
||||||
onResetPassword: () => _resetPassword(context, user),
|
onResetPassword: () => _resetPassword(context, user),
|
||||||
onDelete: () => _confirmDeleteUser(context, usersProvider, user),
|
onDelete: () => _confirmDeleteUser(context, context.read<UsersProvider>(), user),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user