import 'package:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:app_settings/app_settings.dart'; import 'dart:developer'; import 'logger.dart'; // class Logger { // static void e(String tag, String message) { // debugPrint('[$tag] ERROR: $message'); // } // } class PermissionUtil { static final PermissionUtil instance = PermissionUtil._(); PermissionUtil._(); OverlayEntry? _explanationOverlayEntry; Future requestPermission({ required BuildContext context, required Permission permissionType, required String permissionName, required String explanationText, required String permanentDenialText, String settingsButtonText = '前往设置', String cancelButtonText = '取消', }) async { try { final PermissionStatus status = await permissionType.status; log('初始权限状态 for $permissionName: $status'); // 处理已授权状态(包括授予状态和临时通知权限) if (status == PermissionStatus.granted || status == PermissionStatus.provisional) { log('$permissionName 权限已授予或临时授权。'); return true; } // 处理永久拒绝状态 if (status == PermissionStatus.permanentlyDenied) { log('$permissionName 权限被永久拒绝,显示引导对话框。'); await _showPermanentDenialDialog( context: context, permissionName: permissionName, permanentDenialText: permanentDenialText, settingsButtonText: settingsButtonText, cancelButtonText: cancelButtonText, ); return false; } // 处理初始拒绝/未决定状态 if (status == PermissionStatus.denied) { log('$permissionName 权限被拒绝或未决定,显示说明横幅并请求。'); _showExplanationOverlay( context: context, permissionName: permissionName, explanationText: explanationText, ); final PermissionStatus newStatus = await permissionType.request(); log('请求后 $permissionName 的新权限状态: $newStatus'); _hideExplanationOverlay(); // 处理请求后的状态 if (newStatus == PermissionStatus.granted || newStatus == PermissionStatus.provisional) { log('$permissionName 权限在请求后被授予或临时授权。'); return true; } else if (newStatus == PermissionStatus.permanentlyDenied) { log('$permissionName 权限在请求后被永久拒绝,再次显示引导对话框。'); await _showPermanentDenialDialog( context: context, permissionName: permissionName, permanentDenialText: permanentDenialText, settingsButtonText: settingsButtonText, cancelButtonText: cancelButtonText, ); } return false; } // 处理受限状态 if (status == PermissionStatus.restricted || status == PermissionStatus.limited) { log('$permissionName 权限受限或受限访问: $status'); await _showRestrictedPermissionDialog(context, permissionName); return false; } // 其他未知状态处理 log('$permissionName 处于未知状态: $status'); return false; } catch (e) { Logger.e('PermissionUtil', '请求 $permissionName 权限失败: $e'); _hideExplanationOverlay(); return false; } } 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: 4, color: Colors.white, 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!); log('权限说明叠加层已显示。'); } }); } void _hideExplanationOverlay() { _explanationOverlayEntry?.remove(); _explanationOverlayEntry = null; } Future _showPermanentDenialDialog({ required BuildContext context, required String permissionName, required String permanentDenialText, required String settingsButtonText, required String cancelButtonText, }) async { await showDialog( context: context, barrierDismissible: false, builder: (context) => AlertDialog( title: Text('需要$permissionName权限'), content: Text(permanentDenialText), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text(cancelButtonText), ), ElevatedButton( onPressed: () { Navigator.pop(context); AppSettings.openAppSettings(); }, child: Text(settingsButtonText), ), ], ), ); } Future _showRestrictedPermissionDialog( BuildContext context, String permissionName) async { await showDialog( context: context, builder: (context) => AlertDialog( title: Text('$permissionName权限受限'), content: const Text('此功能在当前设备上不可用或受限,请检查设备设置或系统限制'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('确定'), ), ], ), ); } }