depor_os/lib/screens/dashboard/dashboard_screen.dart
Daniel Esteban 34e7cbc382 first commit
2026-03-18 12:47:06 +01:00

186 lines
5.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class DashboardScreen extends StatelessWidget {
const DashboardScreen({super.key});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
final tt = Theme.of(context).textTheme;
return SingleChildScrollView(
padding: const EdgeInsets.all(32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Inicio',
style: tt.headlineMedium?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 4),
Text(
'Accesos rápidos',
style: tt.bodyLarge?.copyWith(color: cs.onSurfaceVariant),
),
const SizedBox(height: 32),
_QuickAccessGrid(),
],
),
);
}
}
// ── Grid de accesos rápidos ───────────────────────────────────────────────
class _QuickAccessGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final columns = constraints.maxWidth >= 900 ? 4 : 2;
final spacing = 16.0;
final cardWidth =
(constraints.maxWidth - spacing * (columns - 1)) / columns;
return Wrap(
spacing: spacing,
runSpacing: spacing,
children: _kShortcuts
.map((s) => SizedBox(
width: cardWidth,
child: _ShortcutCard(shortcut: s),
))
.toList(),
);
},
);
}
}
// ── Tarjeta individual ────────────────────────────────────────────────────
class _ShortcutCard extends StatelessWidget {
final _Shortcut shortcut;
const _ShortcutCard({required this.shortcut});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
final tt = Theme.of(context).textTheme;
final bgColor = shortcut.color.resolve(cs);
final fgColor = shortcut.foreground.resolve(cs);
return Card(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
side: BorderSide(color: cs.outlineVariant),
),
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () => context.go(shortcut.route),
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 52,
height: 52,
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(14),
),
child: Icon(shortcut.icon, color: fgColor, size: 26),
),
const SizedBox(height: 20),
Text(
shortcut.title,
style: tt.titleMedium?.copyWith(fontWeight: FontWeight.w600),
),
const SizedBox(height: 4),
Text(
shortcut.subtitle,
style: tt.bodySmall?.copyWith(color: cs.onSurfaceVariant),
),
],
),
),
),
);
}
}
// ── Datos ─────────────────────────────────────────────────────────────────
class _Shortcut {
final String title;
final String subtitle;
final IconData icon;
final String route;
final _SchemeColor color;
final _SchemeColor foreground;
const _Shortcut({
required this.title,
required this.subtitle,
required this.icon,
required this.route,
required this.color,
required this.foreground,
});
}
/// Referencia indirecta a un color del ColorScheme para evitar context en const.
class _SchemeColor {
final Color Function(ColorScheme) resolve;
const _SchemeColor(this.resolve);
}
const _kShortcuts = [
_Shortcut(
title: 'Abonados',
subtitle: 'Gestionar abonados del club',
icon: Icons.people_outlined,
route: '/abonados',
color: _SchemeColor(_primary),
foreground: _SchemeColor(_onPrimary),
),
_Shortcut(
title: 'Reservas',
subtitle: 'Reservas de pistas',
icon: Icons.sports_tennis_outlined,
route: '/reservas',
color: _SchemeColor(_secondary),
foreground: _SchemeColor(_onSecondary),
),
_Shortcut(
title: 'Recibos',
subtitle: 'Recibos por abonado',
icon: Icons.receipt_long_outlined,
route: '/recibos/abonado',
color: _SchemeColor(_tertiary),
foreground: _SchemeColor(_onTertiary),
),
_Shortcut(
title: 'Caja',
subtitle: 'Movimientos y cobros',
icon: Icons.point_of_sale_outlined,
route: '/caja',
color: _SchemeColor(_error),
foreground: _SchemeColor(_onError),
),
];
// Funciones top-level para poder usarlas en const
Color _primary(ColorScheme cs) => cs.primaryContainer;
Color _onPrimary(ColorScheme cs) => cs.onPrimaryContainer;
Color _secondary(ColorScheme cs) => cs.secondaryContainer;
Color _onSecondary(ColorScheme cs) => cs.onSecondaryContainer;
Color _tertiary(ColorScheme cs) => cs.tertiaryContainer;
Color _onTertiary(ColorScheme cs) => cs.onTertiaryContainer;
Color _error(ColorScheme cs) => cs.errorContainer;
Color _onError(ColorScheme cs) => cs.onErrorContainer;