import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../../../common/domain/metal_type.dart'; import '../../../common/domain/money.dart'; import '../../../common/router/app_router.dart'; import '../../../common/widgets/adaptive.dart'; import '../../../common/widgets/circle_back_button.dart'; import '../../../common/widgets/prototype_ui.dart'; import '../../auth/application/auth_controller.dart'; import '../../auth/data/auth_models.dart'; import '../application/profile_settings_controller.dart'; import '../data/profile_models.dart'; class InviteRewardPage extends StatelessWidget { const InviteRewardPage({super.key}); @override Widget build(BuildContext context) { return _ActionScaffold( title: '邀请好友', child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const _InviteCodeCard(), const SizedBox(height: 16), const PrototypeCard( padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6), child: Column( children: [ _KeyValueLine(label: '已邀请好友', value: '3 人'), PrototypeDivider(margin: EdgeInsets.zero), _KeyValueLine( label: '累计获得奖励', value: '¥120', valueColor: Color(0xFFB5862A), ), ], ), ), const SizedBox(height: 14), FilledButton( onPressed: () => _toast(context, '演示:拉起微信 / 系统分享面板'), child: const Text('分享给好友'), ), const SizedBox(height: 14), const Text( '好友通过你的邀请码注册并完成首次记账,双方各得奖励。奖励权益将随产品逐步开放,具体以活动规则为准。', style: TextStyle( fontSize: 11, height: 1.6, color: Color(0xFFB3AFA5), ), ), ], ), ); } } class ShareCardPage extends ConsumerWidget { const ShareCardPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final auth = ref.watch(authProvider); final currentUser = auth.valueOrNull is LoggedInAuthState ? (auth.valueOrNull as LoggedInAuthState).user : null; final nickname = currentUser?.nickname.trim(); final owner = nickname == null || nickname.isEmpty ? '金值用户' : nickname; return _ActionScaffold( title: '分享估值卡', child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _SharePreviewCard(owner: owner), const SizedBox(height: 14), PrototypeCard( padding: EdgeInsets.zero, child: Column( children: const [ _SettingLikeRow( icon: Icons.visibility_off_outlined, title: '金额隐私', trailing: '已打码', ), PrototypeDivider(margin: EdgeInsets.zero), _SettingLikeRow( icon: Icons.ios_share_outlined, title: '分享渠道', trailing: '系统分享', ), ], ), ), const SizedBox(height: 14), FilledButton( onPressed: () async { await Clipboard.setData( ClipboardData(text: '$owner 的贵金属估值卡,已通过金值生成。'), ); if (!context.mounted) return; _toast(context, '分享文案已复制'); }, child: const Text('复制分享文案'), ), ], ), ); } } class LocalBackupPage extends StatelessWidget { const LocalBackupPage({super.key}); @override Widget build(BuildContext context) { return _ActionScaffold( title: '本地导出备份', child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ PrototypeCard( padding: EdgeInsets.zero, child: Column( children: const [ _SettingLikeRow( icon: Icons.inventory_2_outlined, title: '备份内容', trailing: '资产 / 设置', ), PrototypeDivider(margin: EdgeInsets.zero), _SettingLikeRow( icon: Icons.description_outlined, title: '导出格式', trailing: 'JSON', ), PrototypeDivider(margin: EdgeInsets.zero), _SettingLikeRow( icon: Icons.lock_outline, title: '存储位置', trailing: '仅本机', ), ], ), ), const SizedBox(height: 14), FilledButton( onPressed: () => _toast(context, '已生成本地备份文件'), child: const Text('生成备份'), ), const SizedBox(height: 12), const Text( '备份文件包含资产、纯度系数、回收折扣与显示设置,不包含登录凭证。', style: TextStyle( fontSize: 11, height: 1.6, color: Color(0xFFB3AFA5), ), ), ], ), ); } } class CloudBackupPage extends ConsumerWidget { const CloudBackupPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final auth = ref.watch(authProvider); final loggedIn = auth.valueOrNull is LoggedInAuthState; return _ActionScaffold( title: '云备份 · 多端同步', child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ PrototypeCard( padding: EdgeInsets.zero, child: Column( children: [ _SettingLikeRow( icon: Icons.cloud_done_outlined, title: '同步状态', trailing: loggedIn ? '可开启' : '登录解锁', ), const PrototypeDivider(margin: EdgeInsets.zero), const _SettingLikeRow( icon: Icons.devices_outlined, title: '多端同步', trailing: '资产 / 设置', ), const PrototypeDivider(margin: EdgeInsets.zero), const _SettingLikeRow( icon: Icons.lock_outline, title: '数据策略', trailing: '本地优先', ), ], ), ), const SizedBox(height: 14), FilledButton( onPressed: () { if (!loggedIn) { context.push(AppRoutes.login); } else { _toast(context, '云同步入口已打开'); } }, child: Text(loggedIn ? '开启云备份' : '去登录'), ), ], ), ); } } class WidgetSettingsPage extends StatelessWidget { const WidgetSettingsPage({super.key}); @override Widget build(BuildContext context) { return _ActionScaffold( title: '桌面小组件', child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const _WidgetPreview(), const SizedBox(height: 14), PrototypeCard( padding: EdgeInsets.zero, child: Column( children: const [ _SettingLikeRow( icon: Icons.dashboard_customize_outlined, title: '组件尺寸', trailing: '中号', ), PrototypeDivider(margin: EdgeInsets.zero), _SettingLikeRow( icon: Icons.lock_outline, title: '金额显示', trailing: '跟随隐私设置', ), ], ), ), const SizedBox(height: 14), FilledButton( onPressed: () => _toast(context, '演示:打开系统小组件设置'), child: const Text('添加到桌面'), ), ], ), ); } } class PuritySettingsPage extends ConsumerWidget { const PuritySettingsPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final settings = ref.watch(profileSettingsControllerProvider); final groups = [ ('黄金', ['足金9999', '足金999']), ('铂金', ['PT950']), ('白银', ['999银']), ]; return _ActionScaffold( title: '纯度系数管理', child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ for (final group in groups) ...[ _SectionLabel(group.$1), PrototypeCard( padding: EdgeInsets.zero, child: Column( children: [ for (final purity in group.$2) ...[ _SettingLikeRow( icon: Icons.tune_outlined, title: purity, trailing: (settings.purityPresets[purity] ?? 1) .toStringAsFixed(4), onTap: () => _toast(context, '演示:自定义「$purity」纯度系数'), ), if (purity != group.$2.last) const PrototypeDivider(margin: EdgeInsets.zero), ], ], ), ), if (group != groups.last) const SizedBox(height: 12), ], ], ), ); } } class RecycleDiscountPage extends ConsumerWidget { const RecycleDiscountPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final settings = ref.watch(profileSettingsControllerProvider); final notifier = ref.read(profileSettingsControllerProvider.notifier); final preview = 483812.0 * (settings.recycleDiscounts[MetalType.gold] ?? 0.97); return _ActionScaffold( title: '回收折扣设置', child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ PrototypeCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '回收参考预览', style: TextStyle(fontSize: 13, color: Color(0xFF8A8780)), ), const SizedBox(height: 8), Text( formatCny(preview), style: const TextStyle( fontSize: 28, fontWeight: FontWeight.w700, height: 1, ), ), const SizedBox(height: 8), const Text( '按当前资产总估值和黄金折扣演示,实际以持仓金属分层计算。', style: TextStyle( fontSize: 11, height: 1.5, color: Color(0xFFB3AFA5), ), ), ], ), ), const SizedBox(height: 14), PrototypeCard( padding: EdgeInsets.zero, child: Column( children: [ for (final entry in settings.recycleDiscounts.entries) ...[ _DiscountSliderRow( metal: entry.key, value: entry.value, onChanged: (value) => notifier.setRecycleDiscount(entry.key, value), ), if (entry.key != settings.recycleDiscounts.keys.last) const PrototypeDivider(margin: EdgeInsets.zero), ], ], ), ), ], ), ); } } class PriceColorPage extends ConsumerWidget { const PriceColorPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final cs = ShadTheme.of(context).colorScheme; final current = ref.watch(profileSettingsControllerProvider).priceColorMode; final notifier = ref.read(profileSettingsControllerProvider.notifier); return _ActionScaffold( title: '涨跌颜色', child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ PrototypeCard( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _ColorModeTile( title: PriceColorMode.redUpGreenDown.label, upColor: const Color(0xFFC0392B), downColor: const Color(0xFF2E8B6F), selected: current == PriceColorMode.redUpGreenDown, onTap: () => notifier.setPriceColorMode(PriceColorMode.redUpGreenDown), ), const SizedBox(height: 10), _ColorModeTile( title: PriceColorMode.greenUpRedDown.label, upColor: const Color(0xFF2E8B6F), downColor: const Color(0xFFC0392B), selected: current == PriceColorMode.greenUpRedDown, onTap: () => notifier.setPriceColorMode(PriceColorMode.greenUpRedDown), ), ], ), ), const SizedBox(height: 12), Text( '当前预览: ${current.label}', style: TextStyle(fontSize: 12, color: cs.mutedForeground), ), ], ), ); } } class CurrencyPage extends StatelessWidget { const CurrencyPage({super.key}); @override Widget build(BuildContext context) { return const _ActionScaffold( title: '显示币种', child: PrototypeCard( padding: EdgeInsets.zero, child: Column( children: [ _CurrencyRow(label: '人民币', code: '¥ CNY', selected: true), PrototypeDivider(margin: EdgeInsets.zero), _CurrencyRow(label: '美元', code: r'$ USD', selected: false), PrototypeDivider(margin: EdgeInsets.zero), _CurrencyRow(label: '港币', code: r'HK$ HKD', selected: false), ], ), ), ); } } class DisclaimerPage extends StatelessWidget { const DisclaimerPage({super.key}); @override Widget build(BuildContext context) { return const _ActionScaffold( title: '免责声明 · 数据来源', child: PrototypeCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _InfoParagraph('App 内「材料价值」= 克重 × 纯度系数 × 上海金现货参考价(元/克)。'), _InfoParagraph('它不是金店零售价(含工费 / 品牌溢价),也不是回收实收价。'), _InfoParagraph( '「兑换试算」中各渠道(金店 / 金条 / T+D / 回收)报价均为参考价,恒标来源与时间,以实际门店 / 交易系统为准。', ), _InfoParagraph('「回收参考价」= 材料价值 × 可调折扣系数,仅供参考;正式版将尽量对接真实回收报价。'), _InfoParagraph('本品为资产记录与估值工具,所有信息均不构成投资建议。'), ], ), ), ); } } class AboutPage extends StatelessWidget { const AboutPage({super.key}); @override Widget build(BuildContext context) { return _ActionScaffold( title: '意见反馈 · 关于金值', child: FutureBuilder( future: PackageInfo.fromPlatform(), builder: (context, snapshot) { final version = snapshot.data == null ? '加载中' : 'Version ${snapshot.data!.version}+${snapshot.data!.buildNumber}'; return PrototypeCard( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Text( '金值 · 贵金属资产管家', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w700), ), const SizedBox(height: 8), Text(version, style: const TextStyle(fontSize: 13)), const SizedBox(height: 10), const Text( '以「我的贵金属资产实时估值」为中心,辅以行情判断与资讯。', style: TextStyle( fontSize: 13, color: Color(0xFF8A8780), height: 1.5, ), ), const SizedBox(height: 16), _GoldTextAction( label: '提交意见反馈', onTap: () => _toast(context, '演示:打开反馈表单'), ), const SizedBox(height: 10), _GoldTextAction( label: '检查更新', onTap: () => _toast(context, '当前已是最新版本'), ), ], ), ); }, ), ); } } class _ActionScaffold extends StatelessWidget { const _ActionScaffold({required this.title, required this.child}); final String title; final Widget child; @override Widget build(BuildContext context) { final cs = ShadTheme.of(context).colorScheme; return Scaffold( backgroundColor: cs.background, appBar: AppBar( backgroundColor: cs.background, surfaceTintColor: Colors.transparent, elevation: 0, scrolledUnderElevation: 0, centerTitle: true, toolbarHeight: 46, title: Text( title, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: cs.foreground, ), ), leading: const CircleBackButton(), ), body: ListView( padding: Adaptive.screenPadding(context, top: 8, bottom: 32), children: [child], ), ); } } class _InviteCodeCard extends StatelessWidget { const _InviteCodeCard(); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( borderRadius: BorderRadius.circular(18), gradient: const LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFF1A1A17), Color(0xFF3A2F12)], ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Row( children: [ _GoldDot(), SizedBox(width: 7), Text( '邀请好友,一起记账各得奖励', style: TextStyle( color: Colors.white, fontSize: 13, fontWeight: FontWeight.w600, ), ), ], ), const SizedBox(height: 14), const Text( '我的邀请码', style: TextStyle(fontSize: 12, color: Color(0xFFC9C4B5)), ), const SizedBox(height: 6), Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 13), decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.10), borderRadius: BorderRadius.circular(12), border: Border.all( color: Colors.white.withValues(alpha: 0.30), width: 0.5, ), ), child: Row( children: [ const Expanded( child: Text( 'JINZHI-8K3F', style: TextStyle( color: Colors.white, fontSize: 22, fontWeight: FontWeight.w700, letterSpacing: 2, ), ), ), GestureDetector( onTap: () async { await Clipboard.setData( const ClipboardData(text: 'JINZHI-8K3F'), ); if (!context.mounted) return; _toast(context, '已复制邀请码'); }, child: const Text( '复制', style: TextStyle( color: Color(0xFFB5862A), fontSize: 13, fontWeight: FontWeight.w600, ), ), ), ], ), ), ], ), ); } } class _SharePreviewCard extends StatelessWidget { const _SharePreviewCard({required this.owner}); final String owner; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( borderRadius: BorderRadius.circular(18), gradient: const LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFF1A1A17), Color(0xFF3A2F12)], ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Row( children: [ _GoldDot(), SizedBox(width: 7), Text( '金值 · 我的贵金属', style: TextStyle( color: Colors.white, fontSize: 13, fontWeight: FontWeight.w600, ), ), ], ), const SizedBox(height: 20), const Text( '总估值', textAlign: TextAlign.center, style: TextStyle(fontSize: 12, color: Color(0xFFC9C4B5)), ), const SizedBox(height: 8), const Text( '••••••', textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 42, fontWeight: FontWeight.w700, height: 1, ), ), const SizedBox(height: 10), Center( child: Container( padding: const EdgeInsets.symmetric(horizontal: 9, vertical: 4), decoration: BoxDecoration( color: const Color(0xFFC0392B).withValues(alpha: 0.22), borderRadius: BorderRadius.circular(999), ), child: const Text( '•••• · +1.21% 今日', style: TextStyle( color: Color(0xFFF0A99E), fontSize: 12, fontWeight: FontWeight.w600, ), ), ), ), const SizedBox(height: 18), Text( '来自 $owner · 金额已自动打码', textAlign: TextAlign.center, style: const TextStyle(fontSize: 12, color: Color(0xFFC9C4B5)), ), ], ), ); } } class _WidgetPreview extends StatelessWidget { const _WidgetPreview(); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(18), decoration: BoxDecoration( color: const Color(0xFF1A1A17), borderRadius: BorderRadius.circular(20), ), child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFFF7F4EE), borderRadius: BorderRadius.circular(18), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row( children: [ _GoldDot(), SizedBox(width: 7), Text( '金值', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w700), ), ], ), const SizedBox(height: 14), const Text( '¥ 483,812', style: TextStyle( fontSize: 28, fontWeight: FontWeight.w700, height: 1, ), ), const SizedBox(height: 8), Container( padding: const EdgeInsets.symmetric(horizontal: 9, vertical: 4), decoration: BoxDecoration( color: const Color(0xFFFBEDEA), borderRadius: BorderRadius.circular(999), ), child: const Text( '+¥5,821 · +1.21% 今日', style: TextStyle( fontSize: 12, color: Color(0xFFC0392B), fontWeight: FontWeight.w600, ), ), ), const SizedBox(height: 14), const Row( children: [ Expanded( child: _MiniMetal(label: '金', value: '64%'), ), SizedBox(width: 8), Expanded( child: _MiniMetal(label: '铂', value: '22%'), ), SizedBox(width: 8), Expanded( child: _MiniMetal(label: '银', value: '14%'), ), ], ), ], ), ), ); } } class _DiscountSliderRow extends StatelessWidget { const _DiscountSliderRow({ required this.metal, required this.value, required this.onChanged, }); final MetalType metal; final double value; final ValueChanged onChanged; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.fromLTRB(16, 12, 16, 10), child: Column( children: [ Row( children: [ Container( width: 8, height: 8, decoration: BoxDecoration( color: metal.color, shape: BoxShape.circle, ), ), const SizedBox(width: 8), Expanded( child: Text( metal.label, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, ), ), ), Text( '${(value * 100).round()}%', style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w700, ), ), ], ), Slider( min: 0.7, max: 1.0, divisions: 30, value: value.clamp(0.7, 1.0), activeColor: const Color(0xFFB5862A), inactiveColor: const Color(0xFFECEAE3), onChanged: onChanged, ), ], ), ); } } class _ColorModeTile extends StatelessWidget { const _ColorModeTile({ required this.title, required this.upColor, required this.downColor, required this.selected, required this.onTap, }); final String title; final Color upColor; final Color downColor; final bool selected; final VoidCallback onTap; @override Widget build(BuildContext context) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(14), child: Container( padding: const EdgeInsets.all(13), decoration: BoxDecoration( color: selected ? const Color(0xFFF6ECD6) : Colors.white, borderRadius: BorderRadius.circular(14), border: Border.all( color: selected ? const Color(0xFFE3D6B4) : const Color(0xFFECEAE3), width: 0.5, ), ), child: Row( children: [ Expanded( child: Text( title, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, ), ), ), _ColorSwatch(color: upColor, label: '涨'), const SizedBox(width: 8), _ColorSwatch(color: downColor, label: '跌'), const SizedBox(width: 8), Icon( selected ? Icons.check_circle : Icons.radio_button_unchecked, size: 18, color: selected ? const Color(0xFFB5862A) : const Color(0xFFB3AFA5), ), ], ), ), ); } } class _CurrencyRow extends StatelessWidget { const _CurrencyRow({ required this.label, required this.code, required this.selected, }); final String label; final String code; final bool selected; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), child: Row( children: [ Expanded( child: Text( label, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: selected ? const Color(0xFF1F1D18) : const Color(0xFFB3AFA5), ), ), ), Text( code, style: TextStyle( fontSize: 13, fontWeight: FontWeight.w700, color: selected ? const Color(0xFFB5862A) : const Color(0xFFB3AFA5), ), ), const SizedBox(width: 8), Icon( selected ? Icons.check_circle : Icons.lock_outline, size: 17, color: selected ? const Color(0xFFB5862A) : const Color(0xFFB3AFA5), ), ], ), ); } } class _SettingLikeRow extends StatelessWidget { const _SettingLikeRow({ required this.icon, required this.title, required this.trailing, this.onTap, }); final IconData icon; final String title; final String trailing; final VoidCallback? onTap; @override Widget build(BuildContext context) { final content = Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 13), child: Row( children: [ Icon(icon, size: 18, color: const Color(0xFFB5862A)), const SizedBox(width: 10), Expanded( child: Text( title, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600), ), ), Text( trailing, style: const TextStyle( fontSize: 13, color: Color(0xFF6E6A60), fontWeight: FontWeight.w600, ), ), if (onTap != null) ...[ const SizedBox(width: 4), const Icon(Icons.chevron_right, size: 16, color: Color(0xFFB3AFA5)), ], ], ), ); if (onTap == null) return content; return InkWell(onTap: onTap, child: content); } } class _KeyValueLine extends StatelessWidget { const _KeyValueLine({ required this.label, required this.value, this.valueColor, }); final String label; final String value; final Color? valueColor; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 12), child: Row( children: [ Expanded( child: Text( label, style: const TextStyle(fontSize: 13, color: Color(0xFF8A8780)), ), ), Text( value, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w700, color: valueColor ?? const Color(0xFF1F1D18), ), ), ], ), ); } } class _GoldTextAction extends StatelessWidget { const _GoldTextAction({required this.label, required this.onTap}); final String label; final VoidCallback onTap; @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Text( '$label ›', style: const TextStyle( color: Color(0xFFB5862A), fontSize: 14, fontWeight: FontWeight.w700, ), ), ); } } class _InfoParagraph extends StatelessWidget { const _InfoParagraph(this.text); final String text; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(bottom: 10), child: Text( text, style: const TextStyle( fontSize: 13, height: 1.65, color: Color(0xFF6E6A60), ), ), ); } } class _SectionLabel extends StatelessWidget { const _SectionLabel(this.label); final String label; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.fromLTRB(2, 0, 2, 7), child: Text( label, style: const TextStyle(fontSize: 12, color: Color(0xFF8A8780)), ), ); } } class _MiniMetal extends StatelessWidget { const _MiniMetal({required this.label, required this.value}); final String label; final String value; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 9, vertical: 8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: const Color(0xFFE6E0D6), width: 0.5), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: const TextStyle(fontSize: 11, color: Color(0xFF8A8780)), ), const SizedBox(height: 4), Text( value, style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w700), ), ], ), ); } } class _ColorSwatch extends StatelessWidget { const _ColorSwatch({required this.color, required this.label}); final Color color; final String label; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: color.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(999), ), child: Text( label, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w700, color: color, ), ), ); } } class _GoldDot extends StatelessWidget { const _GoldDot(); @override Widget build(BuildContext context) { return Container( width: 8, height: 8, decoration: const BoxDecoration( color: Color(0xFFB5862A), shape: BoxShape.circle, ), ); } } void _toast(BuildContext context, String message) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message))); }