import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:uuid/uuid.dart'; import 'package:webview_flutter/webview_flutter.dart'; import '../../../core/theme/app_colors.dart'; import '../../../core/utils/logger.dart'; import '../../../data/models/user_Info.dart'; import '../comment_url.dart'; import '../device_info_helper.dart'; /// 用户反馈:加载加密后的 App Comment 评论页(每次进入重新生成 URL) class CommentWebView extends StatefulWidget { const CommentWebView({super.key}); @override State createState() => _CommentWebViewState(); } class _CommentWebViewState extends State { WebViewController? _controller; bool _isLoading = true; String? _error; static const _anonStorageKey = 'comment_feedback_anon_id'; @override void initState() { super.initState(); _loadUrl(); } Future _loadUrl() async { try { final packageInfo = await PackageInfo.fromPlatform(); final device = await readCommentDeviceInfo(); final lang = Get.locale?.languageCode ?? 'en'; final String userId; final String? userName; if (User.isLoggedIn()) { userId = User.instance.uid.isNotEmpty ? User.instance.uid : _ensureAnonymousUserId(); userName = User.instance.name.isNotEmpty ? User.instance.name : null; } else { userId = _ensureAnonymousUserId(); userName = null; } final url = await buildCommentUrl( userId: userId, userName: userName, packageName: packageInfo.packageName, appName: packageInfo.appName, appVersion: '${packageInfo.version}+${packageInfo.buildNumber}', lang: lang, deviceBrand: device.brand, deviceModel: device.model, osType: device.osType, osVersion: device.osVersion, ); Logger.debug('评论页 URL 已生成'); if (!mounted) return; setState(() { _controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setBackgroundColor(Colors.white) ..setNavigationDelegate( NavigationDelegate( onPageFinished: (_) { Logger.debug('WebView 页面加载完成'); if (mounted) setState(() => _isLoading = false); }, onWebResourceError: (error) { Logger.error( 'WebView 资源错误: code=${error.errorCode}, ' 'type=${error.errorType}, desc=${error.description}, ' 'mainFrame=${error.isForMainFrame}', ); if (error.isForMainFrame == true && mounted) { setState(() { _isLoading = false; _error = error.description; }); } }, onHttpError: (error) { Logger.error( 'WebView HTTP 错误: status=${error.response?.statusCode}, ' 'uri=${error.request?.uri}', ); }, ), ) ..setOnConsoleMessage((message) { Logger.debug( '[WebView Console] ${message.level.name}: ${message.message}', ); }) ..loadRequest(Uri.parse(url)); }); } catch (e, st) { Logger.error('生成评论页 URL 失败', e, st); if (mounted) { setState(() { _isLoading = false; _error = e.toString(); }); } } } String _ensureAnonymousUserId() { final storage = GetStorage(); var id = storage.read(_anonStorageKey); if (id == null || id.isEmpty) { id = const Uuid().v4(); storage.write(_anonStorageKey, id); } return id; } @override Widget build(BuildContext context) { final isDarkMode = Theme.of(context).brightness == Brightness.dark; return Scaffold( backgroundColor: isDarkMode ? AppColors.darkBackground : Theme.of(context).scaffoldBackgroundColor, appBar: AppBar( elevation: 0, backgroundColor: isDarkMode ? AppColors.darkBackground : Colors.white, leading: IconButton( icon: Icon( Icons.arrow_back_ios, size: 20.sp, color: isDarkMode ? AppColors.textPrimary : Colors.black87, ), onPressed: () => Get.back(), ), title: Text( 'feedback'.tr, style: TextStyle( fontSize: 17.sp, fontWeight: FontWeight.w600, color: isDarkMode ? AppColors.textPrimary : Colors.black87, ), ), centerTitle: true, ), body: _buildBody(isDarkMode), ); } Widget _buildBody(bool isDarkMode) { if (_error != null) { final msgColor = isDarkMode ? AppColors.textSecondary : Colors.black54; return Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 24.w), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.error_outline, size: 48.sp, color: msgColor, ), SizedBox(height: 16.h), Text( 'loadFailed'.tr, style: TextStyle(fontSize: 16.sp, color: msgColor), textAlign: TextAlign.center, ), SizedBox(height: 8.h), Text( _error!, style: TextStyle(fontSize: 12.sp, color: msgColor), textAlign: TextAlign.center, maxLines: 4, overflow: TextOverflow.ellipsis, ), SizedBox(height: 16.h), ElevatedButton( onPressed: () { setState(() { _error = null; _isLoading = true; _controller = null; }); _loadUrl(); }, child: Text('retry'.tr), ), ], ), ), ); } return Stack( children: [ if (_controller != null) WebViewWidget(controller: _controller!), if (_isLoading) const Center(child: CircularProgressIndicator()), ], ); } }