import 'package:flutter/material.dart'; import '../../../../api/connect/rmv/rmv_models.dart'; import '../../../../extensions/date_time.dart'; import 'product_chip.dart'; import 'realtime_time.dart'; /// Compact summary of a [Trip] used in the trip results list. class TripTile extends StatelessWidget { final Trip trip; final VoidCallback? onTap; const TripTile({super.key, required this.trip, this.onTap}); @override Widget build(BuildContext context) { final firstLeg = trip.legs.isEmpty ? null : trip.legs.first; final lastLeg = trip.legs.isEmpty ? null : trip.legs.last; if (firstLeg == null || lastLeg == null) { return const ListTile(title: Text('Verbindung ohne Halt')); } final scheduledStart = firstLeg.origin.scheduledTime; final scheduledEnd = lastLeg.destination.scheduledTime; final cancelled = trip.legs.any((l) => l.cancelled || l.partCancelled); final transfers = trip.transferCount ?? _countTransfers(trip); final duration = trip.realDuration ?? trip.duration; final productChips = trip.legs .where((l) => l.type == LegType.journey && l.product != null) .map((l) => Padding( padding: const EdgeInsets.only(right: 4), child: ProductChip(product: l.product, fallbackLabel: l.name), )) .toList(); return ListTile( onTap: onTap, isThreeLine: true, title: Row( children: [ RealtimeTime( scheduled: scheduledStart, realtime: firstLeg.origin.realTime, delayMinutes: firstLeg.origin.delayMinutes?.toInt(), cancelled: cancelled, style: Theme.of(context).textTheme.titleMedium, ), const Padding( padding: EdgeInsets.symmetric(horizontal: 6), child: Text('–'), ), RealtimeTime( scheduled: scheduledEnd, realtime: lastLeg.destination.realTime, delayMinutes: lastLeg.destination.delayMinutes?.toInt(), cancelled: cancelled, style: Theme.of(context).textTheme.titleMedium, ), ], ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 4), Wrap(runSpacing: 4, children: productChips), const SizedBox(height: 4), Row( children: [ if (duration != null) ...[ const Icon(Icons.schedule, size: 14), const SizedBox(width: 2), Text(_formatDuration(duration)), const SizedBox(width: 12), ], const Icon(Icons.swap_horiz, size: 14), const SizedBox(width: 2), Text( transfers == 0 ? 'Direkt' : '$transfers Umstieg${transfers > 1 ? 'e' : ''}', ), ], ), ], ), trailing: const Icon(Icons.chevron_right), ); } int _countTransfers(Trip trip) { final journeyLegs = trip.legs.where((l) => l.type == LegType.journey).length; return journeyLegs <= 1 ? 0 : journeyLegs - 1; } } String _formatDuration(Duration d) { final hours = d.inHours; final minutes = d.inMinutes.remainder(60); if (hours == 0) return '$minutes min'; return '$hours h ${minutes.toString().padLeft(2, '0')} min'; } /// Re-export for trip detail screen. String formatTripDuration(Duration d) => _formatDuration(d); /// Helper used in date headers on the trip results list. String formatTripDateHeader(DateTime when) => when.formatDateRelativeShort();