IA Funcinonal
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import '../constants/item_categories.dart';
|
||||
import '../services/ai_recommendation_service.dart';
|
||||
import '../theme/app_theme.dart';
|
||||
import 'add_item_screen.dart';
|
||||
import 'ai_chat_screen.dart';
|
||||
import 'item_screen.dart';
|
||||
import 'perfil_screen.dart';
|
||||
import 'week_screen.dart';
|
||||
@@ -21,6 +23,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
_HomeContent(),
|
||||
ItemScreen(),
|
||||
WeekScreen(),
|
||||
AiChatScreen(),
|
||||
PerfilScreen(),
|
||||
];
|
||||
|
||||
@@ -55,7 +58,8 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
_navItem(0, Icons.home_rounded, 'Início'),
|
||||
_navItem(1, Icons.inventory_2_rounded, 'Itens'),
|
||||
_navItem(2, Icons.calendar_month_rounded, 'Semana'),
|
||||
_navItem(3, Icons.person_rounded, 'Perfil'),
|
||||
_navItem(3, Icons.auto_awesome_rounded, 'IA'),
|
||||
_navItem(4, Icons.person_rounded, 'Perfil'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -87,16 +91,14 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
Icon(
|
||||
icon,
|
||||
size: 24,
|
||||
color:
|
||||
selected ? AppColors.primary : AppColors.textSecondary,
|
||||
color: selected ? AppColors.primary : AppColors.textSecondary,
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight:
|
||||
selected ? FontWeight.w700 : FontWeight.w500,
|
||||
fontWeight: selected ? FontWeight.w700 : FontWeight.w500,
|
||||
color: selected
|
||||
? AppColors.primary
|
||||
: AppColors.textSecondary,
|
||||
@@ -198,9 +200,8 @@ class _HomeContentState extends State<_HomeContent> {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_itemCount = all.length;
|
||||
_userName = userRow?['nome'] ??
|
||||
user.email?.split('@').first ??
|
||||
'Utilizador';
|
||||
_userName =
|
||||
userRow?['nome'] ?? user.email?.split('@').first ?? 'Utilizador';
|
||||
_recentItems = List<Map<String, dynamic>>.from(recent);
|
||||
_todayItems = todayItems;
|
||||
_isLoading = false;
|
||||
@@ -227,6 +228,8 @@ class _HomeContentState extends State<_HomeContent> {
|
||||
_buildGreeting(),
|
||||
const SizedBox(height: 20),
|
||||
_buildHeroCard(),
|
||||
const SizedBox(height: 16),
|
||||
_buildAiSuggestionButton(),
|
||||
const SizedBox(height: 24),
|
||||
_buildSectionHeader('Hoje'),
|
||||
const SizedBox(height: 12),
|
||||
@@ -249,23 +252,17 @@ class _HomeContentState extends State<_HomeContent> {
|
||||
final saudacao = hour < 12
|
||||
? 'Bom dia'
|
||||
: hour < 19
|
||||
? 'Boa tarde'
|
||||
: 'Boa noite';
|
||||
? 'Boa tarde'
|
||||
: 'Boa noite';
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
saudacao,
|
||||
style: AppText.bodySecondary,
|
||||
),
|
||||
Text(saudacao, style: AppText.bodySecondary),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
_userName.isEmpty ? 'Olá!' : _userName,
|
||||
style: AppText.h2,
|
||||
),
|
||||
Text(_userName.isEmpty ? 'Olá!' : _userName, style: AppText.h2),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -413,10 +410,7 @@ class _HomeContentState extends State<_HomeContent> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Nada planeado para hoje',
|
||||
style: AppText.body,
|
||||
),
|
||||
Text('Nada planeado para hoje', style: AppText.body),
|
||||
SizedBox(height: 2),
|
||||
Text(
|
||||
'Vá à aba Semana para organizar',
|
||||
@@ -454,17 +448,11 @@ class _HomeContentState extends State<_HomeContent> {
|
||||
color: AppColors.accent.withValues(alpha: 0.15),
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.add_box_rounded,
|
||||
color: AppColors.accent,
|
||||
),
|
||||
child: const Icon(Icons.add_box_rounded, color: AppColors.accent),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const Expanded(
|
||||
child: Text(
|
||||
'Adicione o seu primeiro item',
|
||||
style: AppText.body,
|
||||
),
|
||||
child: Text('Adicione o seu primeiro item', style: AppText.body),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -509,20 +497,12 @@ class _HomeContentState extends State<_HomeContent> {
|
||||
? Image.network(
|
||||
imageUrl,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (_, __, ___) => Center(
|
||||
child: Icon(
|
||||
cat.icon,
|
||||
color: cat.color,
|
||||
size: 32,
|
||||
),
|
||||
errorBuilder: (_, _, _) => Center(
|
||||
child: Icon(cat.icon, color: cat.color, size: 32),
|
||||
),
|
||||
)
|
||||
: Center(
|
||||
child: Icon(
|
||||
cat.icon,
|
||||
color: cat.color,
|
||||
size: 32,
|
||||
),
|
||||
child: Icon(cat.icon, color: cat.color, size: 32),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -569,7 +549,7 @@ class _HomeContentState extends State<_HomeContent> {
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: 3,
|
||||
itemBuilder: (_, __) => Container(
|
||||
itemBuilder: (_, _) => Container(
|
||||
width: 110,
|
||||
margin: const EdgeInsets.only(right: 12),
|
||||
decoration: BoxDecoration(
|
||||
@@ -581,6 +561,127 @@ class _HomeContentState extends State<_HomeContent> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAiSuggestionButton() {
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
onTap: () async {
|
||||
final service = AiRecommendationService();
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => const Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
final response = await service.sendMessage(
|
||||
'vou fazer uma viagem de 4 horas de onibus',
|
||||
silent: true,
|
||||
);
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (_) => Container(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: MediaQuery.of(context).size.height * 0.6,
|
||||
),
|
||||
margin: const EdgeInsets.all(12),
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.surface,
|
||||
borderRadius: BorderRadius.circular(AppRadius.xl),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.auto_awesome, color: AppColors.primary),
|
||||
const SizedBox(width: 10),
|
||||
const Expanded(
|
||||
child: Text('Sugestao da IA', style: AppText.h3),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(height: 20),
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Text(response, style: AppText.body),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(18),
|
||||
decoration: BoxDecoration(
|
||||
gradient: AppColors.warmGradient,
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.accent.withValues(alpha: 0.3),
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 44,
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.25),
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.auto_awesome,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
const Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Pedir sugestao a IA',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 2),
|
||||
Text(
|
||||
'Monta um outfit para o teu dia',
|
||||
style: TextStyle(fontSize: 12, color: Colors.white70),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios_rounded,
|
||||
size: 16,
|
||||
color: Colors.white70,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAddCta() {
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
@@ -588,9 +689,7 @@ class _HomeContentState extends State<_HomeContent> {
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
.push(
|
||||
MaterialPageRoute(builder: (_) => const AddItemScreen()),
|
||||
)
|
||||
.push(MaterialPageRoute(builder: (_) => const AddItemScreen()))
|
||||
.then((_) => _loadData());
|
||||
},
|
||||
child: Container(
|
||||
@@ -613,8 +712,11 @@ class _HomeContentState extends State<_HomeContent> {
|
||||
gradient: AppColors.brandGradient,
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
),
|
||||
child:
|
||||
const Icon(Icons.add_rounded, color: Colors.white, size: 24),
|
||||
child: const Icon(
|
||||
Icons.add_rounded,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
const Expanded(
|
||||
|
||||
Reference in New Issue
Block a user