From 58de4f74d60614a51bed78f6d5bf2cc29cc6f141 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Mon, 28 Jul 2025 20:40:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(privacy):=20=E6=B7=BB=E5=8A=A0=E9=9A=90?= =?UTF-8?q?=E7=A7=81=E6=94=BF=E7=AD=96=E5=BC=B9=E7=AA=97=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=B9=B6=E9=87=8D=E6=9E=84=E7=9B=B8=E5=85=B3=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将隐私政策弹窗逻辑提取为独立组件,优化代码复用 在登录和闪屏页面使用新组件替代重复实现 支持暗黑模式适配和国际化 --- .../common/widgets/privacy_policy_dialog.dart | 200 ++++++++++++++++++ .../login/controllers/login_controller.dart | 171 +-------------- .../splash/controllers/splash_controller.dart | 168 +-------------- 3 files changed, 217 insertions(+), 322 deletions(-) create mode 100644 lib/modules/common/widgets/privacy_policy_dialog.dart diff --git a/lib/modules/common/widgets/privacy_policy_dialog.dart b/lib/modules/common/widgets/privacy_policy_dialog.dart new file mode 100644 index 000000000..b6863e2f3 --- /dev/null +++ b/lib/modules/common/widgets/privacy_policy_dialog.dart @@ -0,0 +1,200 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import '../webview_page.dart'; + +/// 隐私政策弹窗组件 +class PrivacyPolicyDialog extends StatelessWidget { + final VoidCallback? onAccept; // 同意回调 + final VoidCallback? onReject; // 拒绝回调 + final bool canDismiss; // 是否可以通过返回键关闭 + + const PrivacyPolicyDialog({ + super.key, + this.onAccept, + this.onReject, + this.canDismiss = false, + }); + + /// 显示隐私政策弹窗 + static Future show({ + VoidCallback? onAccept, + VoidCallback? onReject, + bool canDismiss = false, + }) { + return Get.dialog( + PrivacyPolicyDialog( + onAccept: onAccept, + onReject: onReject, + canDismiss: canDismiss, + ), + barrierDismissible: canDismiss, + ); + } + + @override + Widget build(BuildContext context) { + final bool isDarkMode = Get.theme.brightness == Brightness.dark; + + return PopScope( + canPop: canDismiss, // 根据参数决定是否可以通过返回键关闭 + child: Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.r), + ), + backgroundColor: + isDarkMode ? Colors.grey[800] : Colors.white, // 暗黑模式使用深灰色背景 + child: Container( + padding: EdgeInsets.all(20.w), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'loginDeclaration'.tr, // APP 声明 + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.bold, + color: isDarkMode ? Colors.white : Colors.black, // 暗黑模式使用白色文字 + ), + ), + SizedBox(height: 16.h), + Padding( + padding: EdgeInsets.symmetric(horizontal: 20.w), + child: Text.rich( + TextSpan( + children: [ + TextSpan( + text: 'welcomeToThisApp'.tr, // 欢迎使用本APP,请充分阅读 + style: TextStyle( + fontSize: 14.sp, + color: isDarkMode + ? Colors.white70 + : Colors.black87, // 暗黑模式使用浅白色 + ), + ), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: GestureDetector( + onTap: () { + String url = + 'https://www.voitrans.net/doc/ysxy.html'; // 隐私政策链接 + if (Get.locale?.languageCode != 'zh' || + Get.locale?.countryCode != 'CN') { + url = + 'https://www.voitrans.net/doc/ysxy_en.html'; // 隐私政策英文链接 + } + Get.to(() => WebViewPage( + url: url, + title: 'privacyPolicy'.tr, + )); + }, + child: Text( + 'privacyPolicy'.tr, // 隐私政策 + style: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF3B82F6), + ), + ), + ), + ), + TextSpan( + text: 'and'.tr, // 和 + style: TextStyle( + fontSize: 14.sp, + color: isDarkMode ? Colors.white70 : Colors.black87, + ), + ), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: GestureDetector( + onTap: () { + String url = + 'https://www.voitrans.net/doc/yhxy.html'; // 用户协议链接 + if (Get.locale?.languageCode != 'zh' || + Get.locale?.countryCode != 'CN') { + url = + 'https://www.voitrans.net/doc/yhxy_en.html'; // 用户协议英文链接 + } + Get.to(() => WebViewPage( + url: url, + title: 'userAgreement'.tr, // 用户协议 + )); + }, + child: Text( + 'userAgreement'.tr, // 用户协议 + style: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF3B82F6), + ), + ), + ), + ), + TextSpan( + text: 'privacyPolicyText' + .tr, // ',点击"同意并进入"表示您已充分阅读并同意上述协议。点击"不同意"将退出应用。', + style: TextStyle( + fontSize: 14.sp, + color: isDarkMode ? Colors.white70 : Colors.black87, + ), + ), + ], + ), + textAlign: TextAlign.center, + ), + ), + SizedBox(height: 20.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: () { + if (onReject != null) { + onReject!(); + } else { + // 默认行为:退出应用 + exit(0); + } + }, + style: TextButton.styleFrom( + foregroundColor: isDarkMode + ? Colors.grey[400] + : Colors.black54, // 暗黑模式使用浅灰色 + ), + child: Text( + 'disagree'.tr, // 不同意 + style: TextStyle( + color: isDarkMode ? Colors.grey[400] : Colors.black54, + ), + ), + ), + ElevatedButton( + onPressed: () { + if (onAccept != null) { + onAccept!(); + } else { + // 默认行为:关闭弹窗 + Get.back(); + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF0066CC), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + elevation: isDarkMode ? 4 : 2, // 暗黑模式下增加阴影效果提高辨识度 + padding: EdgeInsets.symmetric( + horizontal: 16.w, vertical: 10.h), // 统一的内边距 + ), + child: Text('agreeAndEnter'.tr), // 同意并进入 + ), + ], + ), + ], + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/modules/login/controllers/login_controller.dart b/lib/modules/login/controllers/login_controller.dart index fb27108f2..3cd59f5fd 100644 --- a/lib/modules/login/controllers/login_controller.dart +++ b/lib/modules/login/controllers/login_controller.dart @@ -12,12 +12,12 @@ import 'weixinLogin.dart'; import 'appleLogin.dart'; import '../../../data/services/network/api.dart'; import '../../../../data/models/user_Info.dart'; -import '../../common/webview_page.dart'; import 'package:get_storage/get_storage.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'dart:io'; import 'package:package_info_plus/package_info_plus.dart'; import '../../../data/services/version_update_service.dart'; +import '../../../modules/common/widgets/privacy_policy_dialog.dart'; enum LoginViewState { welcome, // 欢迎页面 @@ -267,167 +267,14 @@ class LoginController extends GetxController { // 显示隐私政策弹窗 void _showPrivacyDialog() { - // 获取当前主题模式 - final bool isDarkMode = Get.theme.brightness == Brightness.dark; - - Get.dialog( - WillPopScope( - onWillPop: () async => false, // 禁止通过返回键关闭弹窗 - child: Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - backgroundColor: - isDarkMode ? Colors.grey[800] : Colors.white, // 暗黑模式使用深灰色背景 - child: Container( - padding: const EdgeInsets.all(20), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'loginDeclaration'.tr, //APP 声明 - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: - isDarkMode ? Colors.white : Colors.black, // 暗黑模式使用白色文字 - ), - ), - const SizedBox(height: 16), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Text.rich( - TextSpan( - children: [ - TextSpan( - text: 'welcomeToThisApp'.tr, //欢迎使用本APP,请充分阅读 - style: TextStyle( - fontSize: 14, - color: isDarkMode - ? Colors.white70 - : Colors.black87, // 暗黑模式使用浅白色 - ), - ), - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: GestureDetector( - onTap: () { - String url = - 'https://www.voitrans.net/doc/ysxy.html'; // 隐私政策链接 - if (Get.locale?.languageCode != 'zh' || - Get.locale?.countryCode != 'CN') { - url = - 'https://www.voitrans.net/doc/ysxy_en.html'; // 隐私政策英文链接 - } - Get.to(() => WebViewPage( - url: url, - title: 'privacyPolicy'.tr, - )); - }, - child: Text( - 'privacyPolicy'.tr, //隐私政策 - style: const TextStyle( - fontSize: 14, - color: Color(0xFF3B82F6), - ), - ), - ), - ), - TextSpan( - text: 'and'.tr, //和 - style: TextStyle( - fontSize: 14, - color: isDarkMode ? Colors.white70 : Colors.black87, - ), - ), - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: GestureDetector( - onTap: () { - String url = - 'https://www.voitrans.net/doc/yhxy.html'; // 用户协议链接 - if (Get.locale?.languageCode != 'zh' || - Get.locale?.countryCode != 'CN') { - url = - 'https://www.voitrans.net/doc/yhxy_en.html'; // 用户协议英文链接 - } - Get.to(() => WebViewPage( - url: url, - title: 'userAgreement'.tr, //用户协议 - )); - }, - child: Text( - 'userAgreement'.tr, //用户协议 - style: const TextStyle( - fontSize: 14, - color: Color(0xFF3B82F6), - ), - ), - ), - ), - TextSpan( - text: 'privacyPolicyText' - .tr, //',点击“同意并进入”表示您已充分阅读并同意上述协议。点击“不同意”将退出应用。', - style: TextStyle( - fontSize: 14, - color: isDarkMode ? Colors.white70 : Colors.black87, - ), - ), - ], - ), - textAlign: TextAlign.center, - ), - ), - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - TextButton( - onPressed: () { - // 用户不同意,退出应用 - exit(0); - }, - style: TextButton.styleFrom( - foregroundColor: isDarkMode - ? Colors.grey[400] - : Colors.black54, // 暗黑模式使用浅灰色 - ), - child: Text( - 'disagree'.tr, //不同意 - style: TextStyle( - color: isDarkMode ? Colors.grey[400] : Colors.black54, - ), - ), - //child: const Text('不同意'), - ), - ElevatedButton( - onPressed: () { - _storage.write( - 'hasAcceptedPrivacy', true); // 存储用户已接受隐私政策 - // 用户同意,关闭弹窗并继续 - _hasAcceptedPrivacy.value = true; - Get.back(); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0066CC), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: isDarkMode ? 4 : 2, // 暗黑模式下增加阴影效果提高辨识度 - padding: const EdgeInsets.symmetric( - horizontal: 16, vertical: 10), // 统一的内边距 - ), - child: Text('agreeAndEnter'.tr), - ), - ], - ), - ], - ), - ), - ), - ), - barrierDismissible: false, // 禁止点击外部关闭弹窗 + PrivacyPolicyDialog.show( + onAccept: () { + _storage.write('hasAcceptedPrivacy', true); // 存储用户已接受隐私政策 + _hasAcceptedPrivacy.value = true; + Get.back(); + }, + onReject: () => exit(0), + canDismiss: false, // 禁止通过返回键关闭弹窗 ); } diff --git a/lib/modules/splash/controllers/splash_controller.dart b/lib/modules/splash/controllers/splash_controller.dart index a333d3ac2..b12b22746 100644 --- a/lib/modules/splash/controllers/splash_controller.dart +++ b/lib/modules/splash/controllers/splash_controller.dart @@ -11,6 +11,7 @@ import '../../../core/themes/theme_service.dart'; import '../../../data/services/network/api.dart'; import '../../../data/services/version_update_service.dart'; import '../../../modules/common/widgets/version_update_dialog.dart'; +import '../../../modules/common/widgets/privacy_policy_dialog.dart'; import '../../common/webview_page.dart'; class SplashController extends GetxController { @@ -65,166 +66,13 @@ class SplashController extends GetxController { // 显示隐私政策弹窗 void _showPrivacyDialog() { - // 获取当前主题模式 - final bool isDarkMode = Get.theme.brightness == Brightness.dark; - - Get.dialog( - WillPopScope( - onWillPop: () async => false, // 禁止通过返回键关闭弹窗 - child: Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - backgroundColor: - isDarkMode ? Colors.grey[800] : Colors.white, // 暗黑模式使用深灰色背景 - child: Container( - padding: const EdgeInsets.all(20), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'loginDeclaration'.tr, //APP 声明 - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: - isDarkMode ? Colors.white : Colors.black, // 暗黑模式使用白色文字 - ), - ), - const SizedBox(height: 16), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Text.rich( - TextSpan( - children: [ - TextSpan( - text: 'welcomeToThisApp'.tr, //欢迎使用本APP,请充分阅读 - style: TextStyle( - fontSize: 14, - color: isDarkMode - ? Colors.white70 - : Colors.black87, // 暗黑模式使用浅白色 - ), - ), - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: GestureDetector( - onTap: () { - String url = - 'https://www.voitrans.net/doc/ysxy.html'; // 隐私政策链接 - if (Get.locale?.languageCode != 'zh' || - Get.locale?.countryCode != 'CN') { - url = - 'https://www.voitrans.net/doc/ysxy_en.html'; // 隐私政策英文链接 - } - Get.to(() => WebViewPage( - url: url, - title: 'privacyPolicy'.tr, - )); - }, - child: Text( - 'privacyPolicy'.tr, //隐私政策 - style: const TextStyle( - fontSize: 14, - color: Color(0xFF3B82F6), - ), - ), - ), - ), - TextSpan( - text: 'and'.tr, //和 - style: TextStyle( - fontSize: 14, - color: isDarkMode ? Colors.white70 : Colors.black87, - ), - ), - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: GestureDetector( - onTap: () { - String url = - 'https://www.voitrans.net/doc/yhxy.html'; // 用户协议链接 - if (Get.locale?.languageCode != 'zh' || - Get.locale?.countryCode != 'CN') { - url = - 'https://www.voitrans.net/doc/yhxy_en.html'; // 用户协议英文链接 - } - Get.to(() => WebViewPage( - url: url, - title: 'userAgreement'.tr, //用户协议 - )); - }, - child: Text( - 'userAgreement'.tr, //用户协议 - style: const TextStyle( - fontSize: 14, - color: Color(0xFF3B82F6), - ), - ), - ), - ), - TextSpan( - text: 'privacyPolicyText' - .tr, //',点击“同意并进入”表示您已充分阅读并同意上述协议。点击“不同意”将退出应用。', - style: TextStyle( - fontSize: 14, - color: isDarkMode ? Colors.white70 : Colors.black87, - ), - ), - ], - ), - textAlign: TextAlign.center, - ), - ), - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - TextButton( - onPressed: () { - // 用户不同意,退出应用 - _onPrivacyRejected(); - }, - style: TextButton.styleFrom( - foregroundColor: isDarkMode - ? Colors.grey[400] - : Colors.black54, // 暗黑模式使用浅灰色 - ), - child: Text( - 'disagree'.tr, //不同意 - style: TextStyle( - color: isDarkMode ? Colors.grey[400] : Colors.black54, - ), - ), - //child: const Text('不同意'), - ), - ElevatedButton( - onPressed: () { - _onPrivacyAccepted(); - // 用户同意,关闭弹窗并继续 - _hasAcceptedPrivacy.value = true; - //Get.back(); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0066CC), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: isDarkMode ? 4 : 2, // 暗黑模式下增加阴影效果提高辨识度 - padding: const EdgeInsets.symmetric( - horizontal: 16, vertical: 10), // 统一的内边距 - ), - child: Text('agreeAndEnter'.tr), - ), - ], - ), - ], - ), - ), - ), - ), - barrierDismissible: false, // 禁止点击外部关闭弹窗 + PrivacyPolicyDialog.show( + onAccept: () { + _onPrivacyAccepted(); + _hasAcceptedPrivacy.value = true; + }, + onReject: _onPrivacyRejected, + canDismiss: false, // 禁止通过返回键关闭弹窗 ); }