|
|
@@ -3,85 +3,492 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
import 'package:go_router/go_router.dart';
|
|
|
import 'package:intl/intl.dart';
|
|
|
import '../../../providers/auth_provider.dart';
|
|
|
-import '../../../providers/database_provider.dart';
|
|
|
+import '../../../providers/order_provider.dart';
|
|
|
import '../../../database/database.dart';
|
|
|
+import '../../widgets/search_bar.dart' as sw;
|
|
|
import '../../widgets/empty_state.dart';
|
|
|
+import '../../../core/constants.dart';
|
|
|
|
|
|
-final ordersListProvider = FutureProvider.family<List<Ordine>, int>((ref, idAgente) {
|
|
|
- return ref.read(ordiniDaoProvider).getLastOrders(idAgente, 200);
|
|
|
-});
|
|
|
+String _statoLabel(String? stato) {
|
|
|
+ switch (stato) {
|
|
|
+ case AppConstants.kStatusNew:
|
|
|
+ return 'Nuovo';
|
|
|
+ case AppConstants.kStatusTransferred:
|
|
|
+ return 'Trasmesso';
|
|
|
+ case AppConstants.kStatoHold:
|
|
|
+ return 'Sospeso';
|
|
|
+ default:
|
|
|
+ return stato ?? '';
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+Color _statoColor(String? stato) {
|
|
|
+ switch (stato) {
|
|
|
+ case AppConstants.kStatusNew:
|
|
|
+ return Colors.orange;
|
|
|
+ case AppConstants.kStatusTransferred:
|
|
|
+ return Colors.green;
|
|
|
+ case AppConstants.kStatoHold:
|
|
|
+ return Colors.blue;
|
|
|
+ default:
|
|
|
+ return Colors.grey;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _StatoPill extends StatelessWidget {
|
|
|
+ final String? stato;
|
|
|
+ const _StatoPill({this.stato});
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final label = _statoLabel(stato);
|
|
|
+ final color = _statoColor(stato);
|
|
|
+
|
|
|
+ return Container(
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: color.withAlpha(25),
|
|
|
+ borderRadius: BorderRadius.circular(4),
|
|
|
+ ),
|
|
|
+ child: Text(
|
|
|
+ label,
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 12,
|
|
|
+ height: 16 / 12,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ color: color,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-class OrderListPage extends ConsumerWidget {
|
|
|
+class OrderListPage extends ConsumerStatefulWidget {
|
|
|
const OrderListPage({super.key});
|
|
|
|
|
|
@override
|
|
|
- Widget build(BuildContext context, WidgetRef ref) {
|
|
|
+ ConsumerState<OrderListPage> createState() => _OrderListPageState();
|
|
|
+}
|
|
|
+
|
|
|
+class _OrderListPageState extends ConsumerState<OrderListPage> {
|
|
|
+ String _filter = '';
|
|
|
+ final _searchCtrl = TextEditingController();
|
|
|
+
|
|
|
+ @override
|
|
|
+ void dispose() {
|
|
|
+ _searchCtrl.dispose();
|
|
|
+ super.dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
final agente = ref.watch(authProvider).agente;
|
|
|
- final ordersAsync = agente != null ? ref.watch(ordersListProvider(agente.idAgente)) : null;
|
|
|
- final theme = Theme.of(context);
|
|
|
+ final isPhone = MediaQuery.of(context).size.width < 600;
|
|
|
+
|
|
|
+ final ordersAsync = agente != null
|
|
|
+ ? ref.watch(
|
|
|
+ _filter.isEmpty
|
|
|
+ ? ordersViewProvider(agente.idAgente)
|
|
|
+ : ordersSearchViewProvider((
|
|
|
+ idAgente: agente.idAgente,
|
|
|
+ filter: _filter,
|
|
|
+ )),
|
|
|
+ )
|
|
|
+ : null;
|
|
|
+
|
|
|
+ final statsAsync = agente != null
|
|
|
+ ? ref.watch(orderStatsProvider(agente.idAgente))
|
|
|
+ : null;
|
|
|
|
|
|
return Scaffold(
|
|
|
- appBar: AppBar(title: const Text('Ordini')),
|
|
|
+ appBar: AppBar(title: const Text('Lista Ordini')),
|
|
|
floatingActionButton: FloatingActionButton(
|
|
|
onPressed: () => context.go('/dashboard/orders/new'),
|
|
|
child: const Icon(Icons.add),
|
|
|
),
|
|
|
- body: ordersAsync?.when(
|
|
|
- data: (orders) {
|
|
|
- if (orders.isEmpty) return const EmptyState(icon: Icons.receipt_long, title: 'Nessun ordine');
|
|
|
- return ListView.builder(
|
|
|
- padding: const EdgeInsets.all(8),
|
|
|
- itemCount: orders.length,
|
|
|
- itemBuilder: (_, i) => _OrderCard(order: orders[i], theme: theme, onTap: () => context.go('/dashboard/orders/${orders[i].idOrdine}')),
|
|
|
- );
|
|
|
- },
|
|
|
- loading: () => const Center(child: CircularProgressIndicator()),
|
|
|
- error: (e, _) => Center(child: Text('Errore: $e')),
|
|
|
- ) ?? const Center(child: CircularProgressIndicator()),
|
|
|
+ body: Column(
|
|
|
+ children: [
|
|
|
+ sw.SearchBarWidget(
|
|
|
+ controller: _searchCtrl,
|
|
|
+ hint: 'Cerca ordine, cliente, destinazione...',
|
|
|
+ onChanged: (v) => setState(() => _filter = v),
|
|
|
+ onClear: () {
|
|
|
+ _searchCtrl.clear();
|
|
|
+ setState(() => _filter = '');
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ Expanded(
|
|
|
+ child: ordersAsync?.when(
|
|
|
+ data: (orders) {
|
|
|
+ if (orders.isEmpty) {
|
|
|
+ return const EmptyState(
|
|
|
+ icon: Icons.receipt_long,
|
|
|
+ title: 'Nessun ordine',
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (isPhone) {
|
|
|
+ return ListView.builder(
|
|
|
+ padding: const EdgeInsets.all(16),
|
|
|
+ itemCount: orders.length,
|
|
|
+ itemBuilder: (_, i) => _OrderCard(order: orders[i]),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ return _OrderTable(orders: orders);
|
|
|
+ },
|
|
|
+ loading: () => const Center(child: CircularProgressIndicator()),
|
|
|
+ error: (e, _) => Center(child: Text('Errore: $e')),
|
|
|
+ ) ?? const Center(child: CircularProgressIndicator()),
|
|
|
+ ),
|
|
|
+ if (statsAsync != null)
|
|
|
+ statsAsync.when(
|
|
|
+ data: (stats) => _StatsBar(stats: stats),
|
|
|
+ loading: () => const SizedBox(height: 80),
|
|
|
+ error: (_, _) => const SizedBox.shrink(),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class _OrderCard extends StatelessWidget {
|
|
|
- final Ordine order;
|
|
|
- final ThemeData theme;
|
|
|
- final VoidCallback onTap;
|
|
|
-
|
|
|
- const _OrderCard({required this.order, required this.theme, required this.onTap});
|
|
|
+ final VOrdiniData order;
|
|
|
+ const _OrderCard({required this.order});
|
|
|
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
- final statoColor = switch (order.stato) {
|
|
|
- 'N' => Colors.orange,
|
|
|
- 'T' => Colors.green,
|
|
|
- 'H' => Colors.blue,
|
|
|
- _ => Colors.grey,
|
|
|
- };
|
|
|
+ final theme = Theme.of(context);
|
|
|
+ final cs = theme.colorScheme;
|
|
|
+ final dateFormat = DateFormat('dd/MM/yyyy');
|
|
|
+ final currencyFormat = NumberFormat.currency(symbol: '€ ', decimalDigits: 2);
|
|
|
|
|
|
return Card(
|
|
|
- margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
|
- child: ListTile(
|
|
|
- onTap: onTap,
|
|
|
- leading: CircleAvatar(
|
|
|
- backgroundColor: statoColor.withAlpha(30),
|
|
|
- child: Text(order.numeroOrdine?.toString() ?? '?', style: TextStyle(color: statoColor, fontWeight: FontWeight.bold)),
|
|
|
+ margin: const EdgeInsets.only(bottom: 12),
|
|
|
+ elevation: 0,
|
|
|
+ color: Colors.white,
|
|
|
+ shape: RoundedRectangleBorder(
|
|
|
+ borderRadius: BorderRadius.circular(12),
|
|
|
+ side: BorderSide(color: cs.outlineVariant),
|
|
|
+ ),
|
|
|
+ child: InkWell(
|
|
|
+ onTap: () => context.push('/dashboard/orders/${order.idOrdine}'),
|
|
|
+ borderRadius: BorderRadius.circular(12),
|
|
|
+ child: Padding(
|
|
|
+ padding: const EdgeInsets.all(16),
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ Row(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ Expanded(
|
|
|
+ child: Text(
|
|
|
+ '#${order.numeroOrdine ?? ''}',
|
|
|
+ style: theme.textTheme.titleMedium?.copyWith(
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Text(
|
|
|
+ order.dataOrdine != null
|
|
|
+ ? dateFormat.format(DateTime.parse(order.dataOrdine!))
|
|
|
+ : '',
|
|
|
+ style: theme.textTheme.bodyMedium?.copyWith(
|
|
|
+ color: cs.onSurfaceVariant,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 4),
|
|
|
+ Text(
|
|
|
+ '${order.codCliente ?? ''} - ${order.ragioneSociale ?? ''}',
|
|
|
+ style: theme.textTheme.bodyMedium,
|
|
|
+ maxLines: 1,
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
+ ),
|
|
|
+ if ((order.filiale ?? '').isNotEmpty) ...[
|
|
|
+ const SizedBox(height: 4),
|
|
|
+ Text(
|
|
|
+ 'Filiale: ${order.filiale}',
|
|
|
+ style: theme.textTheme.bodySmall?.copyWith(color: cs.onSurfaceVariant),
|
|
|
+ maxLines: 1,
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ if ((order.indirizzo ?? '').isNotEmpty) ...[
|
|
|
+ const SizedBox(height: 2),
|
|
|
+ Text(
|
|
|
+ '${order.indirizzo}${order.citta != null ? ', ${order.citta}' : ''}',
|
|
|
+ style: theme.textTheme.bodySmall?.copyWith(color: cs.onSurfaceVariant),
|
|
|
+ maxLines: 1,
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ const SizedBox(height: 12),
|
|
|
+ Row(
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ 'Totale: ${currencyFormat.format(order.totale ?? 0)}',
|
|
|
+ style: theme.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold),
|
|
|
+ ),
|
|
|
+ const Spacer(),
|
|
|
+ _StatoPill(stato: order.stato),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
),
|
|
|
- title: Text('Ordine #${order.numeroOrdine ?? ''}'),
|
|
|
- subtitle: Text(order.riferimento ?? order.noteCliente ?? ''),
|
|
|
- trailing: Row(
|
|
|
- mainAxisSize: MainAxisSize.min,
|
|
|
- children: [
|
|
|
- Container(
|
|
|
- padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
|
|
- decoration: BoxDecoration(color: statoColor.withAlpha(20), borderRadius: BorderRadius.circular(12)),
|
|
|
- child: Text(
|
|
|
- order.stato == 'N' ? 'Nuovo' : order.stato == 'T' ? 'Trasmesso' : 'Sospeso',
|
|
|
- style: TextStyle(color: statoColor, fontSize: 12),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _OrderTable extends StatelessWidget {
|
|
|
+ final List<VOrdiniData> orders;
|
|
|
+ const _OrderTable({required this.orders});
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final theme = Theme.of(context);
|
|
|
+ final cs = theme.colorScheme;
|
|
|
+ final dateFormat = DateFormat('dd/MM/yyyy');
|
|
|
+ final currencyFormat = NumberFormat.currency(symbol: '€ ', decimalDigits: 2);
|
|
|
+
|
|
|
+ return SingleChildScrollView(
|
|
|
+ scrollDirection: Axis.horizontal,
|
|
|
+ child: SizedBox(
|
|
|
+ width: 900,
|
|
|
+ child: SingleChildScrollView(
|
|
|
+ scrollDirection: Axis.vertical,
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
|
+ children: [
|
|
|
+ Container(
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: cs.surfaceContainerHigh.withAlpha(50),
|
|
|
+ border: Border(bottom: BorderSide(color: cs.outlineVariant)),
|
|
|
+ ),
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ _headerCell(context, 'Numero Ordine', flex: 2),
|
|
|
+ _headerCell(context, 'Data', flex: 1),
|
|
|
+ _headerCell(context, 'Cliente', flex: 3),
|
|
|
+ _headerCell(context, 'Destinazione', flex: 2),
|
|
|
+ _headerCell(context, 'Totale', flex: 1),
|
|
|
+ _headerCell(context, 'Stato', flex: 1),
|
|
|
+ _headerCell(context, 'Azioni', flex: 1),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
),
|
|
|
- ),
|
|
|
- ],
|
|
|
+ ...orders.map((o) {
|
|
|
+ return Container(
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ border: Border(bottom: BorderSide(color: cs.outlineVariant.withAlpha(80))),
|
|
|
+ ),
|
|
|
+ child: InkWell(
|
|
|
+ onTap: () => context.push('/dashboard/orders/${o.idOrdine}'),
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ _cell(
|
|
|
+ Text(
|
|
|
+ '#${o.numeroOrdine ?? ''}',
|
|
|
+ style: theme.textTheme.bodyMedium?.copyWith(
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ fontFamily: 'monospace',
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ flex: 2,
|
|
|
+ ),
|
|
|
+ _cell(
|
|
|
+ Text(
|
|
|
+ o.dataOrdine != null
|
|
|
+ ? dateFormat.format(DateTime.parse(o.dataOrdine!))
|
|
|
+ : '',
|
|
|
+ style: theme.textTheme.bodyMedium?.copyWith(color: cs.onSurfaceVariant),
|
|
|
+ ),
|
|
|
+ flex: 1,
|
|
|
+ ),
|
|
|
+ _cell(
|
|
|
+ Text(
|
|
|
+ '${o.codCliente ?? ''} - ${o.ragioneSociale ?? ''}',
|
|
|
+ style: theme.textTheme.bodyMedium,
|
|
|
+ maxLines: 1,
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
+ ),
|
|
|
+ flex: 3,
|
|
|
+ ),
|
|
|
+ _cell(
|
|
|
+ Text(
|
|
|
+ '${o.citta ?? ''}${o.provincia != null ? ' (${o.provincia})' : ''}',
|
|
|
+ style: theme.textTheme.bodyMedium?.copyWith(color: cs.onSurfaceVariant),
|
|
|
+ maxLines: 1,
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
+ ),
|
|
|
+ flex: 2,
|
|
|
+ ),
|
|
|
+ _cell(
|
|
|
+ Text(
|
|
|
+ currencyFormat.format(o.totale ?? 0),
|
|
|
+ style: theme.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold),
|
|
|
+ ),
|
|
|
+ flex: 1,
|
|
|
+ ),
|
|
|
+ _cell(_StatoPill(stato: o.stato), flex: 1),
|
|
|
+ _cell(
|
|
|
+ IconButton(
|
|
|
+ icon: Icon(Icons.visibility, size: 20, color: cs.secondary),
|
|
|
+ onPressed: () => context.push('/dashboard/orders/${o.idOrdine}'),
|
|
|
+ visualDensity: VisualDensity.compact,
|
|
|
+ ),
|
|
|
+ flex: 1,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _headerCell(BuildContext context, String label, {int flex = 1}) {
|
|
|
+ final cs = Theme.of(context).colorScheme;
|
|
|
+ return Expanded(
|
|
|
+ flex: flex,
|
|
|
+ child: Text(
|
|
|
+ label,
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 12,
|
|
|
+ fontWeight: FontWeight.w600,
|
|
|
+ color: cs.onSurfaceVariant,
|
|
|
),
|
|
|
),
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+ Widget _cell(Widget child, {int flex = 1}) {
|
|
|
+ return Expanded(flex: flex, child: child);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _StatsBar extends StatelessWidget {
|
|
|
+ final OrderStats stats;
|
|
|
+ const _StatsBar({required this.stats});
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final theme = Theme.of(context);
|
|
|
+ final cs = theme.colorScheme;
|
|
|
+ final currencyFormat = NumberFormat.currency(symbol: '€ ', decimalDigits: 2);
|
|
|
+
|
|
|
+ return Container(
|
|
|
+ padding: const EdgeInsets.all(16),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: cs.surface,
|
|
|
+ border: Border(top: BorderSide(color: cs.outlineVariant)),
|
|
|
+ ),
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ Expanded(
|
|
|
+ child: _StatCard(
|
|
|
+ icon: Icons.shopping_cart,
|
|
|
+ iconBgColor: cs.secondaryContainer.withAlpha(30),
|
|
|
+ iconColor: cs.secondary,
|
|
|
+ label: 'Volume Mensile',
|
|
|
+ value: currencyFormat.format(stats.volumeMensile),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 12),
|
|
|
+ Expanded(
|
|
|
+ child: _StatCard(
|
|
|
+ icon: Icons.pending_actions,
|
|
|
+ iconBgColor: Colors.orange.withAlpha(30),
|
|
|
+ iconColor: Colors.orange,
|
|
|
+ label: 'Da Trasmettere',
|
|
|
+ value: stats.daTrasmettere.toString(),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 12),
|
|
|
+ Expanded(
|
|
|
+ child: _StatCard(
|
|
|
+ icon: Icons.verified,
|
|
|
+ iconBgColor: Colors.green.withAlpha(30),
|
|
|
+ iconColor: Colors.green,
|
|
|
+ label: 'Numero Ordini',
|
|
|
+ value: stats.numeroOrdini.toString(),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _StatCard extends StatelessWidget {
|
|
|
+ final IconData icon;
|
|
|
+ final Color iconBgColor;
|
|
|
+ final Color iconColor;
|
|
|
+ final String label;
|
|
|
+ final String value;
|
|
|
+ const _StatCard({
|
|
|
+ required this.icon,
|
|
|
+ required this.iconBgColor,
|
|
|
+ required this.iconColor,
|
|
|
+ required this.label,
|
|
|
+ required this.value,
|
|
|
+ });
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final theme = Theme.of(context);
|
|
|
+ final cs = theme.colorScheme;
|
|
|
+
|
|
|
+ return Container(
|
|
|
+ padding: const EdgeInsets.all(12),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: Colors.white,
|
|
|
+ borderRadius: BorderRadius.circular(12),
|
|
|
+ border: Border.all(color: cs.outlineVariant),
|
|
|
+ ),
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ Container(
|
|
|
+ width: 40,
|
|
|
+ height: 40,
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: iconBgColor,
|
|
|
+ shape: BoxShape.circle,
|
|
|
+ ),
|
|
|
+ child: Icon(icon, color: iconColor, size: 20),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 12),
|
|
|
+ Expanded(
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ label,
|
|
|
+ style: theme.textTheme.labelSmall?.copyWith(color: cs.onSurfaceVariant),
|
|
|
+ maxLines: 1,
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 2),
|
|
|
+ Text(
|
|
|
+ value,
|
|
|
+ style: theme.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
|
|
+ maxLines: 1,
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
}
|