335 lines
11 KiB
Dart
335 lines
11 KiB
Dart
|
|
import 'package:flutter/material.dart';
|
|||
|
|
import '../../../../core/constants/app_constants.dart';
|
|||
|
|
|
|||
|
|
class GuidePage extends StatelessWidget {
|
|||
|
|
const GuidePage({super.key});
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Widget build(BuildContext context) {
|
|||
|
|
return DefaultTabController(
|
|||
|
|
length: 3,
|
|||
|
|
child: Scaffold(
|
|||
|
|
appBar: AppBar(
|
|||
|
|
title: const Text('Guida'),
|
|||
|
|
bottom: TabBar(
|
|||
|
|
tabs: const [
|
|||
|
|
Tab(text: 'Pasti'),
|
|||
|
|
Tab(text: 'Converti'),
|
|||
|
|
Tab(text: 'Spesa'),
|
|||
|
|
],
|
|||
|
|
labelColor: Theme.of(context).colorScheme.primary,
|
|||
|
|
indicatorColor: Theme.of(context).colorScheme.primary,
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
body: const TabBarView(
|
|||
|
|
children: [
|
|||
|
|
_PastiTab(),
|
|||
|
|
_ConvertiTab(),
|
|||
|
|
_SpesaTab(),
|
|||
|
|
],
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── Pasti ────────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
class _PastiTab extends StatelessWidget {
|
|||
|
|
const _PastiTab();
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Widget build(BuildContext context) {
|
|||
|
|
return ListView(
|
|||
|
|
padding: const EdgeInsets.all(16),
|
|||
|
|
children: const [
|
|||
|
|
_DocCard(
|
|||
|
|
title: 'Aggiungere un alimento',
|
|||
|
|
child: _Steps(steps: [
|
|||
|
|
'Tocca il giorno per espandere la card',
|
|||
|
|
'Scegli il pasto: Colazione, Pranzo o Cena',
|
|||
|
|
'Scrivi il nome nel campo di testo',
|
|||
|
|
'Premi + o Invio per aggiungerlo',
|
|||
|
|
]),
|
|||
|
|
),
|
|||
|
|
_TipCard(
|
|||
|
|
text:
|
|||
|
|
'Premi "Genera lista della spesa" in fondo alla pagina per importare automaticamente tutti gli alimenti della settimana, senza duplicati.',
|
|||
|
|
),
|
|||
|
|
_DocCard(
|
|||
|
|
title: 'Rimuovere un alimento',
|
|||
|
|
child: _Body(
|
|||
|
|
text:
|
|||
|
|
'Tocca il pulsante × a destra dell\'elemento per eliminarlo.'),
|
|||
|
|
),
|
|||
|
|
_DocCard(
|
|||
|
|
title: 'Salvataggio automatico',
|
|||
|
|
child: _Body(
|
|||
|
|
text:
|
|||
|
|
'I dati vengono salvati automaticamente sul dispositivo. Non serve premere nessun tasto.'),
|
|||
|
|
),
|
|||
|
|
],
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── Converti ─────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
class _ConvertiTab extends StatelessWidget {
|
|||
|
|
const _ConvertiTab();
|
|||
|
|
|
|||
|
|
static const _categories = [
|
|||
|
|
('Cereali e pasta', 'Riso (4 varietà), pasta, farro, orzo, quinoa, cous cous'),
|
|||
|
|
('Legumi secchi', 'Ceci, fagioli, lenticchie'),
|
|||
|
|
('Verdure', 'Carote, zucchine, patate, spinaci, broccoli, asparagi e altri'),
|
|||
|
|
('Carni', 'Pollo petto, tacchino fesa, hamburger, vitello'),
|
|||
|
|
('Pesce', 'Tonno, merluzzo, spigola, sogliola'),
|
|||
|
|
('Uova', 'Uovo al tegamino, frittata'),
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
static const _methods = ['Bollitura', 'Padella', 'Forno', 'Friggitrice ad aria'];
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Widget build(BuildContext context) {
|
|||
|
|
final scheme = Theme.of(context).colorScheme;
|
|||
|
|
return ListView(
|
|||
|
|
padding: const EdgeInsets.all(16),
|
|||
|
|
children: [
|
|||
|
|
const _DocCard(
|
|||
|
|
title: 'Come usarlo',
|
|||
|
|
child: _Steps(steps: [
|
|||
|
|
'Cerca l\'alimento nel campo (es. pollo, riso)',
|
|||
|
|
'Seleziona il metodo di cottura dall\'elenco',
|
|||
|
|
'Inserisci il peso in grammi',
|
|||
|
|
'Il risultato appare in tempo reale',
|
|||
|
|
'Premi il pulsante "Cambia" per invertire crudo / cotto',
|
|||
|
|
]),
|
|||
|
|
),
|
|||
|
|
_DocCard(
|
|||
|
|
title: 'Alimenti disponibili',
|
|||
|
|
child: Column(
|
|||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|||
|
|
children: [
|
|||
|
|
Container(
|
|||
|
|
decoration: BoxDecoration(
|
|||
|
|
border: Border.all(color: scheme.outlineVariant),
|
|||
|
|
borderRadius: BorderRadius.circular(8),
|
|||
|
|
),
|
|||
|
|
child: Column(
|
|||
|
|
children: _categories.indexed.map((entry) {
|
|||
|
|
final (i, cat) = entry;
|
|||
|
|
return Container(
|
|||
|
|
decoration: BoxDecoration(
|
|||
|
|
border: i < _categories.length - 1
|
|||
|
|
? Border(
|
|||
|
|
bottom: BorderSide(color: scheme.outlineVariant))
|
|||
|
|
: null,
|
|||
|
|
),
|
|||
|
|
padding: const EdgeInsets.symmetric(
|
|||
|
|
horizontal: 12, vertical: 9),
|
|||
|
|
child: Row(
|
|||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|||
|
|
children: [
|
|||
|
|
SizedBox(
|
|||
|
|
width: 110,
|
|||
|
|
child: Text(cat.$1,
|
|||
|
|
style: const TextStyle(
|
|||
|
|
fontWeight: FontWeight.w600,
|
|||
|
|
fontSize: 13)),
|
|||
|
|
),
|
|||
|
|
const SizedBox(width: 8),
|
|||
|
|
Expanded(
|
|||
|
|
child: Text(cat.$2,
|
|||
|
|
style: TextStyle(
|
|||
|
|
fontSize: 12,
|
|||
|
|
color: scheme.onSurfaceVariant)),
|
|||
|
|
),
|
|||
|
|
],
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
}).toList(),
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
const SizedBox(height: 12),
|
|||
|
|
Wrap(
|
|||
|
|
spacing: 6,
|
|||
|
|
runSpacing: 6,
|
|||
|
|
children: _methods
|
|||
|
|
.map((m) => Chip(
|
|||
|
|
label: Text(m,
|
|||
|
|
style: const TextStyle(fontSize: 12)),
|
|||
|
|
padding: EdgeInsets.zero,
|
|||
|
|
visualDensity: VisualDensity.compact,
|
|||
|
|
))
|
|||
|
|
.toList(),
|
|||
|
|
),
|
|||
|
|
],
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
],
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── Spesa ─────────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
class _SpesaTab extends StatelessWidget {
|
|||
|
|
const _SpesaTab();
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Widget build(BuildContext context) {
|
|||
|
|
return ListView(
|
|||
|
|
padding: const EdgeInsets.all(16),
|
|||
|
|
children: const [
|
|||
|
|
_DocCard(
|
|||
|
|
title: 'Aggiungere un elemento',
|
|||
|
|
child: _Body(
|
|||
|
|
text: 'Scrivi il nome nel campo in alto e premi + o Invio.'),
|
|||
|
|
),
|
|||
|
|
_TipCard(
|
|||
|
|
text:
|
|||
|
|
'Vai alla tab Pasti e premi "Genera lista della spesa" per importare automaticamente gli alimenti pianificati, senza duplicati.',
|
|||
|
|
),
|
|||
|
|
_DocCard(
|
|||
|
|
title: 'Spuntare un elemento',
|
|||
|
|
child: _Body(
|
|||
|
|
text:
|
|||
|
|
'Tocca la casella a sinistra. Gli elementi completati vengono spostati in una sezione separata con testo barrato.'),
|
|||
|
|
),
|
|||
|
|
_DocCard(
|
|||
|
|
title: 'Rimuovere / svuotare',
|
|||
|
|
child: _Body(
|
|||
|
|
text:
|
|||
|
|
'Tocca × per rimuovere un singolo elemento, oppure "Svuota lista" in fondo per eliminare tutto (richiede conferma).'),
|
|||
|
|
),
|
|||
|
|
],
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── Componenti condivisi ──────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
class _DocCard extends StatelessWidget {
|
|||
|
|
final String title;
|
|||
|
|
final Widget child;
|
|||
|
|
const _DocCard({required this.title, required this.child});
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Widget build(BuildContext context) {
|
|||
|
|
return Card(
|
|||
|
|
margin: const EdgeInsets.only(bottom: 10),
|
|||
|
|
child: Padding(
|
|||
|
|
padding: const EdgeInsets.all(14),
|
|||
|
|
child: Column(
|
|||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|||
|
|
children: [
|
|||
|
|
Text(title.toUpperCase(),
|
|||
|
|
style: TextStyle(
|
|||
|
|
fontSize: 11,
|
|||
|
|
fontWeight: FontWeight.w700,
|
|||
|
|
letterSpacing: 0.7,
|
|||
|
|
color: Theme.of(context).colorScheme.onSurfaceVariant)),
|
|||
|
|
const SizedBox(height: 10),
|
|||
|
|
child,
|
|||
|
|
],
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class _TipCard extends StatelessWidget {
|
|||
|
|
final String text;
|
|||
|
|
const _TipCard({required this.text});
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Widget build(BuildContext context) {
|
|||
|
|
final scheme = Theme.of(context).colorScheme;
|
|||
|
|
return Container(
|
|||
|
|
margin: const EdgeInsets.only(bottom: 10),
|
|||
|
|
padding: const EdgeInsets.all(14),
|
|||
|
|
decoration: BoxDecoration(
|
|||
|
|
color: scheme.primaryContainer.withValues(alpha: 0.4),
|
|||
|
|
border: Border(left: BorderSide(color: scheme.primary, width: 3)),
|
|||
|
|
borderRadius: BorderRadius.circular(8),
|
|||
|
|
),
|
|||
|
|
child: Column(
|
|||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|||
|
|
children: [
|
|||
|
|
Row(
|
|||
|
|
children: [
|
|||
|
|
Icon(Icons.info_outline, size: 14, color: scheme.primary),
|
|||
|
|
const SizedBox(width: 5),
|
|||
|
|
Text('SUGGERIMENTO',
|
|||
|
|
style: TextStyle(
|
|||
|
|
fontSize: 11,
|
|||
|
|
fontWeight: FontWeight.w700,
|
|||
|
|
letterSpacing: 0.7,
|
|||
|
|
color: scheme.primary)),
|
|||
|
|
],
|
|||
|
|
),
|
|||
|
|
const SizedBox(height: 6),
|
|||
|
|
Text(text, style: const TextStyle(fontSize: 14, height: 1.5)),
|
|||
|
|
],
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class _Steps extends StatelessWidget {
|
|||
|
|
final List<String> steps;
|
|||
|
|
const _Steps({required this.steps});
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Widget build(BuildContext context) {
|
|||
|
|
return Column(
|
|||
|
|
children: steps.indexed.map((entry) {
|
|||
|
|
final (i, step) = entry;
|
|||
|
|
return Padding(
|
|||
|
|
padding: const EdgeInsets.only(bottom: 8),
|
|||
|
|
child: Row(
|
|||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|||
|
|
children: [
|
|||
|
|
Container(
|
|||
|
|
width: 22,
|
|||
|
|
height: 22,
|
|||
|
|
alignment: Alignment.center,
|
|||
|
|
decoration: BoxDecoration(
|
|||
|
|
color: Theme.of(context).colorScheme.primary,
|
|||
|
|
shape: BoxShape.circle,
|
|||
|
|
),
|
|||
|
|
child: Text('${i + 1}',
|
|||
|
|
style: const TextStyle(
|
|||
|
|
color: Colors.white,
|
|||
|
|
fontSize: 11,
|
|||
|
|
fontWeight: FontWeight.bold)),
|
|||
|
|
),
|
|||
|
|
const SizedBox(width: 10),
|
|||
|
|
Expanded(
|
|||
|
|
child: Padding(
|
|||
|
|
padding: const EdgeInsets.only(top: 2),
|
|||
|
|
child: Text(step,
|
|||
|
|
style:
|
|||
|
|
const TextStyle(fontSize: 14, height: 1.5)),
|
|||
|
|
)),
|
|||
|
|
],
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
}).toList(),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class _Body extends StatelessWidget {
|
|||
|
|
final String text;
|
|||
|
|
const _Body({required this.text});
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Widget build(BuildContext context) {
|
|||
|
|
return Text(text, style: const TextStyle(fontSize: 14, height: 1.5));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ignore footer version — accessed via kAppVersion constant
|
|||
|
|
String get _footerText => 'BitePlan · v$kAppVersion · $kAppAuthor';
|