574 lines
19 KiB
Dart
574 lines
19 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter/gestures.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
import '../../../../routes/route_paths.dart';
|
||
import '../../../../routes/app_router.dart';
|
||
import '../../../../core/di/injection_container.dart';
|
||
import '../../../../core/storage/storage_keys.dart';
|
||
import '../../../../core/services/multi_account_service.dart';
|
||
|
||
/// 创建账号页面 - 用户首次进入应用时的引导页面
|
||
/// 提供创建钱包和导入助记词两种选项
|
||
class OnboardingPage extends ConsumerStatefulWidget {
|
||
const OnboardingPage({super.key});
|
||
|
||
@override
|
||
ConsumerState<OnboardingPage> createState() => _OnboardingPageState();
|
||
}
|
||
|
||
class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
||
// 用户协议勾选状态
|
||
bool _isAgreed = false;
|
||
// 创建钱包加载状态
|
||
bool _isCreating = false;
|
||
// 账号是否已创建
|
||
bool _isAccountCreated = false;
|
||
// 是否正在加载状态
|
||
bool _isLoading = true;
|
||
// 已创建的账号数据
|
||
String? _userSerialNum;
|
||
String? _username;
|
||
String? _avatarSvg;
|
||
String? _referralCode;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
debugPrint('[OnboardingPage] initState - 检查账号状态');
|
||
_checkAccountStatus();
|
||
}
|
||
|
||
/// 检查账号是否已创建
|
||
Future<void> _checkAccountStatus() async {
|
||
debugPrint('[OnboardingPage] _checkAccountStatus - 开始检查');
|
||
try {
|
||
final accountService = ref.read(accountServiceProvider);
|
||
|
||
// 检查是否已创建账号
|
||
final hasAccount = await accountService.hasAccount();
|
||
debugPrint('[OnboardingPage] _checkAccountStatus - hasAccount: $hasAccount');
|
||
|
||
if (hasAccount) {
|
||
// 读取已保存的账号数据
|
||
debugPrint('[OnboardingPage] _checkAccountStatus - 读取已保存账号数据');
|
||
final userSerialNum = await accountService.getUserSerialNum();
|
||
final username = await accountService.getUsername();
|
||
final avatarSvg = await accountService.getAvatarSvg();
|
||
final referralCode = await accountService.getReferralCode();
|
||
|
||
debugPrint('[OnboardingPage] _checkAccountStatus - userSerialNum: $userSerialNum, username: $username');
|
||
|
||
if (mounted) {
|
||
setState(() {
|
||
_isAccountCreated = true;
|
||
_userSerialNum = userSerialNum;
|
||
_username = username;
|
||
_avatarSvg = avatarSvg;
|
||
_referralCode = referralCode;
|
||
_isLoading = false;
|
||
// 如果账号已创建,自动勾选协议
|
||
_isAgreed = true;
|
||
});
|
||
}
|
||
} else {
|
||
debugPrint('[OnboardingPage] _checkAccountStatus - 账号未创建');
|
||
if (mounted) {
|
||
setState(() {
|
||
_isAccountCreated = false;
|
||
_isLoading = false;
|
||
});
|
||
}
|
||
}
|
||
} catch (e, stackTrace) {
|
||
debugPrint('[OnboardingPage] _checkAccountStatus - 异常: $e');
|
||
debugPrint('[OnboardingPage] _checkAccountStatus - 堆栈: $stackTrace');
|
||
if (mounted) {
|
||
setState(() {
|
||
_isAccountCreated = false;
|
||
_isLoading = false;
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 创建账号
|
||
///
|
||
/// 调用后端 API 快速创建账号(不含钱包信息)
|
||
Future<void> _createAccount() async {
|
||
debugPrint('[OnboardingPage] _createAccount - 用户点击创建账号');
|
||
if (!_isAgreed) {
|
||
debugPrint('[OnboardingPage] _createAccount - 未同意协议,显示提示');
|
||
_showAgreementTip();
|
||
return;
|
||
}
|
||
|
||
setState(() {
|
||
_isCreating = true;
|
||
});
|
||
|
||
try {
|
||
// 获取 AccountService 和 SecureStorage
|
||
final accountService = ref.read(accountServiceProvider);
|
||
final secureStorage = ref.read(secureStorageProvider);
|
||
|
||
// 读取邀请人推荐码(从向导页保存的)
|
||
final inviterReferralCode = await secureStorage.read(
|
||
key: StorageKeys.inviterReferralCode,
|
||
);
|
||
debugPrint('[OnboardingPage] _createAccount - 邀请人推荐码: ${inviterReferralCode ?? "无"}');
|
||
|
||
// 调用后端 API 创建账号
|
||
debugPrint('[OnboardingPage] _createAccount - 调用 accountService.createAccount()');
|
||
final response = await accountService.createAccount(
|
||
inviterReferralCode: inviterReferralCode,
|
||
);
|
||
debugPrint('[OnboardingPage] _createAccount - 成功! 序列号=${response.userSerialNum}, 用户名=${response.username}');
|
||
|
||
// 创建成功后清除临时存储的邀请人推荐码
|
||
if (inviterReferralCode != null) {
|
||
await secureStorage.delete(key: StorageKeys.inviterReferralCode);
|
||
debugPrint('[OnboardingPage] _createAccount - 已清除临时邀请人推荐码');
|
||
}
|
||
|
||
// 将账号添加到多账号列表
|
||
final multiAccountService = ref.read(multiAccountServiceProvider);
|
||
await multiAccountService.addAccount(
|
||
AccountSummary(
|
||
userSerialNum: response.userSerialNum,
|
||
username: response.username,
|
||
avatarSvg: response.avatarSvg,
|
||
createdAt: DateTime.now(),
|
||
),
|
||
);
|
||
await multiAccountService.setCurrentAccountId(response.userSerialNum);
|
||
debugPrint('[OnboardingPage] _createAccount - 已添加到多账号列表');
|
||
|
||
if (!mounted) {
|
||
debugPrint('[OnboardingPage] _createAccount - Widget已卸载,忽略响应');
|
||
return;
|
||
}
|
||
|
||
// 更新状态
|
||
debugPrint('[OnboardingPage] _createAccount - 更新本地状态');
|
||
setState(() {
|
||
_isAccountCreated = true;
|
||
_userSerialNum = response.userSerialNum;
|
||
_username = response.username;
|
||
_avatarSvg = response.avatarSvg;
|
||
_referralCode = response.referralCode;
|
||
});
|
||
|
||
// 跳转到备份助记词页面
|
||
debugPrint('[OnboardingPage] _createAccount - 跳转到备份助记词页面');
|
||
context.push(
|
||
RoutePaths.backupMnemonic,
|
||
extra: BackupMnemonicParams(
|
||
userSerialNum: response.userSerialNum,
|
||
referralCode: response.referralCode,
|
||
),
|
||
);
|
||
} catch (e, stackTrace) {
|
||
debugPrint('[OnboardingPage] _createAccount - 创建失败: $e');
|
||
debugPrint('[OnboardingPage] _createAccount - 堆栈: $stackTrace');
|
||
if (!mounted) return;
|
||
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(
|
||
content: Text('创建账号失败: ${e.toString().replaceAll('Exception: ', '')}'),
|
||
backgroundColor: Colors.red,
|
||
duration: const Duration(seconds: 5),
|
||
),
|
||
);
|
||
} finally {
|
||
if (mounted) {
|
||
setState(() => _isCreating = false);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 显示需要同意协议的提示
|
||
void _showAgreementTip() {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(
|
||
content: Text('请先阅读并同意用户协议和隐私政策'),
|
||
backgroundColor: Color(0xFFD4AF37),
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 显示用户协议
|
||
void _showUserAgreement() {
|
||
// TODO: 跳转到用户协议页面
|
||
debugPrint('显示用户协议');
|
||
}
|
||
|
||
/// 显示隐私政策
|
||
void _showPrivacyPolicy() {
|
||
// TODO: 跳转到隐私政策页面
|
||
debugPrint('显示隐私政策');
|
||
}
|
||
|
||
/// 导入助记词
|
||
void _importMnemonic() {
|
||
debugPrint('[OnboardingPage] _importMnemonic - 跳转到导入助记词页面');
|
||
context.push(RoutePaths.importMnemonic);
|
||
}
|
||
|
||
/// 跳转到备份助记词页面(账号已创建的情况)
|
||
void _goToBackupMnemonic() {
|
||
debugPrint('[OnboardingPage] _goToBackupMnemonic - 跳转到备份页面');
|
||
if (_userSerialNum == null) {
|
||
debugPrint('[OnboardingPage] _goToBackupMnemonic - userSerialNum为空,显示错误');
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(
|
||
content: Text('账号数据不完整,请重新创建'),
|
||
backgroundColor: Colors.red,
|
||
),
|
||
);
|
||
return;
|
||
}
|
||
|
||
debugPrint('[OnboardingPage] _goToBackupMnemonic - userSerialNum: $_userSerialNum');
|
||
context.push(
|
||
RoutePaths.backupMnemonic,
|
||
extra: BackupMnemonicParams(
|
||
userSerialNum: _userSerialNum!,
|
||
referralCode: _referralCode,
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 处理按钮点击
|
||
void _handleButtonTap() {
|
||
debugPrint('[OnboardingPage] _handleButtonTap - isAccountCreated: $_isAccountCreated');
|
||
if (_isAccountCreated) {
|
||
// 账号已创建,跳转到备份页面
|
||
_goToBackupMnemonic();
|
||
} else {
|
||
// 账号未创建,创建新账号
|
||
_createAccount();
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
body: Container(
|
||
width: double.infinity,
|
||
height: double.infinity,
|
||
// 背景图片
|
||
decoration: const BoxDecoration(
|
||
image: DecorationImage(
|
||
image: AssetImage('assets/images/backgrounds/onboarding_bg.jpg'),
|
||
fit: BoxFit.cover,
|
||
),
|
||
),
|
||
child: SafeArea(
|
||
child: Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||
child: Column(
|
||
children: [
|
||
// 顶部返回按钮
|
||
_buildHeader(),
|
||
// 留出空间给背景图的 logo
|
||
const Spacer(flex: 3),
|
||
// 创建账户说明区域
|
||
_buildDescription(),
|
||
const SizedBox(height: 16),
|
||
// 底部操作区域
|
||
_buildActionSection(),
|
||
const Spacer(flex: 1),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 返回向导页第5页(仅在账号未创建时可用)
|
||
void _goBackToGuide() {
|
||
debugPrint('[OnboardingPage] _goBackToGuide - 返回向导页第5页');
|
||
// 返回向导页,传入初始页索引4(第5页)
|
||
context.go(RoutePaths.guide, extra: 4);
|
||
}
|
||
|
||
/// 构建顶部返回按钮
|
||
Widget _buildHeader() {
|
||
return SizedBox(
|
||
height: 32,
|
||
child: (!_isLoading && !_isAccountCreated)
|
||
? Align(
|
||
alignment: Alignment.centerLeft,
|
||
child: GestureDetector(
|
||
onTap: _goBackToGuide,
|
||
behavior: HitTestBehavior.opaque,
|
||
child: Container(
|
||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white.withValues(alpha: 0.9),
|
||
borderRadius: BorderRadius.circular(16),
|
||
),
|
||
child: const Row(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Icon(
|
||
Icons.arrow_back_ios,
|
||
size: 16,
|
||
color: Color(0xFF2E7D32),
|
||
),
|
||
SizedBox(width: 4),
|
||
Text(
|
||
'返回',
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
fontFamily: 'Inter',
|
||
fontWeight: FontWeight.w600,
|
||
color: Color(0xFF2E7D32),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
)
|
||
: null,
|
||
);
|
||
}
|
||
|
||
/// 构建创建账户说明区域
|
||
Widget _buildDescription() {
|
||
return Container(
|
||
padding: const EdgeInsets.all(20),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white.withValues(alpha: 0.95),
|
||
borderRadius: BorderRadius.circular(16),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black.withValues(alpha: 0.1),
|
||
blurRadius: 10,
|
||
offset: const Offset(0, 4),
|
||
),
|
||
],
|
||
),
|
||
child: const Column(
|
||
children: [
|
||
// 标题
|
||
Text(
|
||
'创建账户',
|
||
style: TextStyle(
|
||
fontSize: 22,
|
||
fontFamily: 'Inter',
|
||
fontWeight: FontWeight.w700,
|
||
height: 1.25,
|
||
letterSpacing: -0.33,
|
||
color: Color(0xFF2E7D32),
|
||
),
|
||
),
|
||
SizedBox(height: 12),
|
||
// 说明文字
|
||
Text(
|
||
'我们将为你创建三个链的钱包地址:KAVA / DST / BSC,同时生成唯一序列号用于推荐与权益。',
|
||
style: TextStyle(
|
||
fontSize: 15,
|
||
fontFamily: 'Inter',
|
||
height: 1.5,
|
||
color: Color(0xFF424242),
|
||
),
|
||
textAlign: TextAlign.center,
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 构建底部操作区域
|
||
Widget _buildActionSection() {
|
||
return Container(
|
||
padding: const EdgeInsets.all(20),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white.withValues(alpha: 0.95),
|
||
borderRadius: BorderRadius.circular(16),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black.withValues(alpha: 0.1),
|
||
blurRadius: 10,
|
||
offset: const Offset(0, 4),
|
||
),
|
||
],
|
||
),
|
||
child: Column(
|
||
children: [
|
||
// 生成钱包按钮
|
||
_buildCreateButton(),
|
||
const SizedBox(height: 16),
|
||
// 用户协议勾选
|
||
_buildAgreementCheckbox(),
|
||
const SizedBox(height: 16),
|
||
// 导入助记词链接
|
||
_buildImportLink(),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 构建创建钱包按钮
|
||
Widget _buildCreateButton() {
|
||
// 加载中显示骨架
|
||
if (_isLoading) {
|
||
return Container(
|
||
width: double.infinity,
|
||
height: 48,
|
||
decoration: BoxDecoration(
|
||
color: const Color(0xFFD4AF37).withValues(alpha: 0.5),
|
||
borderRadius: BorderRadius.circular(8),
|
||
),
|
||
child: const Center(
|
||
child: SizedBox(
|
||
width: 24,
|
||
height: 24,
|
||
child: CircularProgressIndicator(
|
||
strokeWidth: 2,
|
||
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
// 根据账号状态决定按钮文字和行为
|
||
final buttonText = _isAccountCreated
|
||
? '账号已创建(点击备份助记词)'
|
||
: '生成钱包(创建账户)';
|
||
|
||
// 账号已创建时,不需要勾选协议
|
||
final isEnabled = _isAccountCreated || _isAgreed;
|
||
|
||
return GestureDetector(
|
||
onTap: (_isCreating || !isEnabled) ? null : _handleButtonTap,
|
||
child: Opacity(
|
||
opacity: isEnabled ? 1.0 : 0.5,
|
||
child: Container(
|
||
width: double.infinity,
|
||
height: 48,
|
||
decoration: BoxDecoration(
|
||
color: _isAccountCreated
|
||
? const Color(0xFF52C41A) // 绿色表示已创建
|
||
: const Color(0xFFD4AF37), // 金色表示待创建
|
||
borderRadius: BorderRadius.circular(8),
|
||
),
|
||
child: Center(
|
||
child: _isCreating
|
||
? const SizedBox(
|
||
width: 24,
|
||
height: 24,
|
||
child: CircularProgressIndicator(
|
||
strokeWidth: 2,
|
||
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||
),
|
||
)
|
||
: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
if (_isAccountCreated) ...[
|
||
const Icon(
|
||
Icons.check_circle,
|
||
color: Colors.white,
|
||
size: 20,
|
||
),
|
||
const SizedBox(width: 8),
|
||
],
|
||
Text(
|
||
buttonText,
|
||
style: const TextStyle(
|
||
fontSize: 16,
|
||
fontFamily: 'Inter',
|
||
fontWeight: FontWeight.w700,
|
||
height: 1.5,
|
||
letterSpacing: 0.24,
|
||
color: Colors.white,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 构建用户协议勾选框
|
||
Widget _buildAgreementCheckbox() {
|
||
return Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
// 勾选框
|
||
SizedBox(
|
||
width: 20,
|
||
height: 20,
|
||
child: Checkbox(
|
||
value: _isAgreed,
|
||
onChanged: (value) {
|
||
setState(() {
|
||
_isAgreed = value ?? false;
|
||
});
|
||
},
|
||
activeColor: const Color(0xFF2E7D32),
|
||
side: const BorderSide(color: Color(0xFF757575)),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(4),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
// 协议文字
|
||
Flexible(
|
||
child: RichText(
|
||
text: TextSpan(
|
||
style: const TextStyle(
|
||
fontSize: 14,
|
||
fontFamily: 'Inter',
|
||
fontWeight: FontWeight.w500,
|
||
height: 1.43,
|
||
color: Color(0xFF424242),
|
||
),
|
||
children: [
|
||
const TextSpan(text: '我已阅读并同意 '),
|
||
TextSpan(
|
||
text: '《用户协议》',
|
||
style: const TextStyle(color: Color(0xFF2E7D32)),
|
||
recognizer: TapGestureRecognizer()..onTap = _showUserAgreement,
|
||
),
|
||
TextSpan(
|
||
text: '《隐私政策》',
|
||
style: const TextStyle(color: Color(0xFF2E7D32)),
|
||
recognizer: TapGestureRecognizer()..onTap = _showPrivacyPolicy,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
/// 构建导入助记词链接
|
||
Widget _buildImportLink() {
|
||
return GestureDetector(
|
||
onTap: _importMnemonic,
|
||
child: const Text(
|
||
'已有账号? 导入助记词',
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
fontFamily: 'Inter',
|
||
fontWeight: FontWeight.w600,
|
||
height: 1.43,
|
||
color: Color(0xFF2E7D32),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|