Browse Source
- 新增 PermissionUtil 工具类,用于检查和请求权限 - 修改 AgentController,引入 PermissionUtil - 调整 MessageBubble 布局,优化 AI 消息显示newdev_shunjiawei
3 changed files with 136 additions and 2 deletions
@ -0,0 +1,134 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:permission_handler/permission_handler.dart'; |
||||
|
import 'package:app_settings/app_settings.dart'; |
||||
|
|
||||
|
class PermissionUtil { |
||||
|
/// 检查并请求多个权限 |
||||
|
/// |
||||
|
/// [permissions] 要检查的权限列表,如 [Permission.microphone, Permission.location] |
||||
|
/// [rationaleTitle] 弹窗标题 |
||||
|
/// [rationaleMessage] 权限用途说明内容(支持多行) |
||||
|
/// |
||||
|
/// 返回是否所有权限都已被授予 |
||||
|
static Future<bool> checkAndRequestPermissions({ |
||||
|
required List<Permission> permissions, |
||||
|
required String rationaleTitle, |
||||
|
required List<String> rationaleMessage, |
||||
|
}) async { |
||||
|
try { |
||||
|
Map<Permission, PermissionStatus> statuses = {}; |
||||
|
|
||||
|
// 检查是否都已授权 |
||||
|
bool allGranted = true; |
||||
|
for (var permission in permissions) { |
||||
|
final status = await permission.status; |
||||
|
if (!status.isGranted) { |
||||
|
allGranted = false; |
||||
|
statuses[permission] = status; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (allGranted) return true; |
||||
|
|
||||
|
// 判断是否包含永久拒绝 |
||||
|
bool hasPermanentDenied = |
||||
|
statuses.values.any((status) => status.isPermanentlyDenied); |
||||
|
|
||||
|
// 显示提示弹窗 |
||||
|
_showPermissionDialog( |
||||
|
isPermanent: hasPermanentDenied, |
||||
|
title: rationaleTitle, |
||||
|
messages: rationaleMessage, |
||||
|
onConfirm: () async { |
||||
|
if (hasPermanentDenied) { |
||||
|
AppSettings.openAppSettings(); |
||||
|
} else { |
||||
|
final newStatuses = await permissions.request(); |
||||
|
final allGrantedNow = |
||||
|
newStatuses.values.every((status) => status.isGranted); |
||||
|
if (!allGrantedNow) { |
||||
|
print("部分权限被拒绝: $newStatuses"); |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
return false; |
||||
|
} catch (e) { |
||||
|
print("权限检查异常: $e"); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 权限说明弹窗 |
||||
|
static void _showPermissionDialog({ |
||||
|
required bool isPermanent, |
||||
|
required String title, |
||||
|
required List<String> messages, |
||||
|
required VoidCallback onConfirm, |
||||
|
}) { |
||||
|
Get.generalDialog( |
||||
|
barrierDismissible: false, |
||||
|
barrierLabel: '权限提示', |
||||
|
transitionBuilder: (context, anim1, anim2, child) { |
||||
|
return SlideTransition( |
||||
|
position: Tween<Offset>( |
||||
|
begin: Offset(0, -1), |
||||
|
end: Offset(0, 0), |
||||
|
).animate(CurvedAnimation(parent: anim1, curve: Curves.easeOut)), |
||||
|
child: child, |
||||
|
); |
||||
|
}, |
||||
|
pageBuilder: (context, anim1, anim2) { |
||||
|
return SafeArea( |
||||
|
child: Align( |
||||
|
alignment: Alignment.topCenter, |
||||
|
child: Padding( |
||||
|
padding: const EdgeInsets.only(top: 80, left: 24, right: 24), |
||||
|
child: Material( |
||||
|
borderRadius: BorderRadius.circular(12), |
||||
|
color: Colors.white, |
||||
|
child: Padding( |
||||
|
padding: const EdgeInsets.all(16), |
||||
|
child: Column( |
||||
|
mainAxisSize: MainAxisSize.min, |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Text(title, |
||||
|
style: TextStyle( |
||||
|
fontSize: 18, fontWeight: FontWeight.bold)), |
||||
|
const SizedBox(height: 12), |
||||
|
...messages.map((msg) => Padding( |
||||
|
padding: const EdgeInsets.only(bottom: 8), |
||||
|
child: Text("• $msg"), |
||||
|
)), |
||||
|
const SizedBox(height: 20), |
||||
|
Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.end, |
||||
|
children: [ |
||||
|
TextButton( |
||||
|
onPressed: () => Get.back(), |
||||
|
child: const Text('取消'), |
||||
|
), |
||||
|
const SizedBox(width: 8), |
||||
|
TextButton( |
||||
|
onPressed: () { |
||||
|
Get.back(); |
||||
|
onConfirm(); |
||||
|
}, |
||||
|
child: Text(isPermanent ? '前往设置' : '授权'), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue