rwadurian/frontend/mining-app/lib/presentation/pages/profile/profile_page.dart

640 lines
18 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../core/router/routes.dart';
import '../../providers/user_providers.dart';
import '../../providers/profile_providers.dart';
import '../../widgets/shimmer_loading.dart';
class ProfilePage extends ConsumerWidget {
const ProfilePage({super.key});
// 设计色彩
static const Color _orange = Color(0xFFFF6B00);
static const Color _green = Color(0xFF10B981);
static const Color _darkText = Color(0xFF1F2937);
static const Color _grayText = Color(0xFF6B7280);
static const Color _lightGray = Color(0xFF9CA3AF);
static const Color _bgGray = Color(0xFFF3F4F6);
static const Color _red = Color(0xFFEF4444);
@override
Widget build(BuildContext context, WidgetRef ref) {
final user = ref.watch(userNotifierProvider);
final statsAsync = ref.watch(userStatsProvider);
final isStatsLoading = statsAsync.isLoading;
final stats = statsAsync.valueOrNull;
return Scaffold(
backgroundColor: _bgGray,
body: SafeArea(
bottom: false,
child: RefreshIndicator(
onRefresh: () async {
ref.invalidate(userStatsProvider);
await ref.read(userNotifierProvider.notifier).fetchProfile();
},
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children: [
// 用户头部信息
_buildUserHeader(context, user),
const SizedBox(height: 16),
// 统计数据行
_buildStatsRow(stats, isStatsLoading),
const SizedBox(height: 16),
// 账户设置
_buildAccountSettings(context, user),
const SizedBox(height: 16),
// 记录入口
_buildRecordsSection(context),
const SizedBox(height: 16),
// 团队与收益
_buildTeamEarningsSection(context),
const SizedBox(height: 16),
// 其他设置
_buildOtherSettings(context),
const SizedBox(height: 24),
// 退出登录
_buildLogoutButton(context, ref),
const SizedBox(height: 16),
// 版本信息
const Text(
'Version 1.0.0',
style: TextStyle(
fontSize: 12,
color: _lightGray,
),
),
const SizedBox(height: 24),
],
),
),
),
),
);
}
Widget _buildUserHeader(BuildContext context, UserState user) {
return Container(
padding: const EdgeInsets.all(20),
color: Colors.white,
child: Row(
children: [
// 头像
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
colors: [_orange.withValues(alpha: 0.8), _orange],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Center(
child: Text(
user.nickname?.isNotEmpty == true
? user.nickname!.substring(0, 1).toUpperCase()
: (user.realName?.isNotEmpty == true
? user.realName!.substring(0, 1).toUpperCase()
: 'U'),
style: const TextStyle(
fontSize: 36,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
),
const SizedBox(width: 16),
// 用户信息
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
user.realName ?? user.nickname ?? '榴莲用户',
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: _darkText,
),
),
const SizedBox(width: 8),
// 实名认证徽章
if (user.isKycVerified)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 2,
),
decoration: BoxDecoration(
color: _green.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(10),
),
child: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.verified, size: 12, color: _green),
SizedBox(width: 2),
Text(
'已实名',
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w500,
color: _green,
),
),
],
),
),
],
),
const SizedBox(height: 8),
Row(
children: [
Text(
'ID: ${user.accountSequence ?? '--------'}',
style: const TextStyle(
fontSize: 14,
color: _grayText,
),
),
const SizedBox(width: 8),
GestureDetector(
onTap: () {
if (user.accountSequence != null) {
Clipboard.setData(
ClipboardData(text: user.accountSequence!),
);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('ID已复制'),
duration: Duration(seconds: 1),
),
);
}
},
child: const Icon(
Icons.copy,
size: 16,
color: _grayText,
),
),
],
),
// 手机号
if (user.phone != null)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
'手机: ${user.phone}',
style: const TextStyle(
fontSize: 12,
color: _lightGray,
),
),
),
],
),
),
// 编辑按钮
IconButton(
onPressed: () {
// TODO: 编辑个人资料
},
icon: const Icon(
Icons.edit_outlined,
color: _grayText,
),
),
],
),
);
}
Widget _buildStatsRow(UserStats? stats, bool isLoading) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 16),
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildStatItem(
'认种状态',
stats?.hasAdopted == true ? '已认种' : '未认种',
isLoading,
),
_buildDivider(),
_buildStatItem(
'引荐人数',
stats?.directReferralAdoptedCount.toString() ?? '0',
isLoading,
),
_buildDivider(),
_buildStatItem(
'团队下级',
stats?.unlockedLevelDepth.toString() ?? '0',
isLoading,
),
_buildDivider(),
_buildStatItem(
'团队上级',
'15',
isLoading,
),
],
),
);
}
Widget _buildStatItem(String label, String value, bool isLoading) {
return Column(
children: [
DataText(
data: isLoading ? null : value,
isLoading: isLoading,
placeholder: '--',
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: _darkText,
),
),
const SizedBox(height: 4),
Text(
label,
style: const TextStyle(
fontSize: 12,
color: _grayText,
),
),
],
);
}
Widget _buildDivider() {
return Container(
width: 1,
height: 30,
color: _bgGray,
);
}
Widget _buildAccountSettings(BuildContext context, UserState user) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
child: Text(
'账户设置',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: _darkText,
),
),
),
_buildSettingItem(
icon: Icons.security,
label: '账户安全',
onTap: () => context.push(Routes.changePassword),
),
_buildSettingItem(
icon: Icons.lock_outline,
label: '支付密码',
trailing: const Text(
'已设置',
style: TextStyle(
fontSize: 14,
color: _green,
),
),
onTap: () {},
showDivider: false,
),
],
),
);
}
Widget _buildSettingItem({
required IconData icon,
required String label,
Widget? trailing,
required VoidCallback onTap,
bool showDivider = true,
}) {
return Column(
children: [
ListTile(
leading: Icon(icon, color: _grayText, size: 22),
title: Text(
label,
style: const TextStyle(
fontSize: 14,
color: _darkText,
),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (trailing != null) trailing,
if (trailing != null) const SizedBox(width: 8),
const Icon(Icons.chevron_right, color: _lightGray, size: 20),
],
),
onTap: onTap,
),
if (showDivider)
const Divider(height: 1, indent: 56, endIndent: 16),
],
);
}
Widget _buildRecordsSection(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'我的记录',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: _darkText,
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildRecordIcon(
icon: Icons.eco,
label: '认种记录',
onTap: () {},
),
_buildRecordIcon(
icon: Icons.assignment,
label: '分配记录',
onTap: () {},
),
_buildRecordIcon(
icon: Icons.receipt_long,
label: '交易记录',
onTap: () {},
),
_buildRecordIcon(
icon: Icons.account_balance_wallet,
label: '提现记录',
onTap: () {},
),
],
),
],
),
);
}
Widget _buildRecordIcon({
required IconData icon,
required String label,
required VoidCallback onTap,
}) {
return GestureDetector(
onTap: onTap,
behavior: HitTestBehavior.opaque,
child: Column(
children: [
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: _orange.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(icon, color: _orange, size: 24),
),
const SizedBox(height: 8),
Text(
label,
style: const TextStyle(
fontSize: 12,
color: _grayText,
),
),
],
),
);
}
Widget _buildTeamEarningsSection(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
child: Text(
'团队与收益',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: _darkText,
),
),
),
_buildSettingItem(
icon: Icons.people,
label: '我的团队',
onTap: () {},
),
_buildSettingItem(
icon: Icons.trending_up,
label: '收益明细',
onTap: () {},
),
_buildSettingItem(
icon: Icons.card_giftcard,
label: '推广奖励',
onTap: () {},
showDivider: false,
),
],
),
);
}
Widget _buildOtherSettings(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
child: Text(
'其他设置',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: _darkText,
),
),
),
_buildSwitchItem(
icon: Icons.notifications_outlined,
label: '消息通知',
value: true,
onChanged: (value) {},
),
_buildSwitchItem(
icon: Icons.dark_mode_outlined,
label: '深色模式',
value: false,
onChanged: (value) {},
),
_buildSettingItem(
icon: Icons.help_outline,
label: '帮助中心',
onTap: () {},
),
_buildSettingItem(
icon: Icons.info_outline,
label: '关于我们',
onTap: () {},
showDivider: false,
),
],
),
);
}
Widget _buildSwitchItem({
required IconData icon,
required String label,
required bool value,
required ValueChanged<bool> onChanged,
}) {
return Column(
children: [
ListTile(
leading: Icon(icon, color: _grayText, size: 22),
title: Text(
label,
style: const TextStyle(
fontSize: 14,
color: _darkText,
),
),
trailing: Switch(
value: value,
onChanged: onChanged,
activeTrackColor: _orange,
activeThumbColor: Colors.white,
),
),
const Divider(height: 1, indent: 56, endIndent: 16),
],
);
}
Widget _buildLogoutButton(BuildContext context, WidgetRef ref) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: SizedBox(
width: double.infinity,
child: TextButton(
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('退出登录'),
content: const Text('确定要退出登录吗?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('取消'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
ref.read(userNotifierProvider.notifier).logout();
},
child: const Text(
'确定',
style: TextStyle(color: _red),
),
),
],
),
);
},
style: TextButton.styleFrom(
backgroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: const Text(
'退出登录',
style: TextStyle(
fontSize: 16,
color: _red,
fontWeight: FontWeight.w500,
),
),
),
),
);
}
}