br_ingredientes_icons 2.0.3 copy "br_ingredientes_icons: ^2.0.3" to clipboard
br_ingredientes_icons: ^2.0.3 copied to clipboard

Ícones PNG e busca inteligente de ingredientes para Flutter (brasileiro/multilíngue).

example/lib/main.dart

import 'package:br_ingredientes_icons/ingredientes_data.dart';
import 'package:flutter/material.dart';
import 'package:br_ingredientes_icons/br_ingredientes_icons.dart';

final Map<String, List<String>> ingredientAliasesExemplo = ingredientAliases;

final List<String> todasChavesIcones = ingredientAliasesExemplo.keys.toList()
  ..sort();

void main() {
  runApp(const IngredientesDemoApp());
}

class IngredientesDemoApp extends StatelessWidget {
  const IngredientesDemoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'br_ingredientes_icons Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
          useMaterial3: true,
          colorScheme: ColorScheme.fromSeed(
            seedColor: Colors.orangeAccent,
            brightness: Brightness.light,
          ),
          fontFamily: 'Poppins',
          cardTheme: CardTheme(
            elevation: 2,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(16.0),
            ),
          ),
          inputDecorationTheme: InputDecorationTheme(
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(12.0),
              borderSide: BorderSide.none,
            ),
            filled: true,
            fillColor: Colors.grey[200],
          ),
          appBarTheme: const AppBarTheme(
              elevation: 0,
              backgroundColor: Colors.transparent,
              foregroundColor: Colors.black87,
              centerTitle: true,
              titleTextStyle: TextStyle(
                  fontFamily: 'Poppins',
                  fontSize: 20,
                  fontWeight: FontWeight.w600,
                  color: Colors.black87))),
      darkTheme: ThemeData(
          useMaterial3: true,
          colorScheme: ColorScheme.fromSeed(
            seedColor: Colors.orangeAccent,
            brightness: Brightness.dark,
          ),
          fontFamily: 'Poppins',
          cardTheme: CardTheme(
            elevation: 2,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(16.0),
            ),
          ),
          inputDecorationTheme: InputDecorationTheme(
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(12.0),
              borderSide: BorderSide.none,
            ),
            filled: true,
          ),
          appBarTheme: const AppBarTheme(
              elevation: 0,
              backgroundColor: Colors.transparent,
              centerTitle: true,
              titleTextStyle: TextStyle(
                fontFamily: 'Poppins',
                fontSize: 20,
                fontWeight: FontWeight.w600,
              ))),
      themeMode: ThemeMode.system,
      home: const IngredientesShowcaseScreen(),
    );
  }
}

class IngredientesShowcaseScreen extends StatefulWidget {
  const IngredientesShowcaseScreen({super.key});

  @override
  State<IngredientesShowcaseScreen> createState() =>
      _IngredientesShowcaseScreenState();
}

class _IngredientesShowcaseScreenState
    extends State<IngredientesShowcaseScreen> {
  String _searchTerm = '';
  List<String> _filteredIconKeys = [];
  final TextEditingController _searchController = TextEditingController();

  @override
  void initState() {
    super.initState();
    _filteredIconKeys = [...todasChavesIcones];
  }

  void _filterIcons(String query) {
    final lowerCaseQuery = query.toLowerCase().trim();
    setState(() {
      _searchTerm = lowerCaseQuery;
      if (lowerCaseQuery.isEmpty) {
        _filteredIconKeys = [...todasChavesIcones]; // Já está ordenado
      } else {
        _filteredIconKeys = todasChavesIcones.where((key) {
          final aliases = ingredientAliasesExemplo[key] ?? [];
          final normalizedKey = key.toLowerCase().replaceAll('_', ' ');
          if (normalizedKey.contains(lowerCaseQuery)) return true;
          return aliases
              .any((alias) => alias.toLowerCase().contains(lowerCaseQuery));
        }).toList()
          ..sort(); // Aqui você ordena os filtrados também
      }
    });
  }

  String _formatNome(String nome) {
    final palavras = nome.split('_');
    return palavras.map((p) => p[0].toUpperCase() + p.substring(1)).join(' ');
  }

  void _showIconDetails(BuildContext context, String iconKey) {
    final aliases = ingredientAliasesExemplo[iconKey] ?? [];
    final bool isDark = Theme.of(context).brightness == Brightness.dark;

    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      builder: (BuildContext context) {
        return DraggableScrollableSheet(
          initialChildSize: 0.5,
          minChildSize: 0.3,
          maxChildSize: 0.8,
          expand: false,
          builder: (_, scrollController) {
            return Container(
              decoration: BoxDecoration(
                color: Theme.of(context).cardColor,
                borderRadius: const BorderRadius.only(
                  topLeft: Radius.circular(24.0),
                  topRight: Radius.circular(24.0),
                ),
              ),
              child: ListView(
                controller: scrollController,
                padding: const EdgeInsets.all(24.0),
                children: <Widget>[
                  Center(
                    child: Container(
                      width: 40,
                      height: 5,
                      margin: const EdgeInsets.only(bottom: 16),
                      decoration: BoxDecoration(
                        color: Colors.grey[isDark ? 700 : 300],
                        borderRadius: BorderRadius.circular(10),
                      ),
                    ),
                  ),
                  Text(
                    iconKey.replaceAll('_', ' ').toUpperCase(),
                    textAlign: TextAlign.center,
                    style: Theme.of(context)
                        .textTheme
                        .headlineSmall
                        ?.copyWith(fontWeight: FontWeight.bold),
                  ),
                  const SizedBox(height: 24),
                  Center(
                    child: Hero(
                      tag: 'icon_detail_$iconKey',
                      child: BrIngredienteIconSmart(
                        nome: iconKey,
                        size: 100,
                        fallback: 'default',
                      ),
                    ),
                  ),
                  const SizedBox(height: 24),
                  Text('Chave do Ícone: "$iconKey"',
                      style: Theme.of(context).textTheme.titleMedium),
                  const SizedBox(height: 16),
                  const Divider(),
                  const SizedBox(height: 10),
                  if (aliases.isNotEmpty) ...[
                    _buildTranslationRow(
                        'Português:', aliases.length > 0 ? aliases[0] : 'N/A'),
                    _buildTranslationRow(
                        'Inglês:', aliases.length > 1 ? aliases[1] : 'N/A'),
                    _buildTranslationRow(
                        'Espanhol:', aliases.length > 2 ? aliases[2] : 'N/A'),
                    _buildTranslationRow(
                        'Francês:', aliases.length > 3 ? aliases[3] : 'N/A'),
                  ] else
                    const Text('Nenhum alias encontrado.',
                        style: TextStyle(fontStyle: FontStyle.italic)),
                  const SizedBox(height: 30),
                  Center(
                    child: ElevatedButton(
                      style: ElevatedButton.styleFrom(
                          padding: const EdgeInsets.symmetric(
                              horizontal: 30, vertical: 15),
                          textStyle: const TextStyle(fontSize: 16)),
                      child: const Text('Fechar'),
                      onPressed: () => Navigator.of(context).pop(),
                    ),
                  ),
                ],
              ),
            );
          },
        );
      },
    );
  }

  Widget _buildTranslationRow(String label, String value) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(label,
              style:
                  const TextStyle(fontWeight: FontWeight.bold, fontSize: 15)),
          const SizedBox(width: 8),
          Expanded(child: Text(value, style: const TextStyle(fontSize: 15))),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final bool isDark = Theme.of(context).brightness == Brightness.dark;
    return Scaffold(
      body: SafeArea(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              width: double.infinity,
              padding:
                  const EdgeInsets.symmetric(horizontal: 20.0, vertical: 30.0),
              decoration: const BoxDecoration(
                gradient: LinearGradient(
                  colors: [Color(0xFF4A00E0), Color(0xFF8E2DE2)], // Roxo + azul
                  begin: Alignment.topLeft,
                  end: Alignment.bottomRight,
                ),
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Text(
                    "Ícones de Ingredientes",
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      fontSize: 26,
                      fontWeight: FontWeight.bold,
                      color: Colors.white,
                    ),
                  ),
                  const SizedBox(height: 8),
                  Text(
                    "Coleção de ícones para aplicativos de receitas e gastronomia",
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      fontSize: 16,
                      color: Colors.white70,
                    ),
                  ),
                  const SizedBox(height: 20),
                  Container(
                    decoration: BoxDecoration(
                      color: Colors.white.withOpacity(0.1), // sem fundo sólido
                      borderRadius: BorderRadius.circular(30),
                    ),
                    padding:
                        const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
                    child: Row(
                      children: [
                        const Icon(Icons.search, color: Colors.white),
                        const SizedBox(width: 8),
                        Expanded(
                          child: TextField(
                            style: const TextStyle(color: Colors.white),
                            decoration: const InputDecoration(
                              border: InputBorder.none,
                              hintText: "Buscar ingrediente em qualquer idioma",
                              hintStyle: TextStyle(color: Colors.white70),
                              filled: false, // ✅ impede que o fundo fique opaco
                            ),
                            onChanged: _filterIcons,
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
            Expanded(
              child: _filteredIconKeys.isEmpty && _searchTerm.isNotEmpty
                  ? Center(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Icon(Icons.search_off,
                              size: 60, color: Colors.grey[400]),
                          const SizedBox(height: 16),
                          Text(
                            'Nenhum ícone encontrado para "$_searchTerm".',
                            style: TextStyle(
                                fontSize: 16, color: Colors.grey[600]),
                          ),
                        ],
                      ),
                    )
                  : GridView.builder(
                      padding: const EdgeInsets.all(20.0),
                      itemCount: _filteredIconKeys.length,
                      gridDelegate:
                          const SliverGridDelegateWithMaxCrossAxisExtent(
                        maxCrossAxisExtent: 200,
                        mainAxisSpacing: 20,
                        crossAxisSpacing: 20,
                        childAspectRatio: 0.9,
                      ),
                      itemBuilder: (context, index) {
                        final iconKey = _filteredIconKeys[index];
                        return TweenAnimationBuilder(
                          tween: Tween<double>(begin: 0.0, end: 1.0),
                          duration: Duration(milliseconds: 500 + (index * 50)),
                          curve: Curves.easeOutCubic,
                          builder: (context, double value, child) {
                            return Opacity(
                              opacity: value,
                              child: Transform.translate(
                                offset: Offset(0, 50 * (1 - value)),
                                child: child,
                              ),
                            );
                          },
                          child: InkWell(
                            onTap: () => _showIconDetails(context, iconKey),
                            borderRadius: BorderRadius.circular(16.0),
                            child: Card(
                              elevation: 4,
                              child: Padding(
                                padding: const EdgeInsets.all(12.0),
                                child: Column(
                                  mainAxisAlignment: MainAxisAlignment.center,
                                  children: [
                                    Hero(
                                      tag: 'icon_detail_$iconKey',
                                      child: BrIngredienteIconSmart(
                                        nome: iconKey,
                                        size: 90,
                                        fallback: 'default',
                                      ),
                                    ),
                                    const SizedBox(height: 10),
                                    Text(
                                      _formatNome(iconKey),
                                      textAlign: TextAlign.center,
                                      style: Theme.of(context)
                                          .textTheme
                                          .titleMedium
                                          ?.copyWith(
                                            fontWeight: FontWeight.w500,
                                            fontSize: 18,
                                          ),
                                    ),
                                  ],
                                ),
                              ),
                            ),
                          ),
                        );
                      },
                    ),
            ),
            Padding(
              padding: const EdgeInsets.only(top: 20, bottom: 20.0),
              child: Center(
                child: Text(
                  'by: David Kalil Braga',
                  style: TextStyle(
                    fontSize: 14,
                    fontStyle: FontStyle.italic,
                    color: Colors.grey[600],
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
3
likes
155
points
21
downloads

Publisher

unverified uploader

Weekly Downloads

Ícones PNG e busca inteligente de ingredientes para Flutter (brasileiro/multilíngue).

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on br_ingredientes_icons