import 'package:flutter/material.dart'; import '../../../core/i18n/app_locale.dart'; import '../../../core/theme/tokens.dart'; import '../../home/home_screen.dart' show formatPop; import 'campaign_style.dart'; /// 캠페인 기여률 카드 — 시안 `272:245738`(상세) · `480:14594`(공유) 공용. /// /// #1a1a1c r12 안쪽 12/16. 라벨 12/500 · 「92%」(ABeeZee 32 + % 20) · 10 두께 막대 /// (바탕 #000 30%, 채움 그라디언트) · 0 / 목표. 채움 끝 위에 누적 POP 말풍선(100 폭)이 뜬다. class CampaignGauge extends StatelessWidget { const CampaignGauge({super.key, required this.raised, required this.goal}); final int raised; final int goal; @override Widget build(BuildContext context) { final ratio = goal == 0 ? 0.0 : (raised / goal).clamp(0.0, 1.0); final percent = goal == 0 ? 0 : ((raised / goal) * 100).round(); final axis = campaignText( 12, 400, const Color(0xFFCDCDCD), height: 1, spacing: 0, family: AppFonts.display, ); return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: AppColors.cosmicSurfaceContainer, borderRadius: BorderRadius.circular(AppRadius.md), ), child: LayoutBuilder( builder: (context, box) { final fill = box.maxWidth * ratio; return Stack( clipBehavior: Clip.none, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( context.l10n.campaignGaugeLabel, style: campaignText( 12, 500, AppColors.onCosmicVariant, height: 20 / 12, spacing: 0, ), ), Text.rich( TextSpan( text: '$percent', children: [ TextSpan( text: '%', style: TextStyle(fontSize: 20, letterSpacing: -0.5), ), ], ), style: campaignText( 32, 400, AppColors.onCosmic, height: 1.4, family: AppFonts.display, ), ), const SizedBox(height: 12), Stack( children: [ Container( height: 10, decoration: BoxDecoration( color: Colors.black.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(AppRadius.full), ), ), Container( width: fill, height: 10, decoration: BoxDecoration( gradient: campaignGradient, borderRadius: BorderRadius.circular(AppRadius.full), ), ), ], ), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('0', style: axis), Text(formatPop(goal), style: axis), ], ), ], ), Positioned( top: 31.5, left: (fill - 50).clamp(0.0, box.maxWidth - 100), child: _Bubble(label: formatPop(raised)), ), ], ); }, ), ); } } /// 누적 POP 말풍선 — 그라디언트 알약 100×32 + 아래 꼬리. class _Bubble extends StatelessWidget { const _Bubble({required this.label}); final String label; @override Widget build(BuildContext context) => SizedBox( width: 100, height: 38, child: Stack( alignment: Alignment.topCenter, children: [ Positioned( bottom: 0, child: Transform.rotate( angle: 0.785398, child: Container( width: 8, height: 8, color: const Color(0xFF5388CF), ), ), ), Container( height: 32, alignment: Alignment.center, decoration: BoxDecoration( gradient: campaignGradient, borderRadius: BorderRadius.circular(AppRadius.full), ), child: Text( label, style: campaignText( 12, 500, AppColors.onCosmic, height: 1, spacing: 0, ), ), ), ], ), ); }