// quota_card.dart — 免费版每日额度卡(纯展示) // // 今日剩余分钟 + 进度条(≤3 分钟切 warning 色)+「看广告开始使用」; // 解锁后变绿「已解锁 · 今日可用」。状态由 quota_provider 注入,本地仅展示。 import 'package:flutter/material.dart'; import '../l10n/app_text.dart'; import '../pangolin_theme.dart'; import '../state/quota_provider.dart'; import 'pangolin_icons.dart'; class QuotaCard extends StatelessWidget { const QuotaCard({super.key, required this.quota, required this.t, required this.onWatchAd}); final FreeQuotaState quota; final AppText t; final VoidCallback onWatchAd; @override Widget build(BuildContext context) { final c = context.pangolin; final barColor = quota.isLow ? c.warning : c.accent; return Container( padding: const EdgeInsets.fromLTRB(14, 12, 14, 12), decoration: BoxDecoration( color: c.surface, borderRadius: BorderRadius.circular(PangolinRadius.lg), border: Border.all(color: c.border), boxShadow: PangolinShadow.sm, ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row(children: [ Icon(PangolinIcons.clock, size: 15, color: c.accent), const SizedBox(width: 7), Text(t.quotaToday, style: PangolinText.caption.copyWith(color: c.fg2, fontWeight: FontWeight.w600, fontSize: 12)), const SizedBox(width: 7), Text('${quota.remainingMinutes} ${t.minutes}', style: PangolinText.mono.copyWith(color: c.fg1, fontSize: 14, fontWeight: FontWeight.w600)), const Spacer(), Container( padding: const EdgeInsets.symmetric(horizontal: 9, vertical: 3), decoration: BoxDecoration(color: c.bgSubtle, borderRadius: BorderRadius.circular(PangolinRadius.full)), child: Text(t.quotaFree, style: PangolinText.caption.copyWith(color: c.fg3, fontWeight: FontWeight.w600, fontSize: 10.5)), ), ]), const SizedBox(height: 9), // 进度条:剩余比例;≤3 分钟切 warning 色(满宽轨道 + 比例填充) ClipRRect( borderRadius: BorderRadius.circular(3), child: SizedBox( height: 6, child: Stack(children: [ Positioned.fill(child: ColoredBox(color: c.bgSubtle)), FractionallySizedBox( alignment: Alignment.centerLeft, widthFactor: quota.progress, child: AnimatedContainer( duration: PangolinMotion.base, curve: PangolinMotion.easeOut, decoration: BoxDecoration(color: barColor, borderRadius: BorderRadius.circular(3)), ), ), ]), ), ), const SizedBox(height: 11), if (quota.adUnlocked) SizedBox( height: 38, child: Center( child: Row(mainAxisSize: MainAxisSize.min, children: [ Icon(PangolinIcons.checkCircle, size: 16, color: c.success), const SizedBox(width: 7), Text(t.adUnlocked, style: PangolinText.sm.copyWith(color: c.success, fontWeight: FontWeight.w700, fontSize: 13)), ]), ), ) else _WatchAdButton(t: t, onTap: onWatchAd), ], ), ); } } class _WatchAdButton extends StatelessWidget { const _WatchAdButton({required this.t, required this.onTap}); final AppText t; final VoidCallback onTap; @override Widget build(BuildContext context) { final c = context.pangolin; return Material( color: c.accentSubtle, shape: StadiumBorder(side: BorderSide(color: c.accentBorder, width: 1.5)), clipBehavior: Clip.antiAlias, child: InkWell( onTap: onTap, child: SizedBox( height: 38, child: Center( child: Row(mainAxisSize: MainAxisSize.min, children: [ Icon(PangolinIcons.playCircle, size: 16, color: c.accent), const SizedBox(width: 7), Text(t.watchAd, style: PangolinText.sm.copyWith(color: c.accent, fontWeight: FontWeight.w700, fontSize: 13)), ]), ), ), ), ); } }