Refactoring - Version OK

This commit is contained in:
dahoud
2025-11-17 16:02:04 +00:00
parent 3f00a26308
commit 3b9ffac8cd
198 changed files with 18010 additions and 11383 deletions

View File

@@ -0,0 +1,321 @@
import 'package:flutter/material.dart';
import '../../../../../shared/design_system/dashboard_theme.dart';
/// Widget de recherche rapide pour le dashboard
class DashboardSearchWidget extends StatefulWidget {
final Function(String)? onSearch;
final String? hintText;
final List<SearchSuggestion>? suggestions;
const DashboardSearchWidget({
super.key,
this.onSearch,
this.hintText,
this.suggestions,
});
@override
State<DashboardSearchWidget> createState() => _DashboardSearchWidgetState();
}
class _DashboardSearchWidgetState extends State<DashboardSearchWidget>
with TickerProviderStateMixin {
final TextEditingController _searchController = TextEditingController();
final FocusNode _focusNode = FocusNode();
late AnimationController _animationController;
late Animation<double> _scaleAnimation;
bool _isExpanded = false;
List<SearchSuggestion> _filteredSuggestions = [];
@override
void initState() {
super.initState();
_setupAnimations();
_setupListeners();
_filteredSuggestions = widget.suggestions ?? _getDefaultSuggestions();
}
void _setupAnimations() {
_animationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_scaleAnimation = Tween<double>(
begin: 1.0,
end: 1.05,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
));
}
void _setupListeners() {
_focusNode.addListener(() {
setState(() {
_isExpanded = _focusNode.hasFocus;
});
if (_focusNode.hasFocus) {
_animationController.forward();
} else {
_animationController.reverse();
}
});
_searchController.addListener(() {
_filterSuggestions(_searchController.text);
});
}
void _filterSuggestions(String query) {
if (query.isEmpty) {
setState(() {
_filteredSuggestions = widget.suggestions ?? _getDefaultSuggestions();
});
return;
}
final filtered = (widget.suggestions ?? _getDefaultSuggestions())
.where((suggestion) =>
suggestion.title.toLowerCase().contains(query.toLowerCase()) ||
suggestion.subtitle.toLowerCase().contains(query.toLowerCase()))
.toList();
setState(() {
_filteredSuggestions = filtered;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
_buildSearchBar(),
if (_isExpanded && _filteredSuggestions.isNotEmpty) ...[
const SizedBox(height: DashboardTheme.spacing8),
_buildSuggestions(),
],
],
);
}
Widget _buildSearchBar() {
return AnimatedBuilder(
animation: _scaleAnimation,
builder: (context, child) {
return Transform.scale(
scale: _scaleAnimation.value,
child: Container(
decoration: BoxDecoration(
color: DashboardTheme.white,
borderRadius: BorderRadius.circular(DashboardTheme.borderRadiusLarge),
boxShadow: _isExpanded ? DashboardTheme.elevatedShadow : DashboardTheme.subtleShadow,
),
child: TextField(
controller: _searchController,
focusNode: _focusNode,
onSubmitted: (value) {
if (value.isNotEmpty) {
widget.onSearch?.call(value);
_focusNode.unfocus();
}
},
decoration: InputDecoration(
hintText: widget.hintText ?? 'Rechercher...',
hintStyle: DashboardTheme.bodyMedium.copyWith(
color: DashboardTheme.grey400,
),
prefixIcon: Icon(
Icons.search,
color: _isExpanded ? DashboardTheme.royalBlue : DashboardTheme.grey400,
),
suffixIcon: _searchController.text.isNotEmpty
? IconButton(
onPressed: () {
_searchController.clear();
_focusNode.unfocus();
},
icon: const Icon(
Icons.clear,
color: DashboardTheme.grey400,
),
)
: null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(DashboardTheme.borderRadiusLarge),
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(DashboardTheme.borderRadiusLarge),
borderSide: const BorderSide(
color: DashboardTheme.royalBlue,
width: 2,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: DashboardTheme.spacing16,
vertical: DashboardTheme.spacing12,
),
filled: true,
fillColor: DashboardTheme.white,
),
style: DashboardTheme.bodyMedium,
),
),
);
},
);
}
Widget _buildSuggestions() {
return Container(
constraints: const BoxConstraints(maxHeight: 300),
decoration: BoxDecoration(
color: DashboardTheme.white,
borderRadius: BorderRadius.circular(DashboardTheme.borderRadius),
boxShadow: DashboardTheme.elevatedShadow,
),
child: ListView.builder(
shrinkWrap: true,
itemCount: _filteredSuggestions.length,
itemBuilder: (context, index) {
final suggestion = _filteredSuggestions[index];
return _buildSuggestionItem(suggestion, index == _filteredSuggestions.length - 1);
},
),
);
}
Widget _buildSuggestionItem(SearchSuggestion suggestion, bool isLast) {
return InkWell(
onTap: () {
_searchController.text = suggestion.title;
widget.onSearch?.call(suggestion.title);
_focusNode.unfocus();
suggestion.onTap?.call();
},
child: Container(
padding: const EdgeInsets.all(DashboardTheme.spacing16),
decoration: BoxDecoration(
border: isLast
? null
: const Border(
bottom: BorderSide(
color: DashboardTheme.grey200,
width: 1,
),
),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(DashboardTheme.spacing8),
decoration: BoxDecoration(
color: suggestion.color.withOpacity(0.1),
borderRadius: BorderRadius.circular(DashboardTheme.borderRadiusSmall),
),
child: Icon(
suggestion.icon,
color: suggestion.color,
size: 20,
),
),
const SizedBox(width: DashboardTheme.spacing12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
suggestion.title,
style: DashboardTheme.bodyMedium.copyWith(
fontWeight: FontWeight.w600,
),
),
if (suggestion.subtitle.isNotEmpty) ...[
const SizedBox(height: DashboardTheme.spacing2),
Text(
suggestion.subtitle,
style: DashboardTheme.bodySmall.copyWith(
color: DashboardTheme.grey600,
),
),
],
],
),
),
const Icon(
Icons.arrow_forward_ios,
color: DashboardTheme.grey400,
size: 16,
),
],
),
),
);
}
List<SearchSuggestion> _getDefaultSuggestions() {
return [
SearchSuggestion(
title: 'Membres',
subtitle: 'Rechercher des membres',
icon: Icons.people,
color: DashboardTheme.royalBlue,
onTap: () {},
),
SearchSuggestion(
title: 'Événements',
subtitle: 'Trouver des événements',
icon: Icons.event,
color: DashboardTheme.tealBlue,
onTap: () {},
),
SearchSuggestion(
title: 'Contributions',
subtitle: 'Historique des paiements',
icon: Icons.payment,
color: DashboardTheme.success,
onTap: () {},
),
SearchSuggestion(
title: 'Rapports',
subtitle: 'Consulter les rapports',
icon: Icons.assessment,
color: DashboardTheme.warning,
onTap: () {},
),
SearchSuggestion(
title: 'Paramètres',
subtitle: 'Configuration système',
icon: Icons.settings,
color: DashboardTheme.grey600,
onTap: () {},
),
];
}
@override
void dispose() {
_searchController.dispose();
_focusNode.dispose();
_animationController.dispose();
super.dispose();
}
}
class SearchSuggestion {
final String title;
final String subtitle;
final IconData icon;
final Color color;
final VoidCallback? onTap;
const SearchSuggestion({
required this.title,
required this.subtitle,
required this.icon,
required this.color,
this.onTap,
});
}