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), ), ); } }