import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../models/subscription_model.dart'; import '../../controllers/detail_screen_controller.dart'; import '../../providers/locale_provider.dart'; import '../../providers/payment_card_provider.dart'; import '../../services/currency_util.dart'; import '../../utils/payment_card_utils.dart'; import '../../models/payment_card_model.dart'; import '../payment_card/payment_card_form_sheet.dart'; import '../../routes/app_routes.dart'; import '../website_icon.dart'; import '../../l10n/app_localizations.dart'; /// 상세 화면 상단 헤더 섹션 /// 서비스 아이콘, 이름, 결제 정보를 표시합니다. class DetailHeaderSection extends StatelessWidget { final SubscriptionModel subscription; final DetailScreenController controller; final Animation fadeAnimation; final Animation slideAnimation; final Animation rotateAnimation; const DetailHeaderSection({ super.key, required this.subscription, required this.controller, required this.fadeAnimation, required this.slideAnimation, required this.rotateAnimation, }); @override Widget build(BuildContext context) { return Consumer( builder: (context, controller, child) { final baseColor = controller.getCardColor(); final paymentCardProvider = context.watch(); final paymentCard = paymentCardProvider.getCardById( controller.selectedPaymentCardId ?? subscription.paymentCardId, ); return Container( constraints: const BoxConstraints(minHeight: 320), decoration: BoxDecoration(color: baseColor), child: Stack( children: [ // 배경 패턴 Positioned( top: -50, right: -50, child: RotationTransition( turns: rotateAnimation, child: Container( width: 200, height: 200, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.white.withValues(alpha: 0.1), ), ), ), ), Positioned( bottom: -30, left: -30, child: Container( width: 150, height: 150, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.white.withValues(alpha: 0.08), ), ), ), // 콘텐츠 SafeArea( child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // 뒤로가기 버튼 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( icon: const Icon( Icons.arrow_back_ios_new_rounded, color: Colors.white, ), onPressed: () => Navigator.of(context).pop(), ), IconButton( icon: const Icon( Icons.delete_outline_rounded, color: Colors.white, ), onPressed: controller.deleteSubscription, ), ], ), const SizedBox(height: 16), // 서비스 정보 FadeTransition( opacity: fadeAnimation, child: SlideTransition( position: slideAnimation, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 서비스 아이콘과 이름 Row( children: [ Hero( tag: 'icon_${subscription.id}', child: Container( width: 56, height: 56, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black .withValues(alpha: 0.1), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(16), child: WebsiteIcon( url: controller .websiteUrlController.text, serviceName: controller .serviceNameController.text, size: 48, ), ), ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( controller.displayName ?? controller .serviceNameController.text, style: const TextStyle( fontSize: 28, fontWeight: FontWeight.w800, color: Colors.white, letterSpacing: -0.5, shadows: [ Shadow( color: Colors.black26, offset: Offset(0, 2), blurRadius: 4, ), ], ), ), const SizedBox(height: 4), Text( AppLocalizations.of(context) .billingCyclePayment .replaceAll( '@', _getLocalizedBillingCycle( context, controller.billingCycle)), style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, color: Colors.white .withValues(alpha: 0.8), ), ), const SizedBox(height: 12), _buildPaymentCardChip( context, paymentCard, ), ], ), ), ], ), const SizedBox(height: 20), // 결제 정보 카드 Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(16), ), child: Row( children: [ Expanded( child: _InfoColumn( label: AppLocalizations.of(context) .nextBillingDate, value: AppLocalizations.of(context) .formatDate( controller.nextBillingDate), ), ), const SizedBox(width: 12), Expanded( child: FutureBuilder( future: () async { final locale = context .read() .locale .languageCode; final amount = double.tryParse( controller .monthlyCostController .text .replaceAll(',', '')) ?? 0; return CurrencyUtil .formatAmountWithLocale( amount, controller.currency, locale, ); }(), builder: (context, snapshot) { return _InfoColumn( label: AppLocalizations.of(context) .monthlyExpense, value: snapshot.data ?? '-', alignment: CrossAxisAlignment.end, wrapValue: true, ); }, ), ), ], ), ), ], ), ), ), ], ), ), ), ], ), ); }, ); } String _getLocalizedBillingCycle(BuildContext context, String cycle) { final loc = AppLocalizations.of(context); switch (cycle.toLowerCase()) { case '매월': case '월간': case 'monthly': case '毎月': case '月付': case '月間': case '每月': return loc.billingCycleMonthly; case '분기별': case '분기': case 'quarterly': case 'quarter': case '季付': case '季度付': case '四半期': case '每季度': return loc.billingCycleQuarterly; case '반기별': case 'half-yearly': case 'half yearly': case 'semiannual': case 'semi-annual': case '半年付': case '半年払い': case '半年ごと': case '每半年': return loc.billingCycleHalfYearly; case '매년': case '연간': case 'yearly': case 'annual': case 'annually': case '年間': case '年付': case '每年': return loc.billingCycleYearly; default: return cycle; } } Widget _buildPaymentCardChip( BuildContext context, PaymentCardModel? card, ) { final loc = AppLocalizations.of(context); if (card == null) { return GestureDetector( onTap: () { Navigator.of(context).pushNamed(AppRoutes.paymentCardManagement); }, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(24), border: Border.all( color: Colors.white.withValues(alpha: 0.2), ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.credit_card_off_rounded, color: Colors.white, size: 16, ), const SizedBox(width: 8), Text( loc.paymentCardUnassigned, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Colors.white, ), ), const SizedBox(width: 8), Icon( Icons.arrow_forward_ios_rounded, color: Colors.white.withValues(alpha: 0.7), size: 14, ), ], ), ), ); } final color = PaymentCardUtils.colorFromHex(card.colorHex); final icon = PaymentCardUtils.iconForName(card.iconName); return GestureDetector( onTap: () async { await PaymentCardFormSheet.show(context, card: card); }, child: Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 9), decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(28), border: Border.all( color: color.withValues(alpha: 0.5), ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ CircleAvatar( radius: 14, backgroundColor: Colors.white, child: Icon( icon, size: 16, color: color, ), ), const SizedBox(width: 10), Text( '${card.issuerName} · ****${card.last4}', style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w700, color: Colors.white, ), ), const SizedBox(width: 8), Icon( Icons.edit_rounded, size: 16, color: Colors.white.withValues(alpha: 0.8), ), ], ), ), ); } } /// 정보 표시 컬럼 class _InfoColumn extends StatelessWidget { final String label; final String value; final CrossAxisAlignment alignment; final bool wrapValue; const _InfoColumn({ required this.label, required this.value, this.alignment = CrossAxisAlignment.start, this.wrapValue = false, }); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: alignment, children: [ Text( label, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white.withValues(alpha: 0.8), ), ), const SizedBox(height: 4), if (wrapValue) Text( value, textAlign: TextAlign.end, maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: Colors.white, ), ) else Text( value, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: Colors.white, ), ), ], ); } }