import 'package:flutter/material.dart'; import '../theme/app_theme.dart'; /// Green gradient hero banner background shared by every screen that shows /// a totals summary (Receipts, Vehicle Detail) — callers supply their own /// stat row / controls as [child], keeping the container/gradient styling /// itself in one place. class HeroBanner extends StatelessWidget { final Widget child; const HeroBanner({super.key, required this.child}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.fromLTRB(20, 16, 20, 10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: AppTheme.heroGradient(context), ), ), child: child, ); } } /// A single label/value pair inside a [HeroBanner], e.g. "Total Gallons". class HeroStat extends StatelessWidget { final String label; final String value; final bool alignEnd; const HeroStat({super.key, required this.label, required this.value, required this.alignEnd}); @override Widget build(BuildContext context) { final textAlign = alignEnd ? TextAlign.end : TextAlign.start; return Column( crossAxisAlignment: alignEnd ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [ Text( label, textAlign: textAlign, style: TextStyle( color: AppTheme.heroTextSecondary(context), fontSize: 12, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 4), Text( value, textAlign: textAlign, style: const TextStyle( color: AppTheme.heroText, fontSize: 28, fontWeight: FontWeight.w800, letterSpacing: -0.5, ), ), ], ); } } /// The icon + two-stat row shared by every hero banner: gallons on the /// left, the hero icon (or, if [estimatedRefundValue] is given, the /// estimated fuel refund in its place — see the Receipts tab, the only /// caller that ever passes it) in the middle, cost on the right. class HeroStatsRow extends StatelessWidget { final String gallonsValue; final String costValue; final String gallonsLabel; final String costLabel; final String? estimatedRefundValue; const HeroStatsRow({ super.key, required this.gallonsValue, required this.costValue, this.gallonsLabel = 'Total Gallons', this.costLabel = 'Total Fuel Cost', this.estimatedRefundValue, }); @override Widget build(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(child: HeroStat(label: gallonsLabel, value: gallonsValue, alignEnd: false)), Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: estimatedRefundValue == null // Tall enough to extend past the bottom of the label+value // text next to it, not just match the label's height — width // scales automatically from the source's own aspect ratio // since only height is given. ? Image.asset( 'assets/icon/hero_icon.png', height: 58, fit: BoxFit.contain, ) : _EstimatedRefundStat(value: estimatedRefundValue!), ), Expanded(child: HeroStat(label: costLabel, value: costValue, alignEnd: true)), ], ); } } /// The estimated-fuel-refund stat that takes the hero icon's place in the /// middle of [HeroStatsRow] when that's turned on — smaller/more compact /// than [HeroStat] since it sits in the narrower middle slot rather than /// an [Expanded] one. class _EstimatedRefundStat extends StatelessWidget { final String value; const _EstimatedRefundStat({required this.value}); @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, children: [ Text( 'Est. Refund', textAlign: TextAlign.center, style: TextStyle( color: AppTheme.heroTextSecondary(context), fontSize: 10, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 4), Text( value, textAlign: TextAlign.center, style: const TextStyle( color: AppTheme.heroText, fontSize: 30, fontWeight: FontWeight.w800, ), ), ], ); } }