From 4ea1cf0edf3fce9eca29c4b2f6dc0e2962727134 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Tue, 10 Jun 2025 15:17:46 +0800 Subject: [PATCH] =?UTF-8?q?refactor(permission):=20=E7=A7=BB=E9=99=A4conte?= =?UTF-8?q?xt=E5=8F=82=E6=95=B0=E5=B9=B6=E4=BD=BF=E7=94=A8GetX=E6=9B=BF?= =?UTF-8?q?=E4=BB=A3=E5=8E=9F=E7=94=9F=E5=AF=B9=E8=AF=9D=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构权限请求工具类,移除所有BuildContext参数依赖 使用GetX的对话框和导航替代原生实现 简化权限请求流程并提高代码可维护性 --- lib/core/utils/permission_util.dart | 181 ++++++++++++------ lib/data/services/music_manager.dart | 46 ++--- .../agent/controllers/agent_controller.dart | 4 +- .../controllers/meeting_controller.dart | 4 +- .../controllers/pairing_controller.dart | 12 +- .../settings/views/permissions_view.dart | 6 +- 6 files changed, 155 insertions(+), 98 deletions(-) diff --git a/lib/core/utils/permission_util.dart b/lib/core/utils/permission_util.dart index 0961e7120..04ea36e25 100644 --- a/lib/core/utils/permission_util.dart +++ b/lib/core/utils/permission_util.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:app_settings/app_settings.dart'; import 'logger.dart'; +import 'package:get/get.dart'; /// 权限请求工具类 /// @@ -21,7 +22,7 @@ class PermissionUtil { PermissionUtil._(); /// 权限解释横幅的叠加层入口 - OverlayEntry? _explanationOverlayEntry; + //OverlayEntry? _explanationOverlayEntry; /// 请求指定权限 /// @@ -36,7 +37,7 @@ class PermissionUtil { /// /// 返回值:`Future` 权限是否最终授予 Future requestPermission({ - required BuildContext context, + // required BuildContext context, required Permission permissionType, required String permissionName, required String explanationText, @@ -58,7 +59,7 @@ class PermissionUtil { // 显示权限解释横幅(覆盖所有状态的处理) _showExplanationOverlay( - context: context, + //context: context, permissionName: permissionName, explanationText: explanationText, ); @@ -69,7 +70,7 @@ class PermissionUtil { // 显示永久拒绝对话框(在解释横幅下方显示) final result = await _showPermanentDenialDialog( - context: context, + // context: context, permissionName: permissionName, permanentDenialText: permanentDenialText, settingsButtonText: settingsButtonText, @@ -105,7 +106,7 @@ class PermissionUtil { else if (newStatus == PermissionStatus.permanentlyDenied) { Logger.w('PermissionUtil', '$permissionName 权限在请求后被永久拒绝'); final result = await _showPermanentDenialDialog( - context: context, + // context: context, permissionName: permissionName, permanentDenialText: permanentDenialText, settingsButtonText: settingsButtonText, @@ -123,7 +124,7 @@ class PermissionUtil { if (status == PermissionStatus.restricted || status == PermissionStatus.limited) { Logger.w('PermissionUtil', '$permissionName 权限受限或受限访问: $status'); - await _showRestrictedPermissionDialog(context, permissionName); + await _showRestrictedPermissionDialog(permissionName); _hideExplanationOverlay(); return false; } @@ -148,69 +149,104 @@ class PermissionUtil { /// /// 在请求权限前显示,向用户解释为什么需要这个权限 void _showExplanationOverlay({ - required BuildContext context, required String permissionName, required String explanationText, }) { - _hideExplanationOverlay(); // 确保移除旧叠加层 - - _explanationOverlayEntry = OverlayEntry( - builder: (context) => Positioned( - top: MediaQuery.of(context).padding.top + 10, - left: 16, - right: 16, - child: Material( - borderRadius: BorderRadius.circular(12), - elevation: 8, - color: Theme.of(context).colorScheme.background, - shadowColor: Colors.black.withOpacity(0.3), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '需要$permissionName权限', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - const SizedBox(height: 8), - Text( - explanationText, - style: const TextStyle(fontSize: 14), + Get.dialog( + Stack( + children: [ + Positioned( + top: 10, + left: 16, + right: 16, + child: Material( + borderRadius: BorderRadius.circular(12), + elevation: 8, + color: Colors.grey[300], + shadowColor: Colors.black.withOpacity(0.3), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '需要$permissionName权限', + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + const SizedBox(height: 8), + Text( + explanationText, + style: const TextStyle(fontSize: 14), + ), + ], ), - ], + ), ), ), - ), + ], ), ); + // _hideExplanationOverlay(); // 确保移除旧叠加层 - Future.delayed(Duration.zero, () { - if (_explanationOverlayEntry != null) { - Overlay.of(context).insert(_explanationOverlayEntry!); - Logger.i('PermissionUtil', '权限说明叠加层已显示 ($permissionName)'); - } - }); + // _explanationOverlayEntry = OverlayEntry( + // builder: (context) => Positioned( + // top: MediaQuery.of(context).padding.top + 10, + // left: 16, + // right: 16, + // child: Material( + // borderRadius: BorderRadius.circular(12), + // elevation: 8, + // color: Theme.of(context).colorScheme.background, + // shadowColor: Colors.black.withOpacity(0.3), + // child: Padding( + // padding: const EdgeInsets.all(16), + // child: Column( + // mainAxisSize: MainAxisSize.min, + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Text( + // '需要$permissionName权限', + // style: const TextStyle( + // fontWeight: FontWeight.bold, + // fontSize: 16, + // ), + // ), + // const SizedBox(height: 8), + // Text( + // explanationText, + // style: const TextStyle(fontSize: 14), + // ), + // ], + // ), + // ), + // ), + // ), + // ); + + // Future.delayed(Duration.zero, () { + // if (_explanationOverlayEntry != null) { + // Overlay.of(context).insert(_explanationOverlayEntry!); + // Logger.i('PermissionUtil', '权限说明叠加层已显示 ($permissionName)'); + // } + // }); } /// 隐藏权限解释横幅 void _hideExplanationOverlay() { - if (_explanationOverlayEntry != null) { - _explanationOverlayEntry?.remove(); - _explanationOverlayEntry = null; - Logger.d('PermissionUtil', '权限说明叠加层已移除'); - } + Get.back(); + //_explanationOverlayEntry!.remove(); + Logger.d('PermissionUtil', '权限说明叠加层已移除'); } /// 显示永久拒绝后的设置引导对话框 /// /// 在权限被永久拒绝时调用,提示用户前往设置手动开启权限 Future _showPermanentDenialDialog({ - required BuildContext context, + //required BuildContext context, required String permissionName, required String permanentDenialText, required String settingsButtonText, @@ -218,31 +254,36 @@ class PermissionUtil { }) async { Logger.i('PermissionUtil', '显示永久拒绝对话框 ($permissionName)'); - bool? userChoice = await showDialog( - context: context, - barrierDismissible: false, - builder: (context) => AlertDialog( + bool? userChoice = await Get.dialog( + AlertDialog( title: Text('需要$permissionName权限'), content: Text(permanentDenialText), actions: [ TextButton( onPressed: () { Logger.d('PermissionUtil', '用户取消设置 ($permissionName)'); - Navigator.pop(context, false); + Get.back(result: false); }, child: Text(cancelButtonText), ), ElevatedButton( onPressed: () { Logger.d('PermissionUtil', '用户同意前往设置 ($permissionName)'); - Navigator.pop(context, true); + Get.back(result: true); }, child: Text(settingsButtonText), ), ], ), + barrierDismissible: false, ); + // bool? userChoice = await showDialog( + // context: context, + // barrierDismissible: false, + // builder: (context) => + // ); + // 用户选择前往设置 if (userChoice == true) { AppSettings.openAppSettings(); @@ -256,24 +297,40 @@ class PermissionUtil { /// 显示受限权限对话框 /// /// 在权限受限状态(如iOS上的受限照片访问)时调用 - Future _showRestrictedPermissionDialog( - BuildContext context, String permissionName) async { + Future _showRestrictedPermissionDialog(String permissionName) async { Logger.w('PermissionUtil', '显示受限权限对话框 ($permissionName)'); - await showDialog( - context: context, - builder: (context) => AlertDialog( + Get.dialog( + AlertDialog( title: Text('$permissionName权限受限'), content: const Text('此功能在当前设备上不可用或受限,请检查设备设置或系统限制'), actions: [ TextButton( onPressed: () { Logger.d('PermissionUtil', '用户确认受限权限 ($permissionName)'); - Navigator.pop(context); + // Navigator.pop(context); + Get.back(); }, child: const Text('确定'), ), ], ), ); + + // await showDialog( + // context: context, + // builder: (context) => AlertDialog( + // title: Text('$permissionName权限受限'), + // content: const Text('此功能在当前设备上不可用或受限,请检查设备设置或系统限制'), + // actions: [ + // TextButton( + // onPressed: () { + // Logger.d('PermissionUtil', '用户确认受限权限 ($permissionName)'); + // Navigator.pop(context); + // }, + // child: const Text('确定'), + // ), + // ], + // ), + // ); } } diff --git a/lib/data/services/music_manager.dart b/lib/data/services/music_manager.dart index 7e19942a6..8bfea2f47 100644 --- a/lib/data/services/music_manager.dart +++ b/lib/data/services/music_manager.dart @@ -16,34 +16,34 @@ class MusicManager extends GetxService { @override void onInit() { super.onInit(); - - final context = Get.context; - if (context == null) { - Logger.error('无法获取 BuildContext'); - return; - } - requestNotificationPermission(context); + + // final context = Get.context; + // if (context == null) { + // Logger.error('无法获取 BuildContext'); + // return; + // } + requestNotificationPermission(); Logger.info('初始化权限请求'); } - Future requestNotificationPermission(BuildContext context) async { - final granted = await PermissionUtil.instance.requestPermission( - context: context, - permissionType: Permission.notification, - permissionName: '通知', - explanationText: '需要通知权限来显示音乐播放状态。', - permanentDenialText: '您已永久拒绝通知权限,请前往设置开启权限。', - settingsButtonText: '去设置', - cancelButtonText: '取消', - ); + Future requestNotificationPermission() async { + final granted = await PermissionUtil.instance.requestPermission( + // context: context, + permissionType: Permission.notification, + permissionName: '通知', + explanationText: '需要通知权限来显示音乐播放状态。', + permanentDenialText: '您已永久拒绝通知权限,请前往设置开启权限。', + settingsButtonText: '去设置', + cancelButtonText: '取消', + ); - if (!granted) { - Logger.warning('通知权限未被授予'); - return; - } + if (!granted) { + Logger.warning('通知权限未被授予'); + return; + } - Logger.info('通知权限已授予'); -} + Logger.info('通知权限已授予'); + } /// 释放资源 @override diff --git a/lib/modules/agent/controllers/agent_controller.dart b/lib/modules/agent/controllers/agent_controller.dart index 1a80b8679..eeb4e2248 100644 --- a/lib/modules/agent/controllers/agent_controller.dart +++ b/lib/modules/agent/controllers/agent_controller.dart @@ -700,7 +700,7 @@ class AgentController extends GetxController { if (isTextInputMode.value) { // 使用 PermissionUtil 检查麦克风权限 final hasPermission = await PermissionUtil.instance.requestPermission( - context: Get.context!, + // context: Get.context!, permissionType: Permission.microphone, permissionName: '麦克风', explanationText: '语音识别与翻译功能需要访问麦克风。', @@ -881,7 +881,7 @@ class AgentController extends GetxController { // 检查麦克风权限 final hasPermission = await PermissionUtil.instance.requestPermission( - context: Get.context!, + // context: Get.context!, permissionType: Permission.microphone, permissionName: '麦克风', explanationText: '语音识别与翻译功能需要访问麦克风。', diff --git a/lib/modules/meeting/controllers/meeting_controller.dart b/lib/modules/meeting/controllers/meeting_controller.dart index b191326b7..82cfabbc2 100644 --- a/lib/modules/meeting/controllers/meeting_controller.dart +++ b/lib/modules/meeting/controllers/meeting_controller.dart @@ -87,11 +87,11 @@ class MeetingController extends GetxController { // 请求录音权限 void _requestStoragePermission() async { - final BuildContext context = Get.overlayContext!; + // final BuildContext context = Get.overlayContext!; PermissionUtil.instance .requestPermission( - context: context, + // context: context, permissionType: Permission.storage, permissionName: "存储", explanationText: "我们需要访问存储权限,以便您可以选择并上传音频文件。", diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart index 4f32dfd4f..2c7debbe5 100644 --- a/lib/modules/pairing/controllers/pairing_controller.dart +++ b/lib/modules/pairing/controllers/pairing_controller.dart @@ -529,11 +529,11 @@ class PairingController extends GetxController { } // Android权限检查 - 使用 PermissionUtil - final context = Get.context; - if (context == null) { - Logger.e(_tag, '无法获取有效上下文,跳过权限请求'); - return false; - } + // final context = Get.context; + // if (context == null) { + // Logger.e(_tag, '无法获取有效上下文,跳过权限请求'); + // return false; + // } // 根据 Android 版本确定需要的权限 List requiredPermissions = [ @@ -551,7 +551,7 @@ class PairingController extends GetxController { Logger.d(_tag, '正在请求 $permissionName 权限'); final granted = await PermissionUtil.instance.requestPermission( - context: context, + // context: context, permissionType: permission, permissionName: permissionName, explanationText: _getExplanationText(permission), diff --git a/lib/modules/settings/views/permissions_view.dart b/lib/modules/settings/views/permissions_view.dart index abfaa2ee7..ee0d27311 100644 --- a/lib/modules/settings/views/permissions_view.dart +++ b/lib/modules/settings/views/permissions_view.dart @@ -295,15 +295,15 @@ class PermissionsView extends GetView { Future _handlePermissionAction( Permission permission, PermissionStatus status) async { try { - final context = Get.context; - if (context == null) return; + // final context = Get.context; + // if (context == null) return; final permissionName = _getPermissionName(permission); final explanationText = _getExplanationText(permission); // 使用 PermissionUtil 请求权限 final hasPermission = await PermissionUtil.instance.requestPermission( - context: context, + // context: context, permissionType: permission, permissionName: permissionName, explanationText: explanationText,