Browse Source
将权限管理功能从设置模块分离为独立模块,新增蓝牙、通知、存储和麦克风权限支持。优化权限分组显示逻辑,根据平台显示不同权限组,并完善权限状态管理和多语言支持。 - 新增权限分组模型和独立控制器 - 添加蓝牙、通知等新权限支持 - 优化权限请求流程和状态显示 - 完善中英文多语言翻译 - 移除旧版权限视图并更新路由配置newdev_shunjiawei
14 changed files with 622 additions and 517 deletions
@ -0,0 +1,9 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import '../controllers/permissions_controller.dart'; |
||||
|
|
||||
|
class PermissionsBinding extends Bindings { |
||||
|
@override |
||||
|
void dependencies() { |
||||
|
Get.lazyPut<PermissionsController>(() => PermissionsController()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,222 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:permission_handler/permission_handler.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'dart:io' show Platform; |
||||
|
import '../../../core/utils/permission_util.dart'; |
||||
|
|
||||
|
class PermissionsController extends GetxController { |
||||
|
// 权限状态映射 |
||||
|
final RxMap<Permission, PermissionStatus> permissionStatuses = |
||||
|
<Permission, PermissionStatus>{}.obs; |
||||
|
|
||||
|
// 是否正在请求权限 |
||||
|
final RxBool isRequestingPermission = false.obs; |
||||
|
|
||||
|
@override |
||||
|
void onInit() { |
||||
|
super.onInit(); |
||||
|
checkAllPermissions(); |
||||
|
} |
||||
|
|
||||
|
/// 检查所有权限状态 |
||||
|
Future<Map<Permission, PermissionStatus>> checkAllPermissions() async { |
||||
|
final Map<Permission, PermissionStatus> statuses = {}; |
||||
|
|
||||
|
// 根据平台获取需要检查的权限列表 |
||||
|
final permissions = _getPlatformPermissions(); |
||||
|
|
||||
|
for (final permission in permissions) { |
||||
|
try { |
||||
|
statuses[permission] = await permission.status; |
||||
|
} catch (e) { |
||||
|
// 某些权限在特定平台可能不支持,设置为拒绝状态 |
||||
|
statuses[permission] = PermissionStatus.denied; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
permissionStatuses.value = statuses; |
||||
|
return statuses; |
||||
|
} |
||||
|
|
||||
|
/// 获取平台特定的权限列表 |
||||
|
List<Permission> _getPlatformPermissions() { |
||||
|
if (Platform.isIOS) { |
||||
|
return [ |
||||
|
Permission.calendarFullAccess, |
||||
|
Permission.location, |
||||
|
Permission.contacts, |
||||
|
Permission.bluetooth, |
||||
|
Permission.notification, |
||||
|
Permission.storage, |
||||
|
Permission.microphone, |
||||
|
]; |
||||
|
} else if (Platform.isAndroid) { |
||||
|
return [ |
||||
|
Permission.calendarFullAccess, |
||||
|
Permission.location, |
||||
|
Permission.phone, |
||||
|
Permission.sms, |
||||
|
Permission.contacts, |
||||
|
Permission.bluetooth, |
||||
|
Permission.notification, |
||||
|
Permission.scheduleExactAlarm, |
||||
|
Permission.storage, |
||||
|
Permission.microphone, |
||||
|
]; |
||||
|
} |
||||
|
return []; |
||||
|
} |
||||
|
|
||||
|
/// 请求单个权限 |
||||
|
Future<bool> requestPermission(Permission permission) async { |
||||
|
if (isRequestingPermission.value) return false; |
||||
|
|
||||
|
isRequestingPermission.value = true; |
||||
|
|
||||
|
try { |
||||
|
final permissionName = getPermissionName(permission); |
||||
|
final explanationText = _getDetailedDescription(permission); |
||||
|
|
||||
|
final hasPermission = await PermissionUtil.instance.requestPermission( |
||||
|
permissionType: permission, |
||||
|
permissionName: permissionName, |
||||
|
explanationText: explanationText, |
||||
|
permanentDenialText: 'permanentDenialText'.tr.replaceAll( |
||||
|
'{permission}', permissionName), |
||||
|
settingsButtonText: 'goToSettings'.tr, |
||||
|
cancelButtonText: 'cancel'.tr, |
||||
|
); |
||||
|
|
||||
|
if (hasPermission) { |
||||
|
_showSuccessMessage(); |
||||
|
} |
||||
|
|
||||
|
// 刷新权限状态 |
||||
|
await checkAllPermissions(); |
||||
|
|
||||
|
return hasPermission; |
||||
|
} catch (e) { |
||||
|
_showErrorMessage(); |
||||
|
return false; |
||||
|
} finally { |
||||
|
isRequestingPermission.value = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 打开系统设置 |
||||
|
void openSettings() { |
||||
|
openAppSettings(); |
||||
|
} |
||||
|
|
||||
|
/// 获取权限的用户友好名称 |
||||
|
String getPermissionName(Permission permission) { |
||||
|
switch (permission) { |
||||
|
case Permission.phone: |
||||
|
return 'phone'.tr; |
||||
|
case Permission.sms: |
||||
|
return 'sms'.tr; |
||||
|
case Permission.contacts: |
||||
|
return 'contacts'.tr; |
||||
|
case Permission.bluetooth: |
||||
|
return 'bluetooth'.tr; |
||||
|
case Permission.notification: |
||||
|
return 'notification'.tr; |
||||
|
case Permission.calendarWriteOnly: |
||||
|
return 'calendarWrite'.tr; |
||||
|
case Permission.calendarFullAccess: |
||||
|
return 'calendarFullAccess'.tr; |
||||
|
case Permission.location: |
||||
|
return 'locationInfo'.tr; |
||||
|
case Permission.scheduleExactAlarm: |
||||
|
return 'alarm'.tr; |
||||
|
case Permission.storage: |
||||
|
return 'storagePermission'.tr; |
||||
|
case Permission.microphone: |
||||
|
return 'microphonePermission'.tr; |
||||
|
default: |
||||
|
return permission.toString(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 获取权限说明文本 |
||||
|
String _getDetailedDescription(Permission permission) { |
||||
|
switch (permission) { |
||||
|
case Permission.phone: |
||||
|
return 'phonePermissionDetailDesc'.tr; |
||||
|
case Permission.sms: |
||||
|
return 'smsPermissionDetailDesc'.tr; |
||||
|
case Permission.contacts: |
||||
|
return 'contactsPermissionDetailDesc'.tr; |
||||
|
case Permission.bluetooth: |
||||
|
return 'bluetoothPermissionDetailDesc'.tr; |
||||
|
case Permission.notification: |
||||
|
return 'notificationPermissionDetailDesc'.tr; |
||||
|
case Permission.calendarWriteOnly: |
||||
|
return 'calendarWritePermissionDetailDesc'.tr; |
||||
|
case Permission.calendarFullAccess: |
||||
|
return 'calendarFullAccessPermissionDetailDesc'.tr; |
||||
|
case Permission.location: |
||||
|
return 'locationPermissionDetailDesc'.tr; |
||||
|
case Permission.scheduleExactAlarm: |
||||
|
return 'alarmPermissionDetailDesc'.tr; |
||||
|
case Permission.storage: |
||||
|
return 'storagePermissionExplanation'.tr; |
||||
|
case Permission.microphone: |
||||
|
return 'microphonePermissionExplanation'.tr; |
||||
|
default: |
||||
|
return 'appNeedsPermissionForFullFunction'.tr; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 获取权限描述 |
||||
|
String getPermissionDescription(Permission permission) { |
||||
|
switch (permission) { |
||||
|
case Permission.phone: |
||||
|
return 'phonePermissionDesc'.tr; |
||||
|
case Permission.sms: |
||||
|
return 'smsPermissionDesc'.tr; |
||||
|
case Permission.contacts: |
||||
|
return 'contactsPermissionDesc'.tr; |
||||
|
case Permission.bluetooth: |
||||
|
return 'bluetoothPermissionDesc'.tr; |
||||
|
case Permission.notification: |
||||
|
return 'notificationPermissionDesc'.tr; |
||||
|
case Permission.calendarWriteOnly: |
||||
|
return 'calendarWritePermissionDesc'.tr; |
||||
|
case Permission.calendarFullAccess: |
||||
|
return 'calendarFullAccessPermissionDesc'.tr; |
||||
|
case Permission.location: |
||||
|
return 'locationPermissionDesc'.tr; |
||||
|
case Permission.scheduleExactAlarm: |
||||
|
return 'alarmPermissionDesc'.tr; |
||||
|
case Permission.storage: |
||||
|
return 'storagePermissionExplanation'.tr; |
||||
|
case Permission.microphone: |
||||
|
return 'microphonePermissionExplanation'.tr; |
||||
|
default: |
||||
|
return 'appFunctionNeeds'.tr; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 显示成功消息 |
||||
|
void _showSuccessMessage() { |
||||
|
Get.snackbar( |
||||
|
'success'.tr, |
||||
|
'permissionGranted'.tr, |
||||
|
snackPosition: SnackPosition.BOTTOM, |
||||
|
backgroundColor: Colors.green, |
||||
|
colorText: Colors.white, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/// 显示错误消息 |
||||
|
void _showErrorMessage() { |
||||
|
Get.snackbar( |
||||
|
'error'.tr, |
||||
|
'permissionRequestError'.tr, |
||||
|
snackPosition: SnackPosition.BOTTOM, |
||||
|
backgroundColor: Colors.red, |
||||
|
colorText: Colors.white, |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,67 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:permission_handler/permission_handler.dart'; |
||||
|
|
||||
|
class PermissionGroup { |
||||
|
final String titleKey; |
||||
|
final IconData icon; |
||||
|
final List<Permission> permissions; |
||||
|
|
||||
|
const PermissionGroup({ |
||||
|
required this.titleKey, |
||||
|
required this.icon, |
||||
|
required this.permissions, |
||||
|
}); |
||||
|
|
||||
|
static List<PermissionGroup> getPlatformGroups() { |
||||
|
return [ |
||||
|
// 通讯权限组 - 仅Android(包含联系人权限) |
||||
|
const PermissionGroup( |
||||
|
titleKey: 'communicationPermissions', |
||||
|
icon: Icons.phone_android, |
||||
|
permissions: [Permission.phone, Permission.sms, Permission.contacts], |
||||
|
), |
||||
|
// 蓝牙权限组 |
||||
|
const PermissionGroup( |
||||
|
titleKey: 'bluetoothPermissions', |
||||
|
icon: Icons.bluetooth, |
||||
|
permissions: [Permission.bluetooth], |
||||
|
), |
||||
|
// 通知权限组 |
||||
|
const PermissionGroup( |
||||
|
titleKey: 'notificationPermissions', |
||||
|
icon: Icons.notifications, |
||||
|
permissions: [Permission.notification], |
||||
|
), |
||||
|
// 闹钟权限组 - 仅Android |
||||
|
const PermissionGroup( |
||||
|
titleKey: 'alarmPermissions', |
||||
|
icon: Icons.alarm, |
||||
|
permissions: [Permission.scheduleExactAlarm], |
||||
|
), |
||||
|
// 日历权限组 |
||||
|
const PermissionGroup( |
||||
|
titleKey: 'calendarPermissions', |
||||
|
icon: Icons.calendar_today, |
||||
|
permissions: [Permission.calendarFullAccess], |
||||
|
), |
||||
|
// 位置权限组 |
||||
|
const PermissionGroup( |
||||
|
titleKey: 'locationPermissions', |
||||
|
icon: Icons.location_on, |
||||
|
permissions: [Permission.location], |
||||
|
), |
||||
|
// 存储权限组 |
||||
|
const PermissionGroup( |
||||
|
titleKey: 'storagePermissions', |
||||
|
icon: Icons.storage, |
||||
|
permissions: [Permission.storage], |
||||
|
), |
||||
|
// 麦克风权限组 |
||||
|
const PermissionGroup( |
||||
|
titleKey: 'microphonePermissions', |
||||
|
icon: Icons.mic, |
||||
|
permissions: [Permission.microphone], |
||||
|
), |
||||
|
]; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,276 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:permission_handler/permission_handler.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import 'dart:ui'; |
||||
|
import 'dart:io' show Platform; |
||||
|
|
||||
|
import '../controllers/permissions_controller.dart'; |
||||
|
import '../models/permission_group.dart'; |
||||
|
|
||||
|
class PermissionsView extends GetView<PermissionsController> { |
||||
|
const PermissionsView({Key? key}) : super(key: key); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
||||
|
|
||||
|
return Scaffold( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], |
||||
|
appBar: AppBar( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.white, |
||||
|
elevation: 0.5, |
||||
|
leading: IconButton( |
||||
|
icon: Icon( |
||||
|
Icons.arrow_back_ios, |
||||
|
size: 20.w, |
||||
|
color: isDarkMode ? Colors.white : Colors.black87, |
||||
|
), |
||||
|
onPressed: () => Get.back(), |
||||
|
), |
||||
|
title: Text( |
||||
|
'permissionManagement'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 17.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
), |
||||
|
centerTitle: true, |
||||
|
), |
||||
|
body: Obx(() { |
||||
|
if (controller.permissionStatuses.isEmpty) { |
||||
|
return const Center(child: CircularProgressIndicator()); |
||||
|
} |
||||
|
|
||||
|
return RefreshIndicator( |
||||
|
onRefresh: controller.checkAllPermissions, |
||||
|
child: ListView( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h), |
||||
|
children: _buildPermissionGroups(isDarkMode), |
||||
|
), |
||||
|
); |
||||
|
}), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
List<Widget> _buildPermissionGroups(bool isDarkMode) { |
||||
|
final groups = PermissionGroup.getPlatformGroups(); |
||||
|
final List<Widget> widgets = []; |
||||
|
|
||||
|
for (int i = 0; i < groups.length; i++) { |
||||
|
final group = groups[i]; |
||||
|
|
||||
|
// 过滤平台特定权限 |
||||
|
if (_shouldShowGroup(group)) { |
||||
|
widgets.add(_buildPermissionSection( |
||||
|
group.titleKey, |
||||
|
group.icon, |
||||
|
group.permissions, |
||||
|
controller.permissionStatuses, |
||||
|
isDarkMode, |
||||
|
)); |
||||
|
|
||||
|
if (i < groups.length - 1) { |
||||
|
widgets.add(SizedBox(height: 20.h)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return widgets; |
||||
|
} |
||||
|
|
||||
|
bool _shouldShowGroup(PermissionGroup group) { |
||||
|
// Android特定权限组 |
||||
|
if (group.titleKey == 'communicationPermissions' || |
||||
|
group.titleKey == 'alarmPermissions') { |
||||
|
return Platform.isAndroid; |
||||
|
} |
||||
|
// 蓝牙权限、通知权限、存储权限和麦克风权限在所有平台显示 |
||||
|
if (group.titleKey == 'bluetoothPermissions' || |
||||
|
group.titleKey == 'notificationPermissions' || |
||||
|
group.titleKey == 'storagePermissions' || |
||||
|
group.titleKey == 'microphonePermissions') { |
||||
|
return true; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
Widget _buildPermissionSection( |
||||
|
String titleKey, |
||||
|
IconData icon, |
||||
|
List<Permission> permissions, |
||||
|
Map<Permission, PermissionStatus> statuses, |
||||
|
bool isDarkMode, |
||||
|
) { |
||||
|
return Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
// 组标题 |
||||
|
Padding( |
||||
|
padding: EdgeInsets.only(left: 4.w, bottom: 8.h), |
||||
|
child: Text( |
||||
|
titleKey.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.sp, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
color: isDarkMode ? Colors.blue[400] : Colors.blue[600], |
||||
|
letterSpacing: 1, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
|
||||
|
// 权限项容器 |
||||
|
Container( |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white, |
||||
|
borderRadius: BorderRadius.circular(16.r), |
||||
|
boxShadow: [ |
||||
|
BoxShadow( |
||||
|
color: isDarkMode |
||||
|
? Colors.black.withOpacity(0.2) |
||||
|
: Colors.black.withOpacity(0.05), |
||||
|
blurRadius: 10, |
||||
|
offset: const Offset(0, 2), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
child: ClipRRect( |
||||
|
borderRadius: BorderRadius.circular(16.r), |
||||
|
child: BackdropFilter( |
||||
|
filter: isDarkMode |
||||
|
? ImageFilter.blur(sigmaX: 5, sigmaY: 5) |
||||
|
: ImageFilter.blur(sigmaX: 0, sigmaY: 0), |
||||
|
child: Column( |
||||
|
children: _buildPermissionItems(permissions, statuses, isDarkMode), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
List<Widget> _buildPermissionItems( |
||||
|
List<Permission> permissions, |
||||
|
Map<Permission, PermissionStatus> statuses, |
||||
|
bool isDarkMode, |
||||
|
) { |
||||
|
final List<Widget> items = []; |
||||
|
|
||||
|
for (int i = 0; i < permissions.length; i++) { |
||||
|
final permission = permissions[i]; |
||||
|
final status = statuses[permission] ?? PermissionStatus.denied; |
||||
|
|
||||
|
items.add( |
||||
|
_buildPermissionItem( |
||||
|
permission: permission, |
||||
|
status: status, |
||||
|
isDarkMode: isDarkMode, |
||||
|
), |
||||
|
); |
||||
|
|
||||
|
// 添加分隔线,最后一个不加 |
||||
|
if (i < permissions.length - 1) { |
||||
|
items.add(Divider( |
||||
|
height: 1, |
||||
|
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200], |
||||
|
)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return items; |
||||
|
} |
||||
|
|
||||
|
Widget _buildPermissionItem({ |
||||
|
required Permission permission, |
||||
|
required PermissionStatus status, |
||||
|
required bool isDarkMode, |
||||
|
}) { |
||||
|
return Padding( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
child: Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||
|
children: [ |
||||
|
Expanded( |
||||
|
child: Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Text( |
||||
|
controller.getPermissionName(permission), |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
color: isDarkMode ? Colors.white : Colors.black87, |
||||
|
), |
||||
|
), |
||||
|
SizedBox(height: 4.h), |
||||
|
Text( |
||||
|
controller.getPermissionDescription(permission), |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.sp, |
||||
|
color: isDarkMode ? Colors.white70 : Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
SizedBox(height: 4.h), |
||||
|
_buildStatusText(status, isDarkMode), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
Obx(() => Switch( |
||||
|
value: status.isGranted, |
||||
|
onChanged: controller.isRequestingPermission.value |
||||
|
? null |
||||
|
: (value) => _handlePermissionToggle(permission, status, value), |
||||
|
activeColor: Colors.blue[600], |
||||
|
)), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildStatusText(PermissionStatus status, bool isDarkMode) { |
||||
|
String text; |
||||
|
Color color; |
||||
|
|
||||
|
if (status.isGranted) { |
||||
|
text = 'authorized'.tr; |
||||
|
color = Colors.green; |
||||
|
} else if (status.isDenied) { |
||||
|
text = 'unauthorized'.tr; |
||||
|
color = Colors.red; |
||||
|
} else if (status.isPermanentlyDenied) { |
||||
|
text = 'needOpenInSystemSettings'.tr; |
||||
|
color = Colors.orange; |
||||
|
} else if (status.isLimited) { |
||||
|
text = 'partialAuthorization'.tr; |
||||
|
color = Colors.orange; |
||||
|
} else { |
||||
|
text = 'unknownStatus'.tr; |
||||
|
color = Colors.grey; |
||||
|
} |
||||
|
|
||||
|
return Text( |
||||
|
text, |
||||
|
style: TextStyle( |
||||
|
color: color, |
||||
|
fontSize: 12.sp, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
void _handlePermissionToggle( |
||||
|
Permission permission, |
||||
|
PermissionStatus status, |
||||
|
bool value, |
||||
|
) { |
||||
|
if (value) { |
||||
|
// 请求权限 |
||||
|
controller.requestPermission(permission); |
||||
|
} else if (status.isGranted) { |
||||
|
// 已授权但用户想关闭,引导到系统设置 |
||||
|
controller.openSettings(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,402 +0,0 @@ |
|||||
import 'package:flutter/material.dart'; |
|
||||
import 'package:get/get.dart'; |
|
||||
import 'package:permission_handler/permission_handler.dart'; |
|
||||
import '../controllers/settings_controller.dart'; |
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|
||||
import 'dart:ui'; |
|
||||
import 'dart:io' show Platform; |
|
||||
|
|
||||
import '../../../core/utils/permission_util.dart'; // 引入PermissionUtil |
|
||||
|
|
||||
class PermissionsView extends GetView<SettingsController> { |
|
||||
const PermissionsView({Key? key}) : super(key: key); |
|
||||
|
|
||||
@override |
|
||||
Widget build(BuildContext context) { |
|
||||
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
|
||||
|
|
||||
return Scaffold( |
|
||||
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], |
|
||||
appBar: AppBar( |
|
||||
backgroundColor: isDarkMode ? Colors.black : Colors.white, |
|
||||
elevation: 0.5, |
|
||||
leading: IconButton( |
|
||||
icon: Icon( |
|
||||
Icons.arrow_back_ios, |
|
||||
size: 20.w, |
|
||||
color: isDarkMode ? Colors.white : Colors.black87, |
|
||||
), |
|
||||
onPressed: () => Get.back(), |
|
||||
), |
|
||||
title: Text( |
|
||||
'permissionManagement'.tr, // 权限管理 |
|
||||
style: TextStyle( |
|
||||
fontSize: 17.sp, |
|
||||
fontWeight: FontWeight.w600, |
|
||||
color: isDarkMode ? Colors.white : Colors.black, |
|
||||
), |
|
||||
), |
|
||||
centerTitle: true, |
|
||||
), |
|
||||
body: FutureBuilder<Map<Permission, PermissionStatus>>( |
|
||||
future: controller.checkAllPermissions(), //检查权限当前状态 |
|
||||
builder: (context, snapshot) { |
|
||||
if (snapshot.connectionState == ConnectionState.waiting) { |
|
||||
return const Center(child: CircularProgressIndicator()); |
|
||||
} |
|
||||
|
|
||||
if (snapshot.hasError) { |
|
||||
return Center( |
|
||||
child: Text( |
|
||||
'${'getPermissionStatusFailed'.tr}: ${snapshot.error}')); // 获取权限状态失败 |
|
||||
} |
|
||||
|
|
||||
final permissionStatuses = snapshot.data ?? {}; |
|
||||
|
|
||||
return ListView( |
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h), |
|
||||
children: [ |
|
||||
// 通讯权限组- iOS平台没有通讯权限 |
|
||||
if (Platform.isAndroid) ...[ |
|
||||
_buildPermissionSection( |
|
||||
'communicationPermissions'.tr, // 通讯权限 |
|
||||
Icons.phone_android, |
|
||||
[Permission.phone, Permission.sms], |
|
||||
permissionStatuses, |
|
||||
isDarkMode), |
|
||||
SizedBox(height: 20.h), |
|
||||
], |
|
||||
// 闹钟权限组 |
|
||||
if (Platform.isAndroid) ...[ |
|
||||
_buildPermissionSection( |
|
||||
'alarmPermissions'.tr, // 闹钟权限 |
|
||||
Icons.alarm, |
|
||||
[Permission.scheduleExactAlarm], |
|
||||
permissionStatuses, |
|
||||
isDarkMode, |
|
||||
), |
|
||||
SizedBox(height: 20.h), |
|
||||
], |
|
||||
|
|
||||
// 日历权限组 |
|
||||
_buildPermissionSection( |
|
||||
'calendarPermissions'.tr, // 日历权限 |
|
||||
Icons.calendar_today, |
|
||||
[Permission.calendarFullAccess], |
|
||||
permissionStatuses, |
|
||||
isDarkMode), |
|
||||
|
|
||||
SizedBox(height: 20.h), |
|
||||
|
|
||||
// 位置权限组 |
|
||||
_buildPermissionSection( |
|
||||
'locationPermissions'.tr, // 位置权限 |
|
||||
Icons.location_on, |
|
||||
[Permission.location], |
|
||||
permissionStatuses, |
|
||||
isDarkMode), |
|
||||
], |
|
||||
); |
|
||||
}, |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
// 构建权限组区域 |
|
||||
Widget _buildPermissionSection( |
|
||||
String title, |
|
||||
IconData icon, |
|
||||
List<Permission> permissions, |
|
||||
Map<Permission, PermissionStatus> statuses, |
|
||||
bool isDarkMode) { |
|
||||
return Column( |
|
||||
crossAxisAlignment: CrossAxisAlignment.start, |
|
||||
children: [ |
|
||||
// 组标题 |
|
||||
Padding( |
|
||||
padding: EdgeInsets.only(left: 4.w, bottom: 8.h), |
|
||||
child: Text( |
|
||||
title.tr, |
|
||||
style: TextStyle( |
|
||||
fontSize: 12.sp, |
|
||||
fontWeight: FontWeight.w500, |
|
||||
color: isDarkMode ? Colors.blue[400] : Colors.blue[600], |
|
||||
letterSpacing: 1, |
|
||||
), |
|
||||
), |
|
||||
), |
|
||||
|
|
||||
// 权限项容器 |
|
||||
Container( |
|
||||
decoration: BoxDecoration( |
|
||||
color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white, |
|
||||
borderRadius: BorderRadius.circular(16.r), |
|
||||
boxShadow: [ |
|
||||
BoxShadow( |
|
||||
color: isDarkMode |
|
||||
? Colors.black.withOpacity(0.2) |
|
||||
: Colors.black.withOpacity(0.05), |
|
||||
blurRadius: 10, |
|
||||
offset: const Offset(0, 2), |
|
||||
), |
|
||||
], |
|
||||
), |
|
||||
child: ClipRRect( |
|
||||
borderRadius: BorderRadius.circular(16.r), |
|
||||
child: BackdropFilter( |
|
||||
filter: isDarkMode |
|
||||
? ImageFilter.blur(sigmaX: 5, sigmaY: 5) |
|
||||
: ImageFilter.blur(sigmaX: 0, sigmaY: 0), |
|
||||
child: Column( |
|
||||
children: |
|
||||
_buildPermissionItems(permissions, statuses, isDarkMode), |
|
||||
), |
|
||||
), |
|
||||
), |
|
||||
), |
|
||||
], |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
// 构建权限项列表 |
|
||||
List<Widget> _buildPermissionItems(List<Permission> permissions, |
|
||||
Map<Permission, PermissionStatus> statuses, bool isDarkMode) { |
|
||||
final List<Widget> items = []; |
|
||||
|
|
||||
// 获取名称 |
|
||||
String getName(Permission permission) { |
|
||||
switch (permission) { |
|
||||
case Permission.phone: |
|
||||
return 'phone'.tr; // 电话 |
|
||||
case Permission.sms: |
|
||||
return 'sms'.tr; // 短信 |
|
||||
case Permission.calendarWriteOnly: |
|
||||
return 'calendarWrite'.tr; // 日历写入 |
|
||||
case Permission.calendarFullAccess: |
|
||||
return 'calendarFullAccess'.tr; // 日历完整访问 |
|
||||
case Permission.location: |
|
||||
return 'locationInfo'.tr; // 位置信息 |
|
||||
case Permission.scheduleExactAlarm: |
|
||||
return 'alarm'.tr; // 闹钟 |
|
||||
default: |
|
||||
return permission.toString(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 获取描述文本 |
|
||||
String getDescription(Permission permission) { |
|
||||
switch (permission) { |
|
||||
case Permission.phone: |
|
||||
return 'phonePermissionDesc'.tr; // 用于拨打电话功能 |
|
||||
case Permission.sms: |
|
||||
return 'smsPermissionDesc'.tr; // 用于发送短信功能 |
|
||||
case Permission.calendarWriteOnly: |
|
||||
return 'calendarWritePermissionDesc'.tr; // 用于创建日历事件和提醒 |
|
||||
case Permission.calendarFullAccess: |
|
||||
return 'calendarFullAccessPermissionDesc'.tr; // 用于读取和管理日历事件及提醒 |
|
||||
case Permission.location: |
|
||||
return 'locationPermissionDesc'.tr; // 用于获取当前位置信息 |
|
||||
case Permission.scheduleExactAlarm: |
|
||||
return 'alarmPermissionDesc'.tr; // 设置精确闹钟需要此权限 |
|
||||
default: |
|
||||
return 'appFunctionNeeds'.tr; // 应用功能需要 |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
for (int i = 0; i < permissions.length; i++) { |
|
||||
final permission = permissions[i]; |
|
||||
final status = statuses[permission] ?? PermissionStatus.denied; |
|
||||
|
|
||||
items.add( |
|
||||
_buildPermissionItem( |
|
||||
name: getName(permission), |
|
||||
description: getDescription(permission), |
|
||||
status: status, |
|
||||
permission: permission, |
|
||||
isDarkMode: isDarkMode, |
|
||||
), |
|
||||
); |
|
||||
|
|
||||
// 添加分隔线,最后一个不加 |
|
||||
if (i < permissions.length - 1) { |
|
||||
items.add(Divider( |
|
||||
height: 1, |
|
||||
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200], |
|
||||
)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return items; |
|
||||
} |
|
||||
|
|
||||
// 构建单个权限项 |
|
||||
Widget _buildPermissionItem({ |
|
||||
required String name, |
|
||||
required String description, |
|
||||
required PermissionStatus status, |
|
||||
required Permission permission, |
|
||||
required bool isDarkMode, |
|
||||
}) { |
|
||||
return Padding( |
|
||||
padding: EdgeInsets.all(16.w), |
|
||||
child: Row( |
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
||||
children: [ |
|
||||
Expanded( |
|
||||
child: Column( |
|
||||
crossAxisAlignment: CrossAxisAlignment.start, |
|
||||
children: [ |
|
||||
Text( |
|
||||
name.tr, |
|
||||
style: TextStyle( |
|
||||
fontSize: 16.sp, |
|
||||
fontWeight: FontWeight.w500, |
|
||||
color: isDarkMode ? Colors.white : Colors.black87, |
|
||||
), |
|
||||
), |
|
||||
SizedBox(height: 4.h), |
|
||||
Text( |
|
||||
description.tr, |
|
||||
style: TextStyle( |
|
||||
fontSize: 12.sp, |
|
||||
color: isDarkMode ? Colors.white70 : Colors.grey[600], |
|
||||
), |
|
||||
), |
|
||||
SizedBox(height: 4.h), |
|
||||
_buildStatusText(status, isDarkMode), |
|
||||
], |
|
||||
), |
|
||||
), |
|
||||
Switch( |
|
||||
value: status.isGranted, |
|
||||
onChanged: (value) { |
|
||||
if (value) { |
|
||||
_handlePermissionAction(permission, status); |
|
||||
} else if (status.isGranted) { |
|
||||
controller.openSettings(); |
|
||||
} |
|
||||
}, |
|
||||
activeColor: Colors.blue[600], |
|
||||
), |
|
||||
], |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
// 状态文本 |
|
||||
Widget _buildStatusText(PermissionStatus status, bool isDarkMode) { |
|
||||
String text; |
|
||||
Color color; |
|
||||
|
|
||||
if (status.isGranted) { |
|
||||
text = 'authorized'.tr; // 已授权 |
|
||||
color = Colors.green; |
|
||||
} else if (status.isDenied) { |
|
||||
text = 'unauthorized'.tr; // 未授权 |
|
||||
color = Colors.red; |
|
||||
} else if (status.isPermanentlyDenied) { |
|
||||
text = 'needOpenInSystemSettings'.tr; // 需要在系统设置中开启 |
|
||||
color = Colors.orange; |
|
||||
} else if (status.isLimited) { |
|
||||
text = 'partialAuthorization'.tr; // 部分授权 |
|
||||
color = Colors.orange; |
|
||||
} else { |
|
||||
text = 'unknownStatus'.tr; // 未知状态 |
|
||||
color = Colors.grey; |
|
||||
} |
|
||||
|
|
||||
return Text( |
|
||||
text, |
|
||||
style: TextStyle( |
|
||||
color: color, |
|
||||
fontSize: 12.sp, |
|
||||
fontWeight: FontWeight.w500, |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
// 处理权限请求 |
|
||||
Future<void> _handlePermissionAction( |
|
||||
Permission permission, PermissionStatus status) async { |
|
||||
try { |
|
||||
// final context = Get.context; |
|
||||
// if (context == null) return; |
|
||||
|
|
||||
final permissionName = _getPermissionName(permission); |
|
||||
final explanationText = getDetailedDescription(permission); |
|
||||
|
|
||||
// 使用 PermissionUtil 请求权限 |
|
||||
final hasPermission = await PermissionUtil.instance.requestPermission( |
|
||||
// context: context, |
|
||||
permissionType: permission, |
|
||||
permissionName: permissionName, |
|
||||
explanationText: explanationText, |
|
||||
permanentDenialText: 'permanentDenialText'.tr.replaceAll( |
|
||||
'{permission}', permissionName), // 您已永久拒绝{permission}权限,请前往应用设置开启 |
|
||||
settingsButtonText: 'goToSettings'.tr, // 去设置 |
|
||||
cancelButtonText: 'cancel'.tr, // 取消 |
|
||||
); |
|
||||
|
|
||||
if (hasPermission) { |
|
||||
Get.snackbar( |
|
||||
'success'.tr, // 成功 |
|
||||
'permissionGranted'.tr, // 权限已授予 |
|
||||
snackPosition: SnackPosition.BOTTOM, |
|
||||
backgroundColor: Colors.green, |
|
||||
colorText: Colors.white, |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
// 刷新界面,重新获取权限状态 |
|
||||
Get.forceAppUpdate(); |
|
||||
} catch (e) { |
|
||||
Get.snackbar( |
|
||||
'error'.tr, // 错误 |
|
||||
'permissionRequestError'.tr, // 请求权限时出错 |
|
||||
snackPosition: SnackPosition.BOTTOM, |
|
||||
backgroundColor: Colors.red, |
|
||||
colorText: Colors.white, |
|
||||
); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 获取权限的用户友好名称 |
|
||||
String _getPermissionName(Permission permission) { |
|
||||
switch (permission) { |
|
||||
case Permission.phone: |
|
||||
return 'phone'.tr; // 电话 |
|
||||
case Permission.sms: |
|
||||
return 'sms'.tr; // 短信 |
|
||||
case Permission.calendarWriteOnly: |
|
||||
return 'calendarWrite'.tr; // 日历写入 |
|
||||
case Permission.calendarFullAccess: |
|
||||
return 'calendarFullAccess'.tr; // 日历完整访问 |
|
||||
case Permission.location: |
|
||||
return 'locationInfo'.tr; // 位置信息 |
|
||||
case Permission.scheduleExactAlarm: |
|
||||
return 'alarm'.tr; // 闹钟 |
|
||||
default: |
|
||||
return permission.toString(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 获取权限说明文本 |
|
||||
String getDetailedDescription(Permission permission) { |
|
||||
switch (permission) { |
|
||||
case Permission.phone: |
|
||||
return 'phonePermissionDetailDesc'.tr; // 拨打电话功能需要电话权限 |
|
||||
case Permission.sms: |
|
||||
return 'smsPermissionDetailDesc'.tr; // 发送短信功能需要短信权限 |
|
||||
case Permission.calendarWriteOnly: |
|
||||
return 'calendarWritePermissionDetailDesc'.tr; // 创建日历事件需要日历写入权限 |
|
||||
case Permission.calendarFullAccess: |
|
||||
return 'calendarFullAccessPermissionDetailDesc'.tr; // 管理日历事件需要完整日历权限 |
|
||||
case Permission.location: |
|
||||
return 'locationPermissionDetailDesc'.tr; // 获取位置信息需要位置权限 |
|
||||
case Permission.scheduleExactAlarm: |
|
||||
return 'alarmPermissionDetailDesc'.tr; // 设置精确闹钟需要此权限 |
|
||||
default: |
|
||||
return 'appNeedsPermissionForFullFunction'.tr; // 应用需要此权限以提供完整功能 |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue