import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:flutter_animate/flutter_animate.dart'; import '../../core/theme/app_spacing.dart'; import '../../core/theme/app_theme_extension.dart'; /// 資產卡片組件 - 用於顯示資產總覽 /// /// 設計規則 ("The Kinetic Vault"): /// - 漸變背景: Neon Blue → Electric Purple /// - 圓角: xl (16px) /// - 無邊框,使用漸變層次 /// - 微妙陰影: 10% black, blur 10px class AssetCard extends StatelessWidget { final String title; final String balance; final String? subtitle; final String? profit; final bool? isProfit; final List? items; final Gradient? gradient; final VoidCallback? onTap; const AssetCard({ super.key, this.title = '總資產', required this.balance, this.subtitle, this.profit, this.isProfit, this.items, this.gradient, this.onTap, }); @override Widget build(BuildContext context) { final theme = ShadTheme.of(context); final colorScheme = context.colors; final appColors = context.appColors; final cardGradient = gradient ?? appColors.assetGradient; // 主題感知顏色 - 在漸變背景上使用 onPrimary final primaryTextColor = colorScheme.onPrimary; final secondaryTextColor = colorScheme.onPrimary.withValues(alpha: 0.7); return GestureDetector( onTap: onTap, child: Container( width: double.infinity, padding: const EdgeInsets.all(AppSpacing.lg), decoration: BoxDecoration( gradient: cardGradient, borderRadius: BorderRadius.circular(AppRadius.xl), boxShadow: [ BoxShadow( color: colorScheme.onSurface.withValues(alpha: 0.1), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 標題行 Row( children: [ Text( title, style: theme.textTheme.small.copyWith(color: secondaryTextColor), ), const Spacer(), if (onTap != null) Icon( LucideIcons.chevronRight, color: secondaryTextColor, size: 18, ), ], ), const SizedBox(height: AppSpacing.sm), // 餘額 - 大標題 Text( balance, style: theme.textTheme.h1.copyWith( fontWeight: FontWeight.bold, color: primaryTextColor, fontSize: 20, ), ), // 盈虧信息 if (profit != null) ...[ const SizedBox(height: AppSpacing.md), Row( children: [ Icon( isProfit == true ? LucideIcons.trendingUp : LucideIcons.trendingDown, color: secondaryTextColor, size: 16, ), const SizedBox(width: 6), Text( '盈虧: $profit', style: theme.textTheme.small.copyWith(color: secondaryTextColor), ), ], ), ], // 子項 if (items != null && items!.isNotEmpty) ...[ const SizedBox(height: AppSpacing.lg), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: items!.map((item) => _buildItem(item, primaryTextColor, secondaryTextColor)).toList(), ), ], ], ), ), ).animate().fadeIn(duration: 400.ms).slideY(begin: 0.1, end: 0); } Widget _buildItem(AssetItem item, Color primaryTextColor, Color secondaryTextColor) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.label, style: TextStyle(fontSize: 12, color: secondaryTextColor), ), const SizedBox(height: 4), Text( item.value, style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: primaryTextColor, ), ), ], ); } } /// 資產子項 class AssetItem { final String label; final String value; const AssetItem({ required this.label, required this.value, }); } /// 簡潔資產卡片 - 用於列表中顯示 /// /// 設計規則: /// - 使用 surface 層次而非邊框 /// - 圓角: xl (16px) /// - 漲跌標籤: 15% 透明度背景 class AssetCardCompact extends StatelessWidget { final String title; final String balance; final String? change; final bool? isUp; final VoidCallback? onTap; const AssetCardCompact({ super.key, required this.title, required this.balance, this.change, this.isUp, this.onTap, }); @override Widget build(BuildContext context) { final theme = ShadTheme.of(context); final appColors = context.appColors; final isValueUp = isUp ?? true; return ShadCard( padding: const EdgeInsets.all(AppSpacing.md), child: InkWell( onTap: onTap, child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: theme.textTheme.muted, ), const SizedBox(height: 4), Text( balance, style: theme.textTheme.h3.copyWith( fontWeight: FontWeight.bold, ), ), ], ), ), if (change != null) Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: isValueUp ? appColors.upBackground : appColors.downBackground, borderRadius: BorderRadius.circular(AppRadius.sm), ), child: Text( change!, style: TextStyle( color: isValueUp ? appColors.up : appColors.down, fontWeight: FontWeight.w600, ), ), ), ], ), ), ); } }