import 'package:flutter/material.dart'; /// A widget that displays a grid of Material icons for selection. /// /// Shows a button that opens a dialog with available icons. class IconPicker extends StatelessWidget { const IconPicker({ super.key, required this.selectedIcon, required this.onChanged, this.label = 'Icon', }); /// Currently selected icon name. final String selectedIcon; /// Callback when an icon is selected. final ValueChanged onChanged; /// Label for the field. final String label; @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final textTheme = Theme.of(context).textTheme; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: textTheme.labelMedium?.copyWith( color: colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 8), InkWell( onTap: () => _showIconPicker(context), borderRadius: BorderRadius.circular(8), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( border: Border.all(color: colorScheme.outline), borderRadius: BorderRadius.circular(8), ), child: Row( children: [ Container( width: 40, height: 40, decoration: BoxDecoration( color: colorScheme.primaryContainer, borderRadius: BorderRadius.circular(8), ), child: Icon( getIconData(selectedIcon), color: colorScheme.onPrimaryContainer, ), ), const SizedBox(width: 12), Expanded( child: Text( selectedIcon, style: textTheme.bodyLarge, ), ), Icon( Icons.arrow_drop_down, color: colorScheme.onSurfaceVariant, ), ], ), ), ), ], ); } Future _showIconPicker(BuildContext context) async { final result = await showDialog( context: context, builder: (context) => IconPickerDialog( selectedIcon: selectedIcon, onSelected: (icon) => Navigator.of(context).pop(icon), ), ); if (result != null) { onChanged(result); } } } /// Dialog that displays a grid of icons. class IconPickerDialog extends StatefulWidget { const IconPickerDialog({ super.key, required this.selectedIcon, required this.onSelected, }); final String selectedIcon; final ValueChanged onSelected; @override State createState() => _IconPickerDialogState(); } class _IconPickerDialogState extends State { String _searchQuery = ''; List get _filteredIcons { if (_searchQuery.isEmpty) { return availableIcons; } return availableIcons .where((icon) => icon.toLowerCase().contains(_searchQuery.toLowerCase())) .toList(); } @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Dialog( child: Container( width: 400, height: 500, padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Select Icon', style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 16), TextField( decoration: const InputDecoration( hintText: 'Search icons...', prefixIcon: Icon(Icons.search), border: OutlineInputBorder(), isDense: true, ), onChanged: (value) => setState(() => _searchQuery = value), ), const SizedBox(height: 16), Expanded( child: GridView.builder( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 5, mainAxisSpacing: 8, crossAxisSpacing: 8, ), itemCount: _filteredIcons.length, itemBuilder: (context, index) { final iconName = _filteredIcons[index]; final isSelected = iconName == widget.selectedIcon; return InkWell( onTap: () => widget.onSelected(iconName), borderRadius: BorderRadius.circular(8), child: Container( decoration: BoxDecoration( color: isSelected ? colorScheme.primaryContainer : colorScheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(8), border: isSelected ? Border.all(color: colorScheme.primary, width: 2) : null, ), child: Tooltip( message: iconName, child: Icon( getIconData(iconName), color: isSelected ? colorScheme.onPrimaryContainer : colorScheme.onSurface, ), ), ), ); }, ), ), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Cancel'), ), ], ), ], ), ), ); } } /// Common icons available for selection. const List availableIcons = [ 'home', 'settings', 'search', 'menu', 'add', 'remove', 'close', 'check', 'edit', 'delete', 'favorite', 'star', 'movie', 'music_note', 'photo', 'videocam', 'camera', 'mic', 'volume_up', 'play_arrow', 'pause', 'stop', 'skip_next', 'skip_previous', 'folder', 'file_copy', 'cloud', 'cloud_download', 'cloud_upload', 'download', 'upload', 'share', 'link', 'public', 'language', 'dns', 'storage', 'memory', 'code', 'terminal', 'bug_report', 'api', 'http', 'vpn_key', 'lock', 'lock_open', 'security', 'verified_user', 'admin_panel_settings', 'monitor', 'monitoring', 'analytics', 'dashboard', 'speed', 'timer', 'schedule', 'calendar_today', 'event', 'notifications', 'email', 'message', 'chat', 'forum', 'person', 'people', 'group', 'account_circle', 'shopping_cart', 'credit_card', 'attach_money', 'trending_up', 'trending_down', 'wifi', 'bluetooth', 'router', 'devices', 'computer', 'laptop', 'phone_android', 'tablet', 'watch', 'tv', 'games', 'videogame_asset', 'sports_esports', 'local_cafe', 'local_dining', 'restaurant', 'directions_car', 'flight', 'hotel', 'map', 'place', 'explore', 'navigation', 'book', 'school', 'science', 'psychology', 'work', 'business', 'apartment', 'location_city', 'eco', 'water_drop', 'air', 'thermostat', 'bolt', 'light_mode', 'dark_mode', 'brightness_4', 'palette', 'brush', 'format_paint', 'extension', 'widgets', 'view_module', 'grid_view', 'list', 'table_chart', 'pie_chart', 'bar_chart', 'show_chart', 'donut_large', 'disc_full', ]; /// Convert icon name string to IconData. IconData getIconData(String iconName) { const iconMap = { 'home': Icons.home, 'settings': Icons.settings, 'search': Icons.search, 'menu': Icons.menu, 'add': Icons.add, 'remove': Icons.remove, 'close': Icons.close, 'check': Icons.check, 'edit': Icons.edit, 'delete': Icons.delete, 'favorite': Icons.favorite, 'star': Icons.star, 'movie': Icons.movie, 'music_note': Icons.music_note, 'photo': Icons.photo, 'videocam': Icons.videocam, 'camera': Icons.camera, 'mic': Icons.mic, 'volume_up': Icons.volume_up, 'play_arrow': Icons.play_arrow, 'pause': Icons.pause, 'stop': Icons.stop, 'skip_next': Icons.skip_next, 'skip_previous': Icons.skip_previous, 'folder': Icons.folder, 'file_copy': Icons.file_copy, 'cloud': Icons.cloud, 'cloud_download': Icons.cloud_download, 'cloud_upload': Icons.cloud_upload, 'download': Icons.download, 'upload': Icons.upload, 'share': Icons.share, 'link': Icons.link, 'public': Icons.public, 'language': Icons.language, 'dns': Icons.dns, 'storage': Icons.storage, 'memory': Icons.memory, 'code': Icons.code, 'terminal': Icons.terminal, 'bug_report': Icons.bug_report, 'api': Icons.api, 'http': Icons.http, 'vpn_key': Icons.vpn_key, 'lock': Icons.lock, 'lock_open': Icons.lock_open, 'security': Icons.security, 'verified_user': Icons.verified_user, 'admin_panel_settings': Icons.admin_panel_settings, 'monitor': Icons.monitor, 'monitoring': Icons.monitor_heart, 'analytics': Icons.analytics, 'dashboard': Icons.dashboard, 'speed': Icons.speed, 'timer': Icons.timer, 'schedule': Icons.schedule, 'calendar_today': Icons.calendar_today, 'event': Icons.event, 'notifications': Icons.notifications, 'email': Icons.email, 'message': Icons.message, 'chat': Icons.chat, 'forum': Icons.forum, 'person': Icons.person, 'people': Icons.people, 'group': Icons.group, 'account_circle': Icons.account_circle, 'shopping_cart': Icons.shopping_cart, 'credit_card': Icons.credit_card, 'attach_money': Icons.attach_money, 'trending_up': Icons.trending_up, 'trending_down': Icons.trending_down, 'wifi': Icons.wifi, 'bluetooth': Icons.bluetooth, 'router': Icons.router, 'devices': Icons.devices, 'computer': Icons.computer, 'laptop': Icons.laptop, 'phone_android': Icons.phone_android, 'tablet': Icons.tablet, 'watch': Icons.watch, 'tv': Icons.tv, 'games': Icons.games, 'videogame_asset': Icons.videogame_asset, 'sports_esports': Icons.sports_esports, 'local_cafe': Icons.local_cafe, 'local_dining': Icons.local_dining, 'restaurant': Icons.restaurant, 'directions_car': Icons.directions_car, 'flight': Icons.flight, 'hotel': Icons.hotel, 'map': Icons.map, 'place': Icons.place, 'explore': Icons.explore, 'navigation': Icons.navigation, 'book': Icons.book, 'school': Icons.school, 'science': Icons.science, 'psychology': Icons.psychology, 'work': Icons.work, 'business': Icons.business, 'apartment': Icons.apartment, 'location_city': Icons.location_city, 'eco': Icons.eco, 'water_drop': Icons.water_drop, 'air': Icons.air, 'thermostat': Icons.thermostat, 'bolt': Icons.bolt, 'light_mode': Icons.light_mode, 'dark_mode': Icons.dark_mode, 'brightness_4': Icons.brightness_4, 'palette': Icons.palette, 'brush': Icons.brush, 'format_paint': Icons.format_paint, 'extension': Icons.extension, 'widgets': Icons.widgets, 'view_module': Icons.view_module, 'grid_view': Icons.grid_view, 'list': Icons.list, 'table_chart': Icons.table_chart, 'pie_chart': Icons.pie_chart, 'bar_chart': Icons.bar_chart, 'show_chart': Icons.show_chart, 'donut_large': Icons.donut_large, 'disc_full': Icons.disc_full, }; return iconMap[iconName] ?? Icons.help_outline; }