feat: aggiungi guida utente e icona launcher
Guida utente: - Pulsante info nell'AppBar principale - InfoBottomSheet: icona app, versione, autore, licenza, link alla guida - GuidePage: tre tab (Pasti / Converti / Spesa) con card e step numerati, portata dalla DocsPanel Vue originale AppBar globale in app.dart con titolo dinamico per tab corrente. Icona launcher: - flutter_launcher_icons eseguito in build.sh prima di flutter build apk (sia debug che release) per applicare assets/icon-only.png all'APK. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -36,7 +36,7 @@ if [[ "$RELEASE" == "true" ]]; then
|
|||||||
-v "${PROJECT_ROOT}:/workspace" \
|
-v "${PROJECT_ROOT}:/workspace" \
|
||||||
-v "${HOME}/.gradle:/root/.gradle" \
|
-v "${HOME}/.gradle:/root/.gradle" \
|
||||||
biteplan-build \
|
biteplan-build \
|
||||||
bash -c "cd /workspace && flutter pub get && flutter build apk --release"
|
bash -c "cd /workspace && flutter pub get && flutter pub run flutter_launcher_icons && flutter build apk --release"
|
||||||
|
|
||||||
echo "→ Zipalign..."
|
echo "→ Zipalign..."
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
@@ -67,7 +67,7 @@ else
|
|||||||
-v "${PROJECT_ROOT}:/workspace" \
|
-v "${PROJECT_ROOT}:/workspace" \
|
||||||
-v "${HOME}/.gradle:/root/.gradle" \
|
-v "${HOME}/.gradle:/root/.gradle" \
|
||||||
biteplan-build \
|
biteplan-build \
|
||||||
bash -c "cd /workspace && flutter pub get && flutter build apk --debug"
|
bash -c "cd /workspace && flutter pub get && flutter pub run flutter_launcher_icons && flutter build apk --debug"
|
||||||
|
|
||||||
cp "${PROJECT_ROOT}/build/app/outputs/flutter-apk/app-debug.apk" \
|
cp "${PROJECT_ROOT}/build/app/outputs/flutter-apk/app-debug.apk" \
|
||||||
"${PROJECT_ROOT}/dist/biteplan-debug.apk"
|
"${PROJECT_ROOT}/dist/biteplan-debug.apk"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'core/theme/app_theme.dart';
|
|||||||
import 'features/meal_planner/presentation/pages/meal_planner_page.dart';
|
import 'features/meal_planner/presentation/pages/meal_planner_page.dart';
|
||||||
import 'features/converter/presentation/pages/converter_page.dart';
|
import 'features/converter/presentation/pages/converter_page.dart';
|
||||||
import 'features/shopping_list/presentation/pages/shopping_list_page.dart';
|
import 'features/shopping_list/presentation/pages/shopping_list_page.dart';
|
||||||
|
import 'features/guide/presentation/widgets/info_bottom_sheet.dart';
|
||||||
|
|
||||||
class BitePlanApp extends StatelessWidget {
|
class BitePlanApp extends StatelessWidget {
|
||||||
const BitePlanApp({super.key});
|
const BitePlanApp({super.key});
|
||||||
@@ -29,6 +30,8 @@ class _MainScaffoldState extends State<_MainScaffold> {
|
|||||||
int _currentIndex = 0;
|
int _currentIndex = 0;
|
||||||
late final List<Widget> _pages;
|
late final List<Widget> _pages;
|
||||||
|
|
||||||
|
static const _titles = ['Piano Pasti', 'Convertitore', 'Lista della spesa'];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -44,6 +47,16 @@ class _MainScaffoldState extends State<_MainScaffold> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(_titles[_currentIndex]),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.info_outline),
|
||||||
|
tooltip: 'Informazioni',
|
||||||
|
onPressed: () => showInfoBottomSheet(context),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
body: IndexedStack(
|
body: IndexedStack(
|
||||||
index: _currentIndex,
|
index: _currentIndex,
|
||||||
children: _pages,
|
children: _pages,
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
const String kAppVersion = '2.0.0';
|
||||||
|
const String kAppAuthor = 'Davide Grilli';
|
||||||
|
const String kAppLicense = 'EUPL v1.2';
|
||||||
|
|
||||||
const List<String> kDayIds = [
|
const List<String> kDayIds = [
|
||||||
'lunedi',
|
'lunedi',
|
||||||
'martedi',
|
'martedi',
|
||||||
|
|||||||
@@ -0,0 +1,334 @@
|
|||||||
|
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';
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import '../../../../core/constants/app_constants.dart';
|
||||||
|
import '../pages/guide_page.dart';
|
||||||
|
|
||||||
|
void showInfoBottomSheet(BuildContext context) {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||||
|
),
|
||||||
|
builder: (_) => const _InfoSheet(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InfoSheet extends StatelessWidget {
|
||||||
|
const _InfoSheet();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
|
return SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(20, 12, 20, 24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
// handle
|
||||||
|
Container(
|
||||||
|
width: 36,
|
||||||
|
height: 4,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: scheme.outlineVariant,
|
||||||
|
borderRadius: BorderRadius.circular(2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
// icona + nome + versione
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/icon-only.png',
|
||||||
|
width: 52,
|
||||||
|
height: 52,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 14),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text('BitePlan',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.bold)),
|
||||||
|
Text('Versione $kAppVersion',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall
|
||||||
|
?.copyWith(color: scheme.onSurfaceVariant)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
// righe info
|
||||||
|
_InfoCard(children: [
|
||||||
|
_InfoRow(label: 'Autore', value: kAppAuthor),
|
||||||
|
_InfoRow(label: 'Licenza', value: kAppLicense),
|
||||||
|
_InfoRowButton(
|
||||||
|
label: 'Guida',
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (_) => const GuidePage()),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InfoCard extends StatelessWidget {
|
||||||
|
final List<Widget> children;
|
||||||
|
const _InfoCard({required this.children});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: scheme.outlineVariant),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Column(children: children),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InfoRow extends StatelessWidget {
|
||||||
|
final String label;
|
||||||
|
final String value;
|
||||||
|
const _InfoRow({required this.label, required this.value});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 13),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(label, style: Theme.of(context).textTheme.bodyMedium),
|
||||||
|
Text(value,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(color: scheme.onSurfaceVariant)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InfoRowButton extends StatelessWidget {
|
||||||
|
final String label;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
const _InfoRowButton({required this.label, required this.onTap});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
return InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
borderRadius: const BorderRadius.vertical(bottom: Radius.circular(12)),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 13),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(label, style: Theme.of(context).textTheme.bodyMedium),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text('Apri',
|
||||||
|
style: TextStyle(
|
||||||
|
color: scheme.primary, fontWeight: FontWeight.w600)),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Icon(Icons.chevron_right, size: 18, color: scheme.primary),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user