import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_theme_extension.dart'; import '../../../core/storage/local_storage.dart'; /// 引导页数据模型 class _OnboardingItem { final String title; final String description; final IconData? icon; // 图标(二选一) final String? imagePath; // 图片路径(二选一) final List gradientColors; const _OnboardingItem({ required this.title, required this.description, this.icon, this.imagePath, required this.gradientColors, }); } /// 首次启动引导页 class OnboardingPage extends StatefulWidget { final VoidCallback onComplete; const OnboardingPage({super.key, required this.onComplete}); @override State createState() => _OnboardingPageState(); } class _OnboardingPageState extends State { final PageController _pageController = PageController(); int _currentPage = 0; final _items = const [ _OnboardingItem( title: '实时行情', description: '全球市场行情实时更新,把握每一个投资机会', imagePath: 'assets/images/onboarding_1.png', // 替换为你的图片 gradientColors: [AppColorScheme.darkPrimary, AppColorScheme.darkPrimaryContainer], ), _OnboardingItem( title: '模拟交易', description: '零风险体验真实交易,学习投资策略', imagePath: 'assets/images/onboarding_2.png', // 替换为你的图片 gradientColors: [AppColorScheme.darkTertiary, AppColorScheme.darkTertiaryContainer], ), _OnboardingItem( title: '资产管理', description: '清晰的资产概览,轻松管理你的投资组合', imagePath: 'assets/images/onboarding_3.png', // 替换为你的图片 gradientColors: [AppColorScheme.darkSecondary, AppColorScheme.darkSecondaryFixed], ), _OnboardingItem( title: '安全可靠', description: '数据加密存储,保护你的隐私安全', imagePath: 'assets/images/onboarding_4.png', // 替换为你的图片 gradientColors: [AppColorScheme.darkPrimaryFixed, AppColorScheme.darkPrimaryFixedDim], ), ]; @override void dispose() { _pageController.dispose(); super.dispose(); } void _nextPage() { if (_currentPage < _items.length - 1) { _pageController.nextPage( duration: const Duration(milliseconds: 400), curve: Curves.easeInOut, ); } else { _completeOnboarding(); } } void _skip() { _completeOnboarding(); } Future _completeOnboarding() async { await LocalStorage.setBool('onboarding_completed', true); widget.onComplete(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: context.colors.surface, body: SafeArea( child: Column( children: [ // 顶部跳过按钮 Padding( padding: const EdgeInsets.symmetric( horizontal: AppSpacing.lg, vertical: AppSpacing.md, ), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: _skip, child: Text( '跳过', style: AppTextStyles.headlineMedium(context).copyWith( color: context.colors.onSurfaceVariant, ), ), ), ], ), ), // 页面内容 Expanded( child: PageView.builder( controller: _pageController, onPageChanged: (index) { setState(() { _currentPage = index; }); }, itemCount: _items.length, itemBuilder: (context, index) { return _buildPage(_items[index]); }, ), ), // 底部指示器和按钮 Padding( padding: const EdgeInsets.fromLTRB( AppSpacing.lg, AppSpacing.md, AppSpacing.lg, AppSpacing.xl, ), child: Column( children: [ // 页面指示器 Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate( _items.length, (index) => _buildIndicator(index), ), ), const SizedBox(height: AppSpacing.xl), // 下一步/开始按钮 SizedBox( width: double.infinity, height: 56, child: ElevatedButton( onPressed: _nextPage, style: ElevatedButton.styleFrom( backgroundColor: context.colors.primary, foregroundColor: context.colors.onPrimary, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppRadius.lg), ), elevation: 0, ), child: Text( _currentPage == _items.length - 1 ? '开始使用' : '下一步', style: AppTextStyles.headlineLarge(context).copyWith( fontWeight: FontWeight.w600, ), ), ), ), ], ), ), ], ), ), ); } Widget _buildPage(_OnboardingItem item) { return Padding( padding: const EdgeInsets.symmetric(horizontal: AppSpacing.xl), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 图标/图片容器 Container( width: 200, height: 200, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: item.gradientColors, ), shape: BoxShape.circle, boxShadow: [ BoxShadow( color: item.gradientColors.first.withValues(alpha: 0.4), blurRadius: 40, offset: const Offset(0, 20), ), ], ), child: Center( child: item.imagePath != null ? ClipOval( child: Image.asset( item.imagePath!, width: 180, height: 180, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { // 图片加载失败时显示图标 return Icon( item.icon ?? LucideIcons.image, size: 72, color: context.colors.onPrimary, ); }, ), ) : Icon( item.icon ?? LucideIcons.star, size: 72, color: context.colors.onPrimary, ), ), ), const SizedBox(height: AppSpacing.xxl + AppSpacing.lg), // 标题 Text( item.title, style: AppTextStyles.displaySmall(context).copyWith( fontWeight: FontWeight.bold, color: context.colors.onSurface, letterSpacing: -0.5, ), ), const SizedBox(height: AppSpacing.md), // 描述 Text( item.description, textAlign: TextAlign.center, style: AppTextStyles.headlineMedium(context).copyWith( color: context.colors.onSurfaceVariant, height: 1.6, ), ), ], ), ); } Widget _buildIndicator(int index) { final isActive = index == _currentPage; return AnimatedContainer( duration: const Duration(milliseconds: 300), margin: const EdgeInsets.symmetric(horizontal: AppSpacing.xs), width: isActive ? 24 : 8, height: 8, decoration: BoxDecoration( color: isActive ? context.colors.primary : context.colors.outlineVariant, borderRadius: BorderRadius.circular(AppRadius.sm), ), ); } }