import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../config/app_config.dart'; import '../constants/app_constants.dart'; /// 时间: 2026-03-27 /// 功能: 强制引导页检查器 /// 介绍: 确保引导页一定会显示,如果没有显示则抛出异常并显示错误对话框 /// 最新变化: 新建强制检查机制 class ForceGuideChecker { /// 强制检查引导页状态 /// 返回 true 表示需要显示引导页,false 表示不需要 /// 如果检测到异常情况,会抛出 GuidePageException static Future checkAndValidate( SharedPreferences prefs, ) async { try { // 获取所有键 final allKeys = prefs.getKeys(); debugPrint('=== 强制引导页检查 ==='); debugPrint('所有配置项: $allKeys'); // 检查关键配置是否存在 final bool hasFirstLaunch = prefs.containsKey(AppConfig.keyFirstLaunch); final bool hasAgreementAccepted = prefs.containsKey(AppConfig.keyAgreementAccepted); final bool hasAppVersion = prefs.containsKey(AppConfig.keyAppVersion); debugPrint('hasFirstLaunch: $hasFirstLaunch'); debugPrint('hasAgreementAccepted: $hasAgreementAccepted'); debugPrint('hasAppVersion: $hasAppVersion'); // 获取状态值 final bool firstLaunch = prefs.getBool(AppConfig.keyFirstLaunch) ?? true; final bool agreementAccepted = prefs.getBool(AppConfig.keyAgreementAccepted) ?? false; final int? savedVersion = prefs.getInt(AppConfig.keyAppVersion); debugPrint('firstLaunch: $firstLaunch'); debugPrint('agreementAccepted: $agreementAccepted'); debugPrint('savedVersion: $savedVersion'); // 判断是否需要显示引导页 bool needGuide = false; String reason = ''; // 情况1: 首次安装(没有版本号) if (savedVersion == null) { needGuide = true; reason = '首次安装(无版本号)'; debugPrint('需要引导页: $reason'); } // 情况2: firstLaunch 为 true else if (firstLaunch) { needGuide = true; reason = '首次启动标志为 true'; debugPrint('需要引导页: $reason'); } // 情况3: 未同意协议 else if (!agreementAccepted) { needGuide = true; reason = '未同意协议'; debugPrint('需要引导页: $reason'); } // 情况4: 缺少关键配置 else if (!hasFirstLaunch || !hasAgreementAccepted) { needGuide = true; reason = '缺少关键配置项'; debugPrint('需要引导页: $reason'); } else { debugPrint('不需要引导页,正常启动'); } return GuideCheckResult( needGuide: needGuide, reason: reason, firstLaunch: firstLaunch, agreementAccepted: agreementAccepted, savedVersion: savedVersion, hasFirstLaunch: hasFirstLaunch, hasAgreementAccepted: hasAgreementAccepted, hasAppVersion: hasAppVersion, allKeys: allKeys.toList(), ); } catch (e) { debugPrint('强制引导页检查异常: $e'); throw GuidePageException('引导页检查失败: $e'); } } /// 显示错误对话框 static void showErrorDialog( BuildContext context, GuideCheckResult result, String errorMessage, ) { showDialog( context: context, barrierDismissible: false, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ Icon(Icons.error, color: Colors.red), const SizedBox(width: 8), const Text('引导页加载异常'), ], ), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '错误信息:', style: TextStyle( fontWeight: FontWeight.bold, color: Colors.red, ), ), const SizedBox(height: 8), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(8), ), child: Text( errorMessage, style: TextStyle(fontSize: 12, fontFamily: 'monospace'), ), ), const SizedBox(height: 16), Text( '检测结果:', style: TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(height: 8), _buildInfoRow('需要引导页', result.needGuide ? '是' : '否'), _buildInfoRow('原因', result.reason), _buildInfoRow('firstLaunch', result.firstLaunch.toString()), _buildInfoRow( 'agreementAccepted', result.agreementAccepted.toString()), _buildInfoRow('savedVersion', result.savedVersion?.toString() ?? 'null'), _buildInfoRow('hasFirstLaunch', result.hasFirstLaunch.toString()), _buildInfoRow('hasAgreementAccepted', result.hasAgreementAccepted.toString()), _buildInfoRow('hasAppVersion', result.hasAppVersion.toString()), const SizedBox(height: 8), Text( '所有配置项: ${result.allKeys}', style: TextStyle(fontSize: 11, color: Colors.grey[600]), ), ], ), ), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(); }, child: const Text('关闭'), ), ElevatedButton( onPressed: () async { // 清空所有配置并重启 final prefs = await SharedPreferences.getInstance(); await prefs.clear(); Navigator.of(context).pop(); }, style: ElevatedButton.styleFrom( backgroundColor: AppConstants.primaryColor, ), child: const Text('清空配置'), ), ], ), ); } static Widget _buildInfoRow(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Row( children: [ SizedBox( width: 120, child: Text( '$label:', style: TextStyle(fontSize: 12, color: Colors.grey[700]), ), ), Expanded( child: Text( value, style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500), ), ), ], ), ); } } /// 引导页检查结果 class GuideCheckResult { final bool needGuide; final String reason; final bool firstLaunch; final bool agreementAccepted; final int? savedVersion; final bool hasFirstLaunch; final bool hasAgreementAccepted; final bool hasAppVersion; final List allKeys; GuideCheckResult({ required this.needGuide, required this.reason, required this.firstLaunch, required this.agreementAccepted, required this.savedVersion, required this.hasFirstLaunch, required this.hasAgreementAccepted, required this.hasAppVersion, required this.allKeys, }); } /// 引导页异常 class GuidePageException implements Exception { final String message; GuidePageException(this.message); @override String toString() => 'GuidePageException: $message'; }