docs: relocate skills system documentation and refactor asset page components
Move skills system documentation from bottom to top of CLAUDE.md for better organization. Refactor Flutter asset page by extracting UI components into separate files and updating import structure for improved modularity.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../../core/theme/app_spacing.dart';
|
||||
|
||||
/// 信息行组件(用于关于对话框)
|
||||
class InfoRow extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String text;
|
||||
|
||||
const InfoRow({super.key, required this.icon, required this.text});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Icon(icon, size: 14, color: colorScheme.onSurfaceVariant),
|
||||
SizedBox(width: AppSpacing.sm),
|
||||
Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 圆形头像组件
|
||||
///
|
||||
/// 显示用户首字母或默认比特币符号。通过 [radius] 控制大小,
|
||||
/// [fontSize] 控制文字大小,[text] 可传入用户头像文字。
|
||||
class AvatarCircle extends StatelessWidget {
|
||||
final double radius;
|
||||
final double fontSize;
|
||||
final String? text;
|
||||
|
||||
const AvatarCircle({
|
||||
super.key,
|
||||
required this.radius,
|
||||
required this.fontSize,
|
||||
this.text,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return CircleAvatar(
|
||||
radius: radius,
|
||||
backgroundColor: colorScheme.primary.withOpacity(0.15),
|
||||
child: Text(
|
||||
text ?? '₿',
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
color: colorScheme.primary,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../../../../core/theme/app_color_scheme.dart';
|
||||
import '../../../../core/theme/app_spacing.dart';
|
||||
|
||||
/// 退出登录按钮
|
||||
class LogoutButton extends StatelessWidget {
|
||||
final VoidCallback onLogout;
|
||||
const LogoutButton({super.key, required this.onLogout});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onLogout,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColorScheme.down.withOpacity(0.05),
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(
|
||||
color: AppColorScheme.down.withOpacity(0.15),
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'退出登录',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColorScheme.down,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
105
flutter_monisuo/lib/ui/pages/mine/components/menu_group1.dart
Normal file
105
flutter_monisuo/lib/ui/pages/mine/components/menu_group1.dart
Normal file
@@ -0,0 +1,105 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import '../../../../core/theme/app_color_scheme.dart';
|
||||
import '../../../../core/theme/app_spacing.dart';
|
||||
import '../kyc_page.dart';
|
||||
import '../welfare_center_page.dart';
|
||||
import 'menu_group_container.dart';
|
||||
import 'menu_row.dart';
|
||||
import 'menu_trailing_widgets.dart';
|
||||
|
||||
/// 菜单分组1 - 福利中心 / 实名认证 / 安全设置 / 消息通知
|
||||
class MenuGroup1 extends StatelessWidget {
|
||||
final int kycStatus;
|
||||
final void Function(String) onShowComingSoon;
|
||||
|
||||
const MenuGroup1({
|
||||
super.key,
|
||||
required this.kycStatus,
|
||||
required this.onShowComingSoon,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
return MenuGroupContainer(
|
||||
child: Column(
|
||||
children: [
|
||||
// 福利中心
|
||||
MenuRow(
|
||||
icon: LucideIcons.gift,
|
||||
iconColor: AppColorScheme.darkSecondary, // gold
|
||||
title: '福利中心',
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => const WelfareCenterPage()),
|
||||
);
|
||||
},
|
||||
),
|
||||
const MenuDivider(),
|
||||
// 实名认证
|
||||
MenuRow(
|
||||
icon: LucideIcons.shieldCheck,
|
||||
iconColor: AppColorScheme.getUpColor(isDark),
|
||||
title: '实名认证',
|
||||
trailing: KycBadge(kycStatus: kycStatus),
|
||||
onTap: () {
|
||||
if (kycStatus == 2) {
|
||||
showKycStatusDialog(context);
|
||||
} else {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => const KycPage()),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
const MenuDivider(),
|
||||
// 安全设置
|
||||
MenuRow(
|
||||
icon: LucideIcons.lock,
|
||||
iconColor: colorScheme.onSurfaceVariant,
|
||||
title: '安全设置',
|
||||
onTap: () => onShowComingSoon('安全设置'),
|
||||
),
|
||||
const MenuDivider(),
|
||||
// 消息通知
|
||||
MenuRow(
|
||||
icon: LucideIcons.bell,
|
||||
iconColor: colorScheme.onSurfaceVariant,
|
||||
title: '消息通知',
|
||||
trailing: const RedDotIndicator(),
|
||||
onTap: () => onShowComingSoon('消息通知'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 显示 KYC 认证状态对话框
|
||||
void showKycStatusDialog(BuildContext context) {
|
||||
showShadDialog(
|
||||
context: context,
|
||||
builder: (ctx) => ShadDialog.alert(
|
||||
title: Row(
|
||||
children: [
|
||||
Icon(Icons.check_circle, color: AppColorScheme.up, size: 20),
|
||||
SizedBox(width: AppSpacing.sm),
|
||||
const Text('实名认证'),
|
||||
],
|
||||
),
|
||||
description: const Text('您的实名认证已通过'),
|
||||
actions: [
|
||||
ShadButton(
|
||||
child: const Text('确定'),
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
||||
import 'menu_group_container.dart';
|
||||
import 'menu_row.dart';
|
||||
import 'menu_trailing_widgets.dart';
|
||||
|
||||
/// 菜单分组2 - 深色模式 / 系统设置 / 关于我们
|
||||
class MenuGroup2 extends StatelessWidget {
|
||||
final VoidCallback onShowAbout;
|
||||
|
||||
const MenuGroup2({super.key, required this.onShowAbout});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return MenuGroupContainer(
|
||||
child: Column(
|
||||
children: [
|
||||
// 深色模式
|
||||
const DarkModeRow(),
|
||||
const MenuDivider(),
|
||||
// 系统设置
|
||||
MenuRow(
|
||||
icon: LucideIcons.settings,
|
||||
iconColor: colorScheme.onSurfaceVariant,
|
||||
title: '系统设置',
|
||||
onTap: () {
|
||||
// TODO: 系统设置
|
||||
},
|
||||
),
|
||||
const MenuDivider(),
|
||||
// 关于我们
|
||||
MenuRow(
|
||||
icon: LucideIcons.info,
|
||||
iconColor: colorScheme.onSurfaceVariant,
|
||||
title: '关于我们',
|
||||
onTap: onShowAbout,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../../core/theme/app_spacing.dart';
|
||||
|
||||
/// 菜单分组容器 - 统一的圆角卡片样式
|
||||
///
|
||||
/// 所有菜单分组共享相同的容器样式:背景色、圆角、边框。
|
||||
/// 通过 [child] 传入菜单项 Column。
|
||||
class MenuGroupContainer extends StatelessWidget {
|
||||
final Widget child;
|
||||
|
||||
const MenuGroupContainer({super.key, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(
|
||||
color: isDark
|
||||
? colorScheme.surfaceContainer
|
||||
: colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(
|
||||
color: colorScheme.outlineVariant.withOpacity(0.15),
|
||||
),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
88
flutter_monisuo/lib/ui/pages/mine/components/menu_row.dart
Normal file
88
flutter_monisuo/lib/ui/pages/mine/components/menu_row.dart
Normal file
@@ -0,0 +1,88 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
||||
|
||||
/// 单行菜单项:icon-in-box + title + trailing (chevron / badge / toggle)
|
||||
///
|
||||
/// 通用菜单行组件,[icon] 和 [iconColor] 控制左侧图标,
|
||||
/// [title] 为菜单文字,[trailing] 为右侧自定义内容(默认显示 chevron),
|
||||
/// [onTap] 为点击回调。
|
||||
class MenuRow extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final Color iconColor;
|
||||
final String title;
|
||||
final Widget? trailing;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
const MenuRow({
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.iconColor,
|
||||
required this.title,
|
||||
this.trailing,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
child: Row(
|
||||
children: [
|
||||
// Icon in 36x36 rounded container
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? Theme.of(context).colorScheme.surfaceContainerHigh
|
||||
: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(icon, size: 18, color: iconColor),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
// Title
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Trailing
|
||||
if (trailing != null)
|
||||
trailing!
|
||||
else
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 菜单组内分割线
|
||||
class MenuDivider extends StatelessWidget {
|
||||
const MenuDivider({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).colorScheme.outlineVariant.withOpacity(0.15),
|
||||
margin: const EdgeInsets.only(left: 62),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../../../core/theme/app_color_scheme.dart';
|
||||
import '../../../../core/theme/app_spacing.dart';
|
||||
import '../../../../providers/theme_provider.dart';
|
||||
|
||||
/// KYC 状态徽章 (e.g. "已认证" green badge + chevron)
|
||||
///
|
||||
/// 根据 [kycStatus] 显示不同状态:
|
||||
/// - 2: 已认证(绿色)
|
||||
/// - 1: 审核中(橙色)
|
||||
/// - 其他: 仅显示 chevron
|
||||
class KycBadge extends StatelessWidget {
|
||||
final int kycStatus;
|
||||
const KycBadge({super.key, required this.kycStatus});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
final green = AppColorScheme.getUpColor(isDark);
|
||||
|
||||
if (kycStatus == 2) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: green.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
),
|
||||
child: Text(
|
||||
'已认证',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: green,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
if (kycStatus == 1) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColorScheme.warning.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
),
|
||||
child: Text(
|
||||
'审核中',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColorScheme.warning,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 红点指示器 - 消息通知 + chevron
|
||||
class RedDotIndicator extends StatelessWidget {
|
||||
const RedDotIndicator({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColorScheme.down,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 深色模式切换行
|
||||
class DarkModeRow extends StatelessWidget {
|
||||
const DarkModeRow({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
final themeProvider = context.watch<ThemeProvider>();
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
child: Row(
|
||||
children: [
|
||||
// Icon in 36x36 rounded container
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: isDark
|
||||
? colorScheme.surfaceContainerHigh
|
||||
: colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
LucideIcons.moon,
|
||||
size: 18,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'深色模式',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Toggle switch - matching .pen design (44x24 rounded pill)
|
||||
GestureDetector(
|
||||
onTap: () => themeProvider.toggleTheme(),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
width: 44,
|
||||
height: 24,
|
||||
padding: const EdgeInsets.all(2),
|
||||
decoration: BoxDecoration(
|
||||
color: isDark
|
||||
? colorScheme.surfaceContainerHigh
|
||||
: colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: AnimatedAlign(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
alignment:
|
||||
themeProvider.isDarkMode
|
||||
? Alignment.centerRight
|
||||
: Alignment.centerLeft,
|
||||
child: Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.onSurface,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
||||
import '../../../../core/theme/app_spacing.dart';
|
||||
import 'avatar_circle.dart';
|
||||
|
||||
/// 用户资料卡片 - 头像 + 用户名 + 徽章 + chevron
|
||||
class ProfileCard extends StatelessWidget {
|
||||
final dynamic user;
|
||||
const ProfileCard({super.key, required this.user});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: isDark
|
||||
? colorScheme.surfaceContainer
|
||||
: colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(
|
||||
color: colorScheme.outlineVariant.withOpacity(0.15),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// Avatar
|
||||
AvatarCircle(
|
||||
radius: 24,
|
||||
fontSize: 18,
|
||||
text: user?.avatarText,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// Name + badge column
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
user?.username ?? '未登录',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'普通用户',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Chevron
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,16 @@ import 'package:flutter/material.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
||||
import '../../../core/theme/app_color_scheme.dart';
|
||||
import '../../../core/theme/app_spacing.dart';
|
||||
import '../../../providers/auth_provider.dart';
|
||||
import 'kyc_page.dart';
|
||||
import '../../../providers/theme_provider.dart';
|
||||
import '../auth/login_page.dart';
|
||||
import 'welfare_center_page.dart';
|
||||
import 'components/about_dialog_helpers.dart';
|
||||
import 'components/avatar_circle.dart';
|
||||
import 'components/logout_button.dart';
|
||||
import 'components/menu_group1.dart';
|
||||
import 'components/menu_group2.dart';
|
||||
import 'components/profile_card.dart';
|
||||
|
||||
/// 我的页面 - 匹配 .pen 设计稿
|
||||
class MinePage extends StatefulWidget {
|
||||
@@ -42,16 +44,16 @@ class _MinePageState extends State<MinePage>
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
_ProfileCard(user: auth.user),
|
||||
ProfileCard(user: auth.user),
|
||||
SizedBox(height: AppSpacing.sm),
|
||||
_MenuGroup1(
|
||||
MenuGroup1(
|
||||
kycStatus: auth.user?.kycStatus ?? 0,
|
||||
onShowComingSoon: _showComingSoon,
|
||||
),
|
||||
SizedBox(height: AppSpacing.sm),
|
||||
_MenuGroup2(onShowAbout: _showAboutDialog),
|
||||
MenuGroup2(onShowAbout: _showAboutDialog),
|
||||
SizedBox(height: AppSpacing.lg),
|
||||
_LogoutButton(onLogout: () => _handleLogout(auth)),
|
||||
LogoutButton(onLogout: () => _handleLogout(auth)),
|
||||
SizedBox(height: AppSpacing.md),
|
||||
Text(
|
||||
'System Build v1.0.0',
|
||||
@@ -98,7 +100,7 @@ class _MinePageState extends State<MinePage>
|
||||
builder: (context) => ShadDialog(
|
||||
title: Row(
|
||||
children: [
|
||||
_AvatarCircle(radius: 20, fontSize: 16),
|
||||
AvatarCircle(radius: 20, fontSize: 16),
|
||||
SizedBox(width: AppSpacing.sm + AppSpacing.xs),
|
||||
const Text('模拟所'),
|
||||
],
|
||||
@@ -112,9 +114,9 @@ class _MinePageState extends State<MinePage>
|
||||
style: TextStyle(color: colorScheme.onSurfaceVariant),
|
||||
),
|
||||
SizedBox(height: AppSpacing.md),
|
||||
_InfoRow(icon: Icons.code, text: '版本: 1.0.0'),
|
||||
InfoRow(icon: Icons.code, text: '版本: 1.0.0'),
|
||||
SizedBox(height: AppSpacing.sm),
|
||||
_InfoRow(
|
||||
InfoRow(
|
||||
icon: Icons.favorite,
|
||||
text: 'Built with Flutter & Material Design 3'),
|
||||
],
|
||||
@@ -158,607 +160,3 @@ class _MinePageState extends State<MinePage>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Profile Card
|
||||
// ============================================================
|
||||
|
||||
/// 用户资料卡片 - 头像 + 用户名 + 徽章 + chevron
|
||||
class _ProfileCard extends StatelessWidget {
|
||||
final dynamic user;
|
||||
const _ProfileCard({required this.user});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: isDark
|
||||
? colorScheme.surfaceContainer
|
||||
: colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(
|
||||
color: colorScheme.outlineVariant.withOpacity(0.15),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// Avatar
|
||||
_AvatarCircle(
|
||||
radius: 24,
|
||||
fontSize: 18,
|
||||
text: user?.avatarText,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// Name + badge column
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
user?.username ?? '未登录',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'普通用户',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Chevron
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 圆形头像组件
|
||||
class _AvatarCircle extends StatelessWidget {
|
||||
final double radius;
|
||||
final double fontSize;
|
||||
final String? text;
|
||||
|
||||
const _AvatarCircle({
|
||||
required this.radius,
|
||||
required this.fontSize,
|
||||
this.text,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
return CircleAvatar(
|
||||
radius: radius,
|
||||
backgroundColor: colorScheme.primary.withOpacity(0.15),
|
||||
child: Text(
|
||||
text ?? '₿',
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
color: colorScheme.primary,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Menu Group 1 - 福利中心 / 实名认证 / 安全设置 / 消息通知
|
||||
// ============================================================
|
||||
|
||||
class _MenuGroup1 extends StatelessWidget {
|
||||
final int kycStatus;
|
||||
final void Function(String) onShowComingSoon;
|
||||
|
||||
const _MenuGroup1({
|
||||
required this.kycStatus,
|
||||
required this.onShowComingSoon,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(
|
||||
color: isDark
|
||||
? colorScheme.surfaceContainer
|
||||
: colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(
|
||||
color: colorScheme.outlineVariant.withOpacity(0.15),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// 福利中心
|
||||
_MenuRow(
|
||||
icon: LucideIcons.gift,
|
||||
iconColor: AppColorScheme.darkSecondary, // gold
|
||||
title: '福利中心',
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => const WelfareCenterPage()),
|
||||
);
|
||||
},
|
||||
),
|
||||
_MenuDivider(),
|
||||
// 实名认证
|
||||
_MenuRow(
|
||||
icon: LucideIcons.shieldCheck,
|
||||
iconColor: AppColorScheme.getUpColor(isDark),
|
||||
title: '实名认证',
|
||||
trailing: _KycBadge(kycStatus: kycStatus),
|
||||
onTap: () {
|
||||
if (kycStatus == 2) {
|
||||
_showKycStatusDialog(context);
|
||||
} else {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => const KycPage()),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
_MenuDivider(),
|
||||
// 安全设置
|
||||
_MenuRow(
|
||||
icon: LucideIcons.lock,
|
||||
iconColor: colorScheme.onSurfaceVariant,
|
||||
title: '安全设置',
|
||||
onTap: () => onShowComingSoon('安全设置'),
|
||||
),
|
||||
_MenuDivider(),
|
||||
// 消息通知
|
||||
_MenuRow(
|
||||
icon: LucideIcons.bell,
|
||||
iconColor: colorScheme.onSurfaceVariant,
|
||||
title: '消息通知',
|
||||
trailing: _RedDotIndicator(),
|
||||
onTap: () => onShowComingSoon('消息通知'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Menu Group 2 - 深色模式 / 系统设置 / 关于我们
|
||||
// ============================================================
|
||||
|
||||
class _MenuGroup2 extends StatelessWidget {
|
||||
final VoidCallback onShowAbout;
|
||||
|
||||
const _MenuGroup2({required this.onShowAbout});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(
|
||||
color: isDark
|
||||
? colorScheme.surfaceContainer
|
||||
: colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(
|
||||
color: colorScheme.outlineVariant.withOpacity(0.15),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// 深色模式
|
||||
_DarkModeRow(),
|
||||
_MenuDivider(),
|
||||
// 系统设置
|
||||
_MenuRow(
|
||||
icon: LucideIcons.settings,
|
||||
iconColor: colorScheme.onSurfaceVariant,
|
||||
title: '系统设置',
|
||||
onTap: () {
|
||||
// TODO: 系统设置
|
||||
},
|
||||
),
|
||||
_MenuDivider(),
|
||||
// 关于我们
|
||||
_MenuRow(
|
||||
icon: LucideIcons.info,
|
||||
iconColor: colorScheme.onSurfaceVariant,
|
||||
title: '关于我们',
|
||||
onTap: onShowAbout,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Shared menu row components
|
||||
// ============================================================
|
||||
|
||||
/// 单行菜单项:icon-in-box + title + trailing (chevron / badge / toggle)
|
||||
class _MenuRow extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final Color iconColor;
|
||||
final String title;
|
||||
final Widget? trailing;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
const _MenuRow({
|
||||
required this.icon,
|
||||
required this.iconColor,
|
||||
required this.title,
|
||||
this.trailing,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
child: Row(
|
||||
children: [
|
||||
// Icon in 36x36 rounded container
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? Theme.of(context).colorScheme.surfaceContainerHigh
|
||||
: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(icon, size: 18, color: iconColor),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
// Title
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Trailing
|
||||
if (trailing != null)
|
||||
trailing!
|
||||
else
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Menu group divider
|
||||
class _MenuDivider extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).colorScheme.outlineVariant.withOpacity(0.15),
|
||||
margin: const EdgeInsets.only(left: 62),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Special trailing widgets
|
||||
// ============================================================
|
||||
|
||||
/// KYC status badge (e.g. "已认证" green badge + chevron)
|
||||
class _KycBadge extends StatelessWidget {
|
||||
final int kycStatus;
|
||||
const _KycBadge({required this.kycStatus});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
final green = AppColorScheme.getUpColor(isDark);
|
||||
|
||||
if (kycStatus == 2) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: green.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
),
|
||||
child: Text(
|
||||
'已认证',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: green,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
if (kycStatus == 1) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColorScheme.warning.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
),
|
||||
child: Text(
|
||||
'审核中',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColorScheme.warning,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Red dot indicator for notifications + chevron
|
||||
class _RedDotIndicator extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColorScheme.down,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Dark mode toggle row
|
||||
class _DarkModeRow extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
final themeProvider = context.watch<ThemeProvider>();
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
child: Row(
|
||||
children: [
|
||||
// Icon in 36x36 rounded container
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: isDark
|
||||
? colorScheme.surfaceContainerHigh
|
||||
: colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
LucideIcons.moon,
|
||||
size: 18,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'深色模式',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Toggle switch - matching .pen design (44x24 rounded pill)
|
||||
GestureDetector(
|
||||
onTap: () => themeProvider.toggleTheme(),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
width: 44,
|
||||
height: 24,
|
||||
padding: const EdgeInsets.all(2),
|
||||
decoration: BoxDecoration(
|
||||
color: isDark
|
||||
? colorScheme.surfaceContainerHigh
|
||||
: colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: AnimatedAlign(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
alignment:
|
||||
themeProvider.isDarkMode
|
||||
? Alignment.centerRight
|
||||
: Alignment.centerLeft,
|
||||
child: Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.onSurface,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Logout button
|
||||
// ============================================================
|
||||
|
||||
class _LogoutButton extends StatelessWidget {
|
||||
final VoidCallback onLogout;
|
||||
const _LogoutButton({required this.onLogout});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onLogout,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColorScheme.down.withOpacity(0.05),
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(
|
||||
color: AppColorScheme.down.withOpacity(0.15),
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'退出登录',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColorScheme.down,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Info row (used in about dialog)
|
||||
// ============================================================
|
||||
|
||||
class _InfoRow extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String text;
|
||||
|
||||
const _InfoRow({required this.icon, required this.text});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Icon(icon, size: 14, color: colorScheme.onSurfaceVariant),
|
||||
SizedBox(width: AppSpacing.sm),
|
||||
Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// KYC status dialog
|
||||
// ============================================================
|
||||
|
||||
void _showKycStatusDialog(BuildContext context) {
|
||||
showShadDialog(
|
||||
context: context,
|
||||
builder: (ctx) => ShadDialog.alert(
|
||||
title: Row(
|
||||
children: [
|
||||
Icon(Icons.check_circle, color: AppColorScheme.up, size: 20),
|
||||
SizedBox(width: AppSpacing.sm),
|
||||
const Text('实名认证'),
|
||||
],
|
||||
),
|
||||
description: const Text('您的实名认证已通过'),
|
||||
actions: [
|
||||
ShadButton(
|
||||
child: const Text('确定'),
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import '../../../core/utils/toast_utils.dart';
|
||||
import '../../../core/event/app_event_bus.dart';
|
||||
import '../../../data/services/bonus_service.dart';
|
||||
import '../../../providers/asset_provider.dart';
|
||||
import '../../../providers/auth_provider.dart';
|
||||
|
||||
/// 福利中心页面
|
||||
class WelfareCenterPage extends StatefulWidget {
|
||||
@@ -48,64 +47,144 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
// 主题感知颜色辅助
|
||||
// ============================================
|
||||
|
||||
/// 金色强调色 ($gold-accent)
|
||||
Color _goldAccent(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return isDark ? AppColorScheme.darkSecondary : const Color(0xFFF59E0B);
|
||||
}
|
||||
bool get _isDark => Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
/// 金色强调色带透明度
|
||||
Color _goldAccentWithOpacity(BuildContext context, double opacity) {
|
||||
return _goldAccent(context).withOpacity(opacity);
|
||||
}
|
||||
/// 金色强调色 ($gold-accent)
|
||||
Color get _goldAccent =>
|
||||
_isDark ? AppColorScheme.darkSecondary : const Color(0xFFF59E0B);
|
||||
|
||||
/// 盈利绿色 ($profit-green)
|
||||
Color _profitGreen(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return isDark ? const Color(0xFF4ADE80) : const Color(0xFF16A34A);
|
||||
}
|
||||
Color get _profitGreen =>
|
||||
_isDark ? const Color(0xFF4ADE80) : const Color(0xFF16A34A);
|
||||
|
||||
/// 盈利绿色背景 ($profit-green-bg)
|
||||
Color _profitGreenBg(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return isDark ? const Color(0xFF052E16) : const Color(0xFFF0FDF4);
|
||||
}
|
||||
Color get _profitGreenBg =>
|
||||
_isDark ? const Color(0xFF052E16) : const Color(0xFFF0FDF4);
|
||||
|
||||
/// 文字静默色 ($text-muted)
|
||||
Color _textMuted(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return isDark ? const Color(0xFF64748B) : const Color(0xFF94A3B8);
|
||||
}
|
||||
Color get _textMuted =>
|
||||
_isDark ? const Color(0xFF64748B) : const Color(0xFF94A3B8);
|
||||
|
||||
/// 第三级背景色 ($bg-tertiary)
|
||||
Color _bgTertiary(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return isDark ? AppColorScheme.darkSurfaceContainerHigh : const Color(0xFFF1F5F9);
|
||||
}
|
||||
Color get _bgTertiary =>
|
||||
_isDark ? AppColorScheme.darkSurfaceContainerHigh : const Color(0xFFF1F5F9);
|
||||
|
||||
/// 卡片表面色 ($surface-card)
|
||||
Color _surfaceCard(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return isDark ? AppColorScheme.darkSurfaceContainer : Colors.white;
|
||||
}
|
||||
Color get _surfaceCard =>
|
||||
_isDark ? AppColorScheme.darkSurfaceContainer : Colors.white;
|
||||
|
||||
/// 反色文字 ($text-inverse)
|
||||
Color _textInverse(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return isDark ? const Color(0xFF0F172A) : Colors.white;
|
||||
Color get _textInverse =>
|
||||
_isDark ? const Color(0xFF0F172A) : Colors.white;
|
||||
|
||||
// ============================================
|
||||
// 文本样式辅助
|
||||
// ============================================
|
||||
|
||||
TextStyle _inter({
|
||||
required double fontSize,
|
||||
required FontWeight fontWeight,
|
||||
required Color color,
|
||||
}) {
|
||||
return GoogleFonts.inter(
|
||||
fontSize: fontSize,
|
||||
fontWeight: fontWeight,
|
||||
color: color,
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 容器样式辅助
|
||||
// ============================================
|
||||
|
||||
/// 标准卡片容器
|
||||
BoxDecoration _cardDecoration({Color? borderColor}) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
return BoxDecoration(
|
||||
color: _surfaceCard,
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(
|
||||
color: borderColor ?? scheme.outlineVariant.withValues(alpha: 0.15),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 金色渐变卡片容器
|
||||
BoxDecoration _goldGradientDecoration() {
|
||||
return BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(AppRadius.xl),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
_goldAccent.withValues(alpha: 0.15),
|
||||
_surfaceCard,
|
||||
],
|
||||
),
|
||||
border: Border.all(
|
||||
color: _goldAccent.withValues(alpha: 0.3),
|
||||
width: 1,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 状态胶囊标签
|
||||
Widget _statusBadge(String text, Color textColor, Color bgColor) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: bgColor,
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
style: _inter(fontSize: 11, fontWeight: FontWeight.w600, color: textColor),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 全宽按钮
|
||||
Widget _fullWidthButton({
|
||||
required String text,
|
||||
required Color backgroundColor,
|
||||
required Color foregroundColor,
|
||||
required VoidCallback? onPressed,
|
||||
Color? disabledBackgroundColor,
|
||||
}) {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
height: 44,
|
||||
child: ElevatedButton(
|
||||
onPressed: onPressed,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: backgroundColor,
|
||||
foregroundColor: foregroundColor,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
),
|
||||
disabledBackgroundColor:
|
||||
disabledBackgroundColor ?? backgroundColor.withValues(alpha: 0.3),
|
||||
disabledForegroundColor: foregroundColor.withValues(alpha: 0.7),
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
style: _inter(fontSize: 14, fontWeight: FontWeight.w700, color: foregroundColor),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: isDark
|
||||
backgroundColor: _isDark
|
||||
? AppColorScheme.darkBackground
|
||||
: const Color(0xFFF8FAFC),
|
||||
appBar: AppBar(
|
||||
backgroundColor: isDark
|
||||
backgroundColor: _isDark
|
||||
? AppColorScheme.darkBackground
|
||||
: Colors.white,
|
||||
elevation: 0,
|
||||
@@ -114,7 +193,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
titleSpacing: 0,
|
||||
title: Text(
|
||||
'福利中心',
|
||||
style: GoogleFonts.inter(
|
||||
style: _inter(
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: colorScheme.onSurface,
|
||||
@@ -128,32 +207,25 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
body: _isLoading
|
||||
? Center(
|
||||
child: CircularProgressIndicator(
|
||||
color: _goldAccent(context),
|
||||
color: _goldAccent,
|
||||
strokeWidth: 2.5,
|
||||
),
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: _loadData,
|
||||
color: _goldAccent(context),
|
||||
color: _goldAccent,
|
||||
child: SingleChildScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: const EdgeInsets.fromLTRB(16, 8, 16, 32),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 推广码卡片(金色渐变边框)
|
||||
_buildReferralCodeCard(context),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 新人福利卡片
|
||||
_buildNewUserBonusCard(context),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 推广奖励列表
|
||||
_buildReferralRewardsSection(context),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 奖励规则
|
||||
_buildRulesCard(context),
|
||||
],
|
||||
),
|
||||
@@ -169,37 +241,22 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
Widget _buildReferralCodeCard(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final referralCode = _welfareData?['referralCode'] as String? ?? '';
|
||||
final gold = _goldAccent(context);
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(AppRadius.xl),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
_goldAccentWithOpacity(context, 0.15),
|
||||
_surfaceCard(context),
|
||||
],
|
||||
),
|
||||
border: Border.all(
|
||||
color: _goldAccentWithOpacity(context, 0.3),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
decoration: _goldGradientDecoration(),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Header Row: gift icon + 标题
|
||||
Row(
|
||||
children: [
|
||||
Icon(LucideIcons.gift, color: gold, size: 24),
|
||||
Icon(LucideIcons.gift, color: _goldAccent, size: 24),
|
||||
const SizedBox(width: 10),
|
||||
Text(
|
||||
'我的邀请码',
|
||||
style: GoogleFonts.inter(
|
||||
style: _inter(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: colorScheme.onSurface,
|
||||
@@ -208,20 +265,15 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 邀请码
|
||||
Text(
|
||||
referralCode.isEmpty ? '暂无邀请码' : referralCode,
|
||||
style: GoogleFonts.inter(
|
||||
style: _inter(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w800,
|
||||
letterSpacing: 2,
|
||||
color: gold,
|
||||
),
|
||||
color: _goldAccent,
|
||||
).copyWith(letterSpacing: 2),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 复制邀请码按钮
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 40,
|
||||
@@ -233,20 +285,17 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
ToastUtils.show('邀请码已复制');
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: gold,
|
||||
foregroundColor: _textInverse(context),
|
||||
backgroundColor: _goldAccent,
|
||||
foregroundColor: _textInverse,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
),
|
||||
disabledBackgroundColor: gold.withOpacity(0.4),
|
||||
disabledBackgroundColor: _goldAccent.withValues(alpha: 0.4),
|
||||
),
|
||||
child: Text(
|
||||
'复制邀请码',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
style: _inter(fontSize: 14, fontWeight: FontWeight.w600, color: _textInverse),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -265,10 +314,8 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
final eligible = newUserBonus?['eligible'] as bool? ?? false;
|
||||
final claimed = newUserBonus?['claimed'] as bool? ?? false;
|
||||
final deposited = newUserBonus?['deposited'] as bool? ?? false;
|
||||
final green = _profitGreen(context);
|
||||
final greenBg = _profitGreenBg(context);
|
||||
|
||||
// 状态标签
|
||||
// 状态判定
|
||||
String badgeText;
|
||||
bool showAvailableBadge;
|
||||
String buttonText;
|
||||
@@ -298,13 +345,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: _surfaceCard(context),
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(
|
||||
color: colorScheme.outlineVariant.withOpacity(0.15),
|
||||
),
|
||||
),
|
||||
decoration: _cardDecoration(),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -314,78 +355,40 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
children: [
|
||||
Text(
|
||||
'新人福利',
|
||||
style: GoogleFonts.inter(
|
||||
style: _inter(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
if (showAvailableBadge)
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: greenBg,
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
),
|
||||
child: Text(
|
||||
badgeText,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: green,
|
||||
),
|
||||
),
|
||||
),
|
||||
_statusBadge(badgeText, _profitGreen, _profitGreenBg),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// 金额
|
||||
Text(
|
||||
'+100 USDT',
|
||||
style: GoogleFonts.inter(
|
||||
style: _inter(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: claimed ? colorScheme.onSurfaceVariant : green,
|
||||
color: claimed ? colorScheme.onSurfaceVariant : _profitGreen,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// 描述
|
||||
Text(
|
||||
description,
|
||||
style: GoogleFonts.inter(
|
||||
style: _inter(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 领取按钮
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 44,
|
||||
child: ElevatedButton(
|
||||
onPressed: canClaim ? () => _claimNewUserBonus() : null,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: green,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
),
|
||||
disabledBackgroundColor: green.withOpacity(0.3),
|
||||
disabledForegroundColor: Colors.white70,
|
||||
),
|
||||
child: Text(
|
||||
buttonText,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
_fullWidthButton(
|
||||
text: buttonText,
|
||||
backgroundColor: _profitGreen,
|
||||
foregroundColor: Colors.white,
|
||||
onPressed: canClaim ? () => _claimNewUserBonus() : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -405,40 +408,29 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Section Header
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'推广奖励',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'每邀请一位好友充值达标,奖励100 USDT',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: _textMuted(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
Text(
|
||||
'推广奖励',
|
||||
style: _inter(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'每邀请一位好友充值达标,奖励100 USDT',
|
||||
style: _inter(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: _textMuted,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// 推广列表卡片
|
||||
Container(
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: _surfaceCard(context),
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(
|
||||
color: colorScheme.outlineVariant.withOpacity(0.15),
|
||||
),
|
||||
),
|
||||
decoration: _cardDecoration(),
|
||||
child: referralRewards.isEmpty
|
||||
? _buildEmptyReferralList(context)
|
||||
: _buildReferralListItems(context, referralRewards),
|
||||
@@ -457,13 +449,14 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
Icon(
|
||||
LucideIcons.users,
|
||||
size: 36,
|
||||
color: _textMuted(context).withOpacity(0.4),
|
||||
color: _textMuted.withValues(alpha: 0.4),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'暂无推广用户',
|
||||
style: GoogleFonts.inter(
|
||||
style: _inter(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
@@ -475,9 +468,6 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
|
||||
Widget _buildReferralListItems(BuildContext context, List<dynamic> referralRewards) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final gold = _goldAccent(context);
|
||||
final green = _profitGreen(context);
|
||||
final greenBg = _profitGreenBg(context);
|
||||
|
||||
return Column(
|
||||
children: List.generate(referralRewards.length, (index) {
|
||||
@@ -488,92 +478,17 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
final milestones = data['milestones'] as List<dynamic>? ?? [];
|
||||
final isLast = index == referralRewards.length - 1;
|
||||
|
||||
// 判断状态
|
||||
bool hasClaimable = claimableCount > 0;
|
||||
bool hasAnyMilestone = milestones.isNotEmpty;
|
||||
bool allClaimed = milestones.isNotEmpty &&
|
||||
milestones.every((m) => (m as Map<String, dynamic>)['claimed'] == true);
|
||||
|
||||
// 进度计算
|
||||
double progress = 0;
|
||||
if (milestones.isNotEmpty) {
|
||||
int earnedCount = milestones.where((m) {
|
||||
final milestone = m as Map<String, dynamic>;
|
||||
return milestone['earned'] as bool? ?? false;
|
||||
}).length;
|
||||
progress = earnedCount / milestones.length;
|
||||
} else {
|
||||
// 无里程碑数据时,根据充值金额估算
|
||||
final deposit = double.tryParse(totalDeposit) ?? 0;
|
||||
progress = (deposit / 1000).clamp(0.0, 1.0);
|
||||
}
|
||||
|
||||
// 状态颜色和文字
|
||||
Color progressColor;
|
||||
Color statusTextColor;
|
||||
String statusText;
|
||||
Widget? actionWidget;
|
||||
|
||||
if (hasClaimable) {
|
||||
// 可领取 (achieved, green)
|
||||
progressColor = green;
|
||||
statusTextColor = green;
|
||||
statusText = '';
|
||||
actionWidget = GestureDetector(
|
||||
onTap: () => _claimReferralBonus(data['userId'] as int, milestones.isNotEmpty ? (milestones.firstWhere(
|
||||
(m) => (m as Map<String, dynamic>)['claimable'] == true,
|
||||
orElse: () => milestones.first,
|
||||
) as Map<String, dynamic>)['milestone'] as int? ?? 1 : 1),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: greenBg,
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
),
|
||||
child: Text(
|
||||
'领取',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: green,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (progress > 0) {
|
||||
// 进行中 (amber / gold)
|
||||
progressColor = gold;
|
||||
statusTextColor = const Color(0xFFD97706);
|
||||
statusText = '';
|
||||
actionWidget = Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFEF3C7),
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
),
|
||||
child: Text(
|
||||
'进行中',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: statusTextColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// 待达标 (gray)
|
||||
progressColor = _bgTertiary(context);
|
||||
statusTextColor = _textMuted(context);
|
||||
statusText = '';
|
||||
actionWidget = Text(
|
||||
'待达标',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: _textMuted(context),
|
||||
),
|
||||
);
|
||||
}
|
||||
final progress = _computeProgress(milestones, totalDeposit);
|
||||
// 操作按钮
|
||||
final actionWidget = _buildReferralAction(
|
||||
data: data,
|
||||
claimableCount: claimableCount,
|
||||
milestones: milestones,
|
||||
progress: progress,
|
||||
);
|
||||
// 进度条颜色
|
||||
final progressColor = _referralProgressColor(claimableCount, progress);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
@@ -581,48 +496,21 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
// Top Row: avatar + name + deposit + action
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
// Avatar
|
||||
Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: _bgTertiary(context),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
username.isNotEmpty ? username[0].toUpperCase() : '?',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
_buildAvatar(username),
|
||||
const SizedBox(width: 10),
|
||||
Text(
|
||||
username,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
style: _inter(fontSize: 13, fontWeight: FontWeight.w500, color: colorScheme.onSurface),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Text(
|
||||
'充值: \u00A5$totalDeposit',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
style: _inter(fontSize: 11, fontWeight: FontWeight.normal, color: colorScheme.onSurfaceVariant),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -630,15 +518,13 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// Progress bar
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
child: SizedBox(
|
||||
height: 6,
|
||||
child: LinearProgressIndicator(
|
||||
value: progress,
|
||||
backgroundColor: _bgTertiary(context),
|
||||
backgroundColor: _bgTertiary,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(progressColor),
|
||||
minHeight: 6,
|
||||
),
|
||||
@@ -651,7 +537,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
Divider(
|
||||
height: 1,
|
||||
thickness: 1,
|
||||
color: colorScheme.outlineVariant.withOpacity(0.15),
|
||||
color: colorScheme.outlineVariant.withValues(alpha: 0.15),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -659,6 +545,77 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAvatar(String username) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: _bgTertiary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
username.isNotEmpty ? username[0].toUpperCase() : '?',
|
||||
style: _inter(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 计算推荐奖励进度
|
||||
double _computeProgress(List<dynamic> milestones, String totalDeposit) {
|
||||
if (milestones.isNotEmpty) {
|
||||
int earnedCount = milestones.where((m) {
|
||||
final milestone = m as Map<String, dynamic>;
|
||||
return milestone['earned'] as bool? ?? false;
|
||||
}).length;
|
||||
return earnedCount / milestones.length;
|
||||
}
|
||||
final deposit = double.tryParse(totalDeposit) ?? 0;
|
||||
return (deposit / 1000).clamp(0.0, 1.0);
|
||||
}
|
||||
|
||||
/// 根据状态获取进度条颜色
|
||||
Color _referralProgressColor(int claimableCount, double progress) {
|
||||
if (claimableCount > 0) return _profitGreen;
|
||||
if (progress > 0) return _goldAccent;
|
||||
return _bgTertiary;
|
||||
}
|
||||
|
||||
/// 构建推荐奖励的操作按钮
|
||||
Widget? _buildReferralAction({
|
||||
required Map<String, dynamic> data,
|
||||
required int claimableCount,
|
||||
required List<dynamic> milestones,
|
||||
required double progress,
|
||||
}) {
|
||||
if (claimableCount > 0) {
|
||||
final int milestoneValue = milestones.isNotEmpty
|
||||
? (milestones.firstWhere(
|
||||
(m) => (m as Map<String, dynamic>)['claimable'] == true,
|
||||
orElse: () => milestones.first,
|
||||
) as Map<String, dynamic>)['milestone'] as int? ?? 1
|
||||
: 1;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => _claimReferralBonus(data['userId'] as int, milestoneValue),
|
||||
child: _statusBadge('领取', _profitGreen, _profitGreenBg),
|
||||
);
|
||||
}
|
||||
if (progress > 0) {
|
||||
return _statusBadge('进行中', const Color(0xFFD97706), const Color(0xFFFEF3C7));
|
||||
}
|
||||
return Text(
|
||||
'待达标',
|
||||
style: _inter(fontSize: 12, fontWeight: FontWeight.w500, color: _textMuted),
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 奖励规则卡片
|
||||
// ============================================
|
||||
@@ -670,7 +627,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.fromLTRB(20, 16, 20, 16),
|
||||
decoration: BoxDecoration(
|
||||
color: _bgTertiary(context),
|
||||
color: _bgTertiary,
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
),
|
||||
child: Column(
|
||||
@@ -678,32 +635,33 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
|
||||
children: [
|
||||
Text(
|
||||
'奖励规则',
|
||||
style: GoogleFonts.inter(
|
||||
style: _inter(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_buildRuleItem('新用户注册完成实名认证奖励 100 USDT', context),
|
||||
_buildRuleItem('邀请好友充值每达 1000 USDT,双方各获得 100 USDT', context),
|
||||
_buildRuleItem('奖励直接发放至资金账户', context),
|
||||
_buildRuleItem('新用户注册完成实名认证奖励 100 USDT'),
|
||||
_buildRuleItem('邀请好友充值每达 1000 USDT,双方各获得 100 USDT'),
|
||||
_buildRuleItem('奖励直接发放至资金账户'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRuleItem(String text, BuildContext context) {
|
||||
Widget _buildRuleItem(String text) {
|
||||
final ruleTextColor = _isDark
|
||||
? AppColorScheme.darkOnSurfaceVariant
|
||||
: const Color(0xFF475569);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 3),
|
||||
child: Text(
|
||||
'\u2022 $text',
|
||||
style: GoogleFonts.inter(
|
||||
style: _inter(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? AppColorScheme.darkOnSurfaceVariant
|
||||
: const Color(0xFF475569),
|
||||
color: ruleTextColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user