diff --git a/database/create_items_table.sql b/database/create_items_table.sql new file mode 100644 index 0000000..5863c4b --- /dev/null +++ b/database/create_items_table.sql @@ -0,0 +1,58 @@ +-- Create items table +CREATE TABLE items ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, + name TEXT NOT NULL, + description TEXT, + category_id TEXT NOT NULL, + subcategory_id TEXT, + context_tags TEXT[] DEFAULT '{}', + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() +); + +-- Create index on user_id for faster queries +CREATE INDEX idx_items_user_id ON items(user_id); + +-- Create index on category_id for filtering +CREATE INDEX idx_items_category_id ON items(category_id); + +-- Create index on context_tags for tag-based searches +CREATE INDEX idx_items_context_tags ON items USING GIN(context_tags); + +-- Enable Row Level Security +ALTER TABLE items ENABLE ROW LEVEL SECURITY; + +-- Create policy to allow users to see their own items +CREATE POLICY "Users can view own items" + ON items FOR SELECT + USING (auth.uid() = user_id); + +-- Create policy to allow users to insert their own items +CREATE POLICY "Users can insert own items" + ON items FOR INSERT + WITH CHECK (auth.uid() = user_id); + +-- Create policy to allow users to update their own items +CREATE POLICY "Users can update own items" + ON items FOR UPDATE + USING (auth.uid() = user_id); + +-- Create policy to allow users to delete their own items +CREATE POLICY "Users can delete own items" + ON items FOR DELETE + USING (auth.uid() = user_id); + +-- Create trigger to update updated_at timestamp +CREATE OR REPLACE FUNCTION update_updated_at_column() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = NOW(); + RETURN NEW; +END; +$$ language 'plpgsql'; + +CREATE TRIGGER update_items_updated_at + BEFORE UPDATE ON items + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); diff --git a/lib/Screens/add_item_screen.dart b/lib/Screens/add_item_screen.dart new file mode 100644 index 0000000..19a487d --- /dev/null +++ b/lib/Screens/add_item_screen.dart @@ -0,0 +1,370 @@ +import 'package:flutter/material.dart'; +import 'package:supabase_flutter/supabase_flutter.dart'; +import '../constants/item_categories.dart'; + +class AddItemScreen extends StatefulWidget { + const AddItemScreen({super.key}); + + @override + State createState() => _AddItemScreenState(); +} + +class _AddItemScreenState extends State { + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _descriptionController = TextEditingController(); + + ItemCategory? _selectedCategory; + Subcategory? _selectedSubcategory; + final Set _selectedTags = {}; + + bool _isLoading = false; + + @override + void dispose() { + _nameController.dispose(); + _descriptionController.dispose(); + super.dispose(); + } + + void _onCategoryChanged(ItemCategory? category) { + setState(() { + _selectedCategory = category; + _selectedSubcategory = null; + _selectedTags.clear(); + + if (category != null && category.subcategories.isNotEmpty) { + _selectedSubcategory = category.subcategories.first; + _autoAssignTags(category.id, category.subcategories.first.id); + } + }); + } + + void _onSubcategoryChanged(Subcategory? subcategory) { + setState(() { + _selectedSubcategory = subcategory; + _selectedTags.clear(); + + if (_selectedCategory != null && subcategory != null) { + _autoAssignTags(_selectedCategory!.id, subcategory.id); + } + }); + } + + void _autoAssignTags(String categoryId, String subcategoryId) { + final autoTags = getAutoContextTags(categoryId, subcategoryId); + setState(() { + _selectedTags.addAll(autoTags); + }); + } + + void _toggleTag(String tagId) { + setState(() { + if (_selectedTags.contains(tagId)) { + _selectedTags.remove(tagId); + } else if (_selectedTags.length < 10) { + _selectedTags.add(tagId); + } + }); + } + + Future _saveItem() async { + if (_nameController.text.trim().isEmpty) { + _showErrorSnackBar('Por favor, insira o nome do item'); + return; + } + + if (_selectedCategory == null) { + _showErrorSnackBar('Por favor, selecione uma categoria'); + return; + } + + setState(() => _isLoading = true); + + try { + final user = Supabase.instance.client.auth.currentUser; + if (user == null) { + _showErrorSnackBar('Usuário não autenticado'); + return; + } + + await Supabase.instance.client.from('items').insert({ + 'user_id': user.id, + 'name': _nameController.text.trim(), + 'description': _descriptionController.text.trim(), + 'category_id': _selectedCategory!.id, + 'subcategory_id': _selectedSubcategory?.id, + 'context_tags': _selectedTags.toList(), + }); + + _showSuccessSnackBar('Item adicionado com sucesso!'); + Navigator.pop(context); + } catch (e) { + _showErrorSnackBar('Erro ao salvar item: $e'); + } finally { + setState(() => _isLoading = false); + } + } + + void _showErrorSnackBar(String message) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(message), backgroundColor: Colors.red), + ); + } + + void _showSuccessSnackBar(String message) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(message), backgroundColor: Colors.green), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFFFFE5CC), + appBar: AppBar( + backgroundColor: const Color(0xFF0066CC), + elevation: 0, + title: const Text( + 'Adicionar Item', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + centerTitle: true, + ), + body: SingleChildScrollView( + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Name field + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFFE0E0E0)), + ), + child: TextField( + controller: _nameController, + decoration: const InputDecoration( + labelText: 'Nome do item', + hintText: 'Ex: Camiseta Azul', + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + ), + ), + ), + + const SizedBox(height: 16), + + // Description field + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFFE0E0E0)), + ), + child: TextField( + controller: _descriptionController, + maxLines: 3, + decoration: const InputDecoration( + labelText: 'Descrição (opcional)', + hintText: 'Detalhes sobre o item', + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + ), + ), + ), + + const SizedBox(height: 24), + + // Category selection + const Text( + 'Categoria', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 8), + + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 12), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFFE0E0E0)), + ), + child: DropdownButtonHideUnderline( + child: DropdownButton( + value: _selectedCategory, + hint: const Text('Selecione uma categoria'), + isExpanded: true, + items: ITEM_CATEGORIES.map((category) { + return DropdownMenuItem( + value: category, + child: Row( + children: [ + Text(category.icon, style: const TextStyle(fontSize: 24)), + const SizedBox(width: 12), + Text(category.name), + ], + ), + ); + }).toList(), + onChanged: _onCategoryChanged, + ), + ), + ), + + const SizedBox(height: 16), + + // Subcategory selection + if (_selectedCategory != null && _selectedCategory!.subcategories.isNotEmpty) ...[ + const Text( + 'Subcategoria', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 8), + + SizedBox( + height: 60, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: _selectedCategory!.subcategories.length, + itemBuilder: (context, index) { + final subcategory = _selectedCategory!.subcategories[index]; + final isSelected = _selectedSubcategory == subcategory; + + return Padding( + padding: const EdgeInsets.only(right: 8), + child: GestureDetector( + onTap: () => _onSubcategoryChanged(subcategory), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + color: isSelected ? const Color(0xFF0066CC) : Colors.white, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: isSelected ? const Color(0xFF0066CC) : const Color(0xFFE0E0E0), + ), + ), + child: Center( + child: Text( + subcategory.name, + style: TextStyle( + color: isSelected ? Colors.white : const Color(0xFF333333), + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ), + ); + }, + ), + ), + + const SizedBox(height: 8), + if (_selectedSubcategory != null) + Text( + _selectedSubcategory!.examples, + style: const TextStyle( + fontSize: 12, + color: Color(0xFF666666), + fontStyle: FontStyle.italic, + ), + ), + ], + + const SizedBox(height: 24), + + // Context tags + const Text( + 'Tags de Contexto', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 8), + + Wrap( + spacing: 8, + runSpacing: 8, + children: CONTEXT_TAGS.map((tag) { + final isSelected = _selectedTags.contains(tag.id); + return FilterChip( + label: Text(tag.name), + selected: isSelected, + onSelected: (selected) => _toggleTag(tag.id), + selectedColor: const Color(0xFF0066CC).withOpacity(0.2), + checkmarkColor: const Color(0xFF0066CC), + backgroundColor: Colors.white, + labelStyle: TextStyle( + color: isSelected ? const Color(0xFF0066CC) : const Color(0xFF333333), + ), + ); + }).toList(), + ), + + const SizedBox(height: 8), + Text( + 'Tags selecionadas: ${_selectedTags.length}/10', + style: const TextStyle( + fontSize: 12, + color: Color(0xFF666666), + ), + ), + + const SizedBox(height: 32), + + // Save button + SizedBox( + width: double.infinity, + height: 56, + child: ElevatedButton( + onPressed: _isLoading ? null : _saveItem, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF0066CC), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 0, + ), + child: _isLoading + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ) + : const Text( + 'Salvar Item', + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/Screens/home_screen.dart b/lib/Screens/home_screen.dart index 901f1d9..5e68307 100644 --- a/lib/Screens/home_screen.dart +++ b/lib/Screens/home_screen.dart @@ -1,5 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:supabase_flutter/supabase_flutter.dart'; import 'perfil_screen.dart'; +import 'add_item_screen.dart'; +import '../constants/item_categories.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @@ -50,9 +53,40 @@ class _HomeScreenState extends State { } } -class _HomeContent extends StatelessWidget { +class _HomeContent extends StatefulWidget { const _HomeContent(); + @override + State<_HomeContent> createState() => _HomeContentState(); +} + +class _HomeContentState extends State<_HomeContent> { + int _itemCount = 0; + + @override + void initState() { + super.initState(); + _loadItemCount(); + } + + Future _loadItemCount() async { + try { + final user = Supabase.instance.client.auth.currentUser; + if (user != null) { + final response = await Supabase.instance.client + .from('items') + .select('id') + .eq('user_id', user.id); + + setState(() { + _itemCount = response.length; + }); + } + } catch (e) { + print('Error loading item count: $e'); + } + } + @override Widget build(BuildContext context) { return SafeArea( @@ -70,10 +104,10 @@ class _HomeContent extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const Column( + Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( + const Text( 'DayMaker', style: TextStyle( color: Colors.white, @@ -81,10 +115,13 @@ class _HomeContent extends StatelessWidget { fontWeight: FontWeight.bold, ), ), - SizedBox(height: 4), + const SizedBox(height: 4), Text( - '6 itens', - style: TextStyle(color: Colors.white70, fontSize: 14), + '$_itemCount itens', + style: const TextStyle( + color: Colors.white70, + fontSize: 14, + ), ), ], ), @@ -251,11 +288,8 @@ class _HomeContent extends StatelessWidget { right: 20, child: FloatingActionButton( onPressed: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Adicionar novo item'), - backgroundColor: Color(0xFF0066CC), - ), + Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const AddItemScreen()), ); }, backgroundColor: const Color(0xFF0066CC), @@ -268,12 +302,213 @@ class _HomeContent extends StatelessWidget { } } -class _ItemsScreen extends StatelessWidget { +class _ItemsScreen extends StatefulWidget { const _ItemsScreen(); + @override + State<_ItemsScreen> createState() => _ItemsScreenState(); +} + +class _ItemsScreenState extends State<_ItemsScreen> { + List> _items = []; + bool _isLoading = true; + + @override + void initState() { + super.initState(); + _loadItems(); + } + + Future _loadItems() async { + try { + final user = Supabase.instance.client.auth.currentUser; + if (user != null) { + final response = await Supabase.instance.client + .from('items') + .select() + .eq('user_id', user.id) + .order('created_at', ascending: false); + + setState(() { + _items = List>.from(response); + _isLoading = false; + }); + } + } catch (e) { + print('Error loading items: $e'); + setState(() => _isLoading = false); + } + } + + String _getCategoryName(String categoryId) { + final category = ITEM_CATEGORIES.firstWhere( + (cat) => cat.id == categoryId, + orElse: () => ITEM_CATEGORIES.last, + ); + return category.name; + } + + String _getCategoryIcon(String categoryId) { + final category = ITEM_CATEGORIES.firstWhere( + (cat) => cat.id == categoryId, + orElse: () => ITEM_CATEGORIES.last, + ); + return category.icon; + } + @override Widget build(BuildContext context) { - return const Center(child: Text('Itens')); + return Scaffold( + backgroundColor: const Color(0xFFFFE5CC), + appBar: AppBar( + backgroundColor: const Color(0xFF0066CC), + elevation: 0, + title: const Text( + 'Meus Itens', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + centerTitle: true, + ), + body: _isLoading + ? const Center(child: CircularProgressIndicator()) + : _items.isEmpty + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.inventory_2_outlined, + size: 64, + color: Colors.grey[400], + ), + const SizedBox(height: 16), + const Text( + 'Nenhum item ainda', + style: TextStyle(fontSize: 18, color: Color(0xFF666666)), + ), + const SizedBox(height: 8), + const Text( + 'Toque no + para adicionar', + style: TextStyle(fontSize: 14, color: Color(0xFF999999)), + ), + ], + ), + ) + : ListView.builder( + padding: const EdgeInsets.all(16), + itemCount: _items.length, + itemBuilder: (context, index) { + final item = _items[index]; + final categoryName = _getCategoryName(item['category_id']); + final categoryIcon = _getCategoryIcon(item['category_id']); + final tags = List.from(item['context_tags'] ?? []); + + return Card( + margin: const EdgeInsets.only(bottom: 12), + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + width: 48, + height: 48, + decoration: BoxDecoration( + color: const Color(0xFF0066CC).withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: Text( + categoryIcon, + style: const TextStyle(fontSize: 24), + ), + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item['name'] ?? 'Sem nome', + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 4), + Text( + categoryName, + style: const TextStyle( + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ], + ), + ), + ], + ), + if (item['description'] != null && + item['description'].toString().isNotEmpty) ...[ + const SizedBox(height: 12), + Text( + item['description'], + style: const TextStyle( + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ], + if (tags.isNotEmpty) ...[ + const SizedBox(height: 12), + Wrap( + spacing: 8, + runSpacing: 8, + children: tags.map((tag) { + final contextTag = CONTEXT_TAGS.firstWhere( + (t) => t.id == tag, + orElse: () => CONTEXT_TAGS.first, + ); + return Chip( + label: Text(contextTag.name), + backgroundColor: const Color( + 0xFF0066CC, + ).withOpacity(0.1), + labelStyle: const TextStyle( + color: Color(0xFF0066CC), + fontSize: 12, + ), + padding: EdgeInsets.zero, + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + ); + }).toList(), + ), + ], + ], + ), + ), + ); + }, + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (_) => const AddItemScreen())) + .then((_) => _loadItems()); + }, + backgroundColor: const Color(0xFF0066CC), + child: const Icon(Icons.add, color: Colors.white), + ), + ); } } diff --git a/lib/constants/item_categories.dart b/lib/constants/item_categories.dart new file mode 100644 index 0000000..29c6182 --- /dev/null +++ b/lib/constants/item_categories.dart @@ -0,0 +1,293 @@ +class ItemCategory { + final String id; + final String name; + final String icon; + final String description; + final List subcategories; + + ItemCategory({ + required this.id, + required this.name, + required this.icon, + required this.description, + required this.subcategories, + }); +} + +class Subcategory { + final String id; + final String name; + final String examples; + + Subcategory({required this.id, required this.name, required this.examples}); +} + +class ContextTag { + final String id; + final String name; + final String description; + final String examples; + + ContextTag({ + required this.id, + required this.name, + required this.description, + required this.examples, + }); +} + +// Categorias principais +final List ITEM_CATEGORIES = [ + ItemCategory( + id: 'clothing', + name: 'Roupa', + icon: '👕', + description: 'Peças de vestuário', + subcategories: [ + Subcategory( + id: 'casual', + name: 'Casual', + examples: 't-shirts, calças de ganga, hoodies', + ), + Subcategory( + id: 'formal', + name: 'Formal', + examples: 'fatos, camisas, vestidos de cerimónia', + ), + Subcategory( + id: 'sportswear', + name: 'Sportswear', + examples: 'leggings, tops de treino, shorts', + ), + Subcategory( + id: 'outerwear', + name: 'Outerwear', + examples: 'casacos, impermeáveis, parkas', + ), + Subcategory( + id: 'underwear', + name: 'Underwear', + examples: 'roupa interior, meias', + ), + Subcategory( + id: 'sleepwear', + name: 'Sleepwear', + examples: 'pijamas, roupões', + ), + ], + ), + ItemCategory( + id: 'electronics', + name: 'Eletrónica', + icon: '💻', + description: 'Dispositivos e acessórios tecnológicos', + subcategories: [ + Subcategory( + id: 'computers', + name: 'Computers', + examples: 'portáteis, tablets', + ), + Subcategory( + id: 'phones', + name: 'Phones', + examples: 'smartphones, earphones', + ), + Subcategory( + id: 'cameras', + name: 'Cameras', + examples: 'máquinas fotográficas, action cams', + ), + Subcategory( + id: 'cables', + name: 'Cables', + examples: 'carregadores, cabos USB, adaptadores', + ), + Subcategory( + id: 'gaming', + name: 'Gaming', + examples: 'consolas, comandos, jogos', + ), + Subcategory( + id: 'audio', + name: 'Audio', + examples: 'headphones, colunas bluetooth', + ), + ], + ), + ItemCategory( + id: 'footwear', + name: 'Calçado', + icon: '👟', + description: 'Sapatos, botas, sandálias', + subcategories: [ + Subcategory( + id: 'casual', + name: 'Casual', + examples: 'sapatilhas, loafers', + ), + Subcategory( + id: 'formal', + name: 'Formal', + examples: 'sapatos de salto, mocassins', + ), + Subcategory( + id: 'sport', + name: 'Sport', + examples: 'ténis de corrida, chuteiras', + ), + Subcategory( + id: 'outdoor', + name: 'Outdoor', + examples: 'botas de caminhada, sandálias', + ), + ], + ), + ItemCategory( + id: 'accessories', + name: 'Acessórios', + icon: '🎒', + description: 'Bolsas, relógios, óculos, bijuteria', + subcategories: [ + Subcategory( + id: 'bags', + name: 'Bags', + examples: 'mochilas, malas, bolsas', + ), + Subcategory( + id: 'watches', + name: 'Watches', + examples: 'relógios analógicos e digitais', + ), + Subcategory( + id: 'eyewear', + name: 'Eyewear', + examples: 'óculos de sol, óculos de grau', + ), + Subcategory( + id: 'jewelry', + name: 'Jewelry', + examples: 'colares, pulseiras, brincos', + ), + Subcategory(id: 'hats', name: 'Hats', examples: 'bonés, chapéus, gorros'), + Subcategory(id: 'belts', name: 'Belts', examples: 'cintos'), + ], + ), + ItemCategory( + id: 'documents', + name: 'Documentos', + icon: '📄', + description: 'Passaporte, cartões, papéis importantes', + subcategories: [ + Subcategory( + id: 'identity', + name: 'Identity', + examples: 'passaporte, BI, carta de condução', + ), + Subcategory( + id: 'health', + name: 'Health', + examples: 'cartão de saúde, receitas', + ), + Subcategory( + id: 'travel', + name: 'Travel', + examples: 'bilhetes, reservas, seguros', + ), + Subcategory( + id: 'financial', + name: 'Financial', + examples: 'cartões de crédito/débito', + ), + ], + ), + ItemCategory( + id: 'other', + name: 'Outros', + icon: '📦', + description: 'Tudo o resto', + subcategories: [], + ), +]; + +// Tags de contexto +final List CONTEXT_TAGS = [ + ContextTag( + id: 'travel', + name: 'Viagem', + description: 'Qualquer tipo de viagem', + examples: 'Mala, passaporte, adaptador de tomadas', + ), + ContextTag( + id: 'work', + name: 'Trabalho', + description: 'Ambiente de trabalho', + examples: 'Portátil, fato, sapatos formais', + ), + ContextTag( + id: 'casual', + name: 'Casual', + description: 'Dia-a-dia informal', + examples: 'Jeans, t-shirt, sapatilhas', + ), + ContextTag( + id: 'sport', + name: 'Desporto', + description: 'Atividade física', + examples: 'Leggings, ténis de corrida, garrafa de água', + ), + ContextTag( + id: 'formal', + name: 'Formal', + description: 'Eventos formais', + examples: 'Fato, vestido, sapatos de salto', + ), + ContextTag( + id: 'outdoor', + name: 'Exterior', + description: 'Exterior e natureza', + examples: 'Blusão, botas, impermeável', + ), + ContextTag( + id: 'beach', + name: 'Praia', + description: 'Praia ou piscina', + examples: 'Biquíni, chinelos, protetor solar', + ), + ContextTag( + id: 'cold', + name: 'Frio', + description: 'Clima frio', + examples: 'Casaco, cachecol, luvas', + ), + ContextTag( + id: 'hot', + name: 'Quente', + description: 'Clima quente', + examples: 'Roupa leve, t-shirts, sandálias', + ), +]; + +// Regras de atribuição automática de tags +List getAutoContextTags(String categoryId, String subcategoryId) { + final key = '$categoryId.$subcategoryId'; + + final Map> autoTags = { + 'clothing.formal': ['work', 'formal'], + 'clothing.casual': ['casual', 'travel'], + 'clothing.sportswear': ['sport'], + 'clothing.outerwear': ['travel', 'cold', 'outdoor'], + 'electronics.computers': ['work', 'travel'], + 'electronics.phones': ['travel', 'work', 'casual'], + 'electronics.cables': ['travel'], + 'electronics.gaming': ['casual', 'travel'], + 'footwear.formal': ['work', 'formal'], + 'footwear.casual': ['casual', 'travel'], + 'footwear.sport': ['sport'], + 'footwear.outdoor': ['outdoor', 'travel'], + 'accessories.bags': ['travel', 'work', 'casual'], + 'documents.identity': ['travel'], + 'documents.travel': ['travel'], + }; + + return autoTags[key] ?? []; +} diff --git a/logoDayMaker.png b/logoDayMaker.png new file mode 100644 index 0000000..985d03c Binary files /dev/null and b/logoDayMaker.png differ