Browse Source

Merge branch 'new_dev' of https://github.com/deepcloud2048/deep_voice into new_dev

newdev_shunjiawei
fdp 1 year ago
parent
commit
ff59b4136c
  1. 89
      lib/data/services/ota_check_service.dart
  2. 13
      lib/modules/agent/controllers/agent_controller.dart
  3. 172
      lib/modules/translation/views/dialogs/delete_confirm_dialog.dart
  4. 187
      lib/modules/translation/views/dialogs/translation_long_press_menu.dart
  5. 257
      lib/modules/translation/views/translation_view.dart
  6. 14
      local_plugins/location_service/android/src/main/kotlin/com/yunqiinnovation/location_service/LocationService.kt

89
lib/data/services/ota_check_service.dart

@ -9,49 +9,50 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
/// 负责管理全局OTA检查状态,确保在应用生命周期内只检查一次
class OtaCheckService extends GetxService {
static const String _tag = 'OtaCheckService';
// 全局状态管理
static bool _hasCheckedInCurrentSession = false;
static bool _isCheckingInProgress = false;
final _otaCoreService = OtaCoreService();
/// 获取服务实例
static OtaCheckService get to => Get.find<OtaCheckService>();
@override
void onInit() {
super.onInit();
Logger.d(_tag, 'OTA检查服务已初始化');
}
/// 重置检查状态(仅在应用重启时调用)
static void resetCheckStatus() {
_hasCheckedInCurrentSession = false;
_isCheckingInProgress = false;
Logger.d(_tag, 'OTA检查状态已重置');
}
/// 检查是否应该进行OTA检查
bool shouldCheckOta() {
return !_hasCheckedInCurrentSession && !_isCheckingInProgress;
}
/// 标记为已检查
void _markAsChecked() {
_hasCheckedInCurrentSession = true;
_isCheckingInProgress = false;
Logger.d(_tag, 'OTA检查状态已标记为完成');
}
/// 检查当前是否在Home页面
bool _isCurrentlyOnHomePage() {
final currentRoute = Get.currentRoute;
final isOnHome = currentRoute == Routes.home || currentRoute == Routes.initial;
final isOnHome =
currentRoute == Routes.home || currentRoute == Routes.initial;
Logger.d(_tag, '当前路由: $currentRoute, 是否在Home页面: $isOnHome');
return isOnHome;
}
/// 执行OTA升级检查
/// [isFullyConnected] 设备是否完全连接
/// 返回是否成功执行了检查
@ -62,53 +63,54 @@ class OtaCheckService extends GetxService {
Logger.d(_tag, '跳过OTA检查 - 已检查过或正在检查中');
return false;
}
// 检查设备连接状态
if (!isFullyConnected) {
Logger.d(_tag, '设备未完全连接,跳过OTA检查');
return false;
}
// 检查当前页面
if (!_isCurrentlyOnHomePage()) {
Logger.d(_tag, '当前不在Home页面,跳过OTA检查');
return false;
}
// 标记为检查中
_isCheckingInProgress = true;
Logger.d(_tag, '开始执行OTA固件升级检查...');
// 获取当前版本信息
final currentInfo = await _otaCoreService.getCurrentVersionInfo();
final currentVersion = currentInfo['currentVersion'] as String;
// 获取最新版本信息
final latestInfo = await _otaCoreService.getLatestVersionInfo();
final latestVersion = latestInfo['latestVersion'] as String;
Logger.d(_tag, '当前版本: $currentVersion, 最新版本: $latestVersion');
// 检查是否有更新
final hasUpdate = _otaCoreService.isNewVersionAvailable(currentVersion, latestVersion);
final hasUpdate =
_otaCoreService.isNewVersionAvailable(currentVersion, latestVersion);
if (hasUpdate) {
Logger.d(_tag, '发现新版本,准备显示升级提醒');
// 再次确认当前在Home页面(防止异步执行期间页面切换)
if (_isCurrentlyOnHomePage()) {
_showOtaUpgradeDialog(latestVersion, latestInfo['updateDescription'] as String?);
_showOtaUpgradeDialog(
latestVersion, latestInfo['updateDescription'] as String?);
} else {
Logger.d(_tag, '检查完成时已不在Home页面,取消显示弹窗');
}
} else {
Logger.d(_tag, '当前已是最新版本');
}
// 标记为已检查(无论是否有更新都标记为已检查)
_markAsChecked();
return true;
} catch (e) {
Logger.e(_tag, '检查OTA升级失败: $e');
// 即使检查失败,也标记为已检查,避免重复尝试
@ -116,7 +118,7 @@ class OtaCheckService extends GetxService {
return false;
}
}
/// 显示OTA升级提醒对话框
/// [latestVersion] 最新版本号
/// [updateDescription] 更新描述
@ -126,24 +128,32 @@ class OtaCheckService extends GetxService {
Logger.d(_tag, '显示弹窗时发现不在Home页面,取消显示');
return;
}
final isDarkMode = Get.isDarkMode;
Logger.d(_tag, '显示OTA升级提醒对话框');
Get.dialog(
AlertDialog(
title: Row(
children: [
Icon(
Icons.headset,
color: Colors.blue[600],
color: isDarkMode ? const Color(0xFF0066CC) : Colors.blue[600],
size: 24.sp,
),
SizedBox(width: 8.w),
Text(
'ota_newVersionFound'.tr,
style: TextStyle(
color: Colors.blue[700],
fontWeight: FontWeight.w600,
// 使用Flexible确保标题文本能够自适应不同语言长度,避免溢出
Flexible(
child: Text(
'ota_newVersionFound'.tr, // 发现新版本
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.blue[700],
fontWeight: FontWeight.w600,
fontSize: 20.sp, // 设置合适的字体大小
),
softWrap: true, // 启用软换行
overflow: TextOverflow.visible, // 确保文本完全显示
maxLines: 2, // 最多显示两行
),
),
],
@ -155,6 +165,7 @@ class OtaCheckService extends GetxService {
Text(
'${'latestFirmwareVersion'.tr}: $latestVersion',
style: TextStyle(
color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
fontWeight: FontWeight.w500,
fontSize: 16.sp,
),
@ -173,7 +184,9 @@ class OtaCheckService extends GetxService {
},
child: Text(
'talkLater'.tr,
style: TextStyle(color: Colors.grey[600]),
style: TextStyle(
color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
),
),
),
// 立即升级 (靠右)
@ -184,11 +197,15 @@ class OtaCheckService extends GetxService {
Get.toNamed(Routes.OTA_UPGRADE);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue[600],
backgroundColor:
isDarkMode ? const Color(0xFF0066CC) : Colors.blue[600],
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.sp),
),
side: isDarkMode
? BorderSide(color: Colors.grey[800]!, width: 1)
: BorderSide.none,
),
child: Text(
'ota_updateNow'.tr,
@ -201,12 +218,12 @@ class OtaCheckService extends GetxService {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.sp),
),
backgroundColor: Colors.white,
backgroundColor: isDarkMode ? const Color(0xFF1A1A1A) : Colors.white,
),
barrierDismissible: true, // 允许点击外部关闭
);
}
/// 获取当前检查状态(用于调试)
Map<String, dynamic> getCheckStatus() {
return {

13
lib/modules/agent/controllers/agent_controller.dart

@ -706,7 +706,7 @@ class AgentController extends GetxController with WidgetsBindingObserver {
// messages.refresh();
}
Get.snackbar('error'.tr, '${event.data['message']}');
// Get.snackbar('error'.tr, '${event.data['message']}');
Logger.e(TAG, '代理服务错误: ${event.data['message']}');
break;
@ -2084,12 +2084,13 @@ class AgentController extends GetxController with WidgetsBindingObserver {
return;
}
}
// 5. 最后尝试内置高德导航
_navigationManager.open(start, "$endlongitude,$endlatitude", mode);
// 5. 如果都没有安装,提示用户
print('未找到可用的导航应用');
final availableApps =
Platform.isIOS ? '百度地图、高德地图、谷歌地图或苹果地图' : '百度地图、高德地图或谷歌地图';
Get.snackbar('提示', '未找到可用的导航应用,请安装$availableApps');
// print('未找到可用的导航应用');
// final availableApps =
// Platform.isIOS ? '百度地图、高德地图、谷歌地图或苹果地图' : '百度地图、高德地图或谷歌地图';
// Get.snackbar('提示', '未找到可用的导航应用,请安装$availableApps');
} catch (e) {
print('自动选择导航失败: $e');
Get.snackbar('错误', '启动导航失败');

172
lib/modules/translation/views/dialogs/delete_confirm_dialog.dart

@ -0,0 +1,172 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../../../core/theme/app_colors.dart';
import '../../models/translation_models.dart';
/// 删除确认对话框
/// 提供翻译记录的删除确认功能
class DeleteConfirmDialog {
/// 显示删除单条翻译记录确认对话框
static void showDeleteItemDialog({
required TranslationItem item,
required Function() onConfirm,
}) {
final isDarkMode = Theme.of(Get.context!).brightness == Brightness.dark;
Get.dialog(
AlertDialog(
backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white,
title: Text(
'deleteTranslationRecord'.tr, // 删除翻译记录
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.white : Colors.black,
),
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'deleteTranslationConfirm'.tr, // 确定要删除这条翻译记录吗?此操作无法撤销。
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode ? Colors.grey[300] : Colors.black87,
),
),
SizedBox(height: 12.h),
// 显示要删除的记录预览
Container(
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: isDarkMode
? Colors.grey[800]?.withOpacity(0.5)
: Colors.grey[100],
borderRadius: BorderRadius.circular(8.r),
border: Border.all(
color: isDarkMode ? Colors.grey[700]! : Colors.grey[300]!,
width: 1,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.sourceText,
style: TextStyle(
fontSize: 14.sp,
color: isDarkMode ? Colors.white : Colors.black,
fontWeight: FontWeight.w500,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
if (item.translatedText.isNotEmpty) ...[
SizedBox(height: 4.h),
Text(
item.translatedText,
style: TextStyle(
fontSize: 14.sp,
color: isDarkMode ? Colors.grey[300] : Colors.grey[700],
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
],
),
),
],
),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'cancel'.tr,
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[700],
),
),
),
TextButton(
onPressed: () {
Get.back();
onConfirm();
},
child: Text(
'confirm'.tr,
style: TextStyle(
fontSize: 16.sp,
color: Colors.red,
fontWeight: FontWeight.bold,
),
),
),
],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.r),
),
),
);
}
/// 显示清除所有历史记录确认对话框
static void showClearHistoryDialog({
required Function() onConfirm,
}) {
final isDarkMode = Get.isDarkMode;
Get.dialog(
AlertDialog(
backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white,
title: Text(
'clearHistory'.tr, // 清除历史记录
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.white : Colors.black,
),
),
content: Text(
'clearHistoryConfirm'.tr, // 确定要清除所有翻译历史记录吗?此操作无法撤销。
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode ? Colors.grey[300] : Colors.black87,
),
),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'cancel'.tr,
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[700],
),
),
),
TextButton(
onPressed: () {
Get.back();
onConfirm();
},
child: Text(
'confirm'.tr,
style: TextStyle(
fontSize: 16.sp,
color: Colors.red,
fontWeight: FontWeight.bold,
),
),
),
],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.r),
),
),
);
}
}

187
lib/modules/translation/views/dialogs/translation_long_press_menu.dart

@ -0,0 +1,187 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:haptic_feedback/haptic_feedback.dart';
import '../../../../core/theme/app_colors.dart';
import '../../models/translation_models.dart';
/// 翻译长按菜单对话框
/// 负责处理翻译条目的长按菜单显示和交互
class TranslationLongPressMenu {
/// 显示翻译长按菜单
static void show({
required BuildContext context,
required bool isDarkMode,
required LongPressStartDetails details,
required TranslationItem item,
required Function(TranslationItem) onCopy,
required Function(TranslationItem) onDeleteItem,
required Function() onClearHistory,
}) {
// 只对完成态记录显示长按菜单
if (item.isIntermediate) return;
// 触发触觉反馈
Haptics.vibrate(HapticsType.success);
// 计算弹出菜单位置
RenderBox? renderBox =
Overlay.of(context).context.findRenderObject() as RenderBox;
final RelativeRect position = RelativeRect.fromRect(
Rect.fromLTRB(
details.globalPosition.dx,
details.globalPosition.dy,
details.globalPosition.dx + 110, // 菜单显示位置X轴坐标
details.globalPosition.dy - 40, // 菜单显示位置Y轴坐标
),
Offset.zero & renderBox.size,
);
// 显示弹出菜单
showMenu(
context: context,
position: position,
color: isDarkMode ? AppColors.cardBackground : Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.r),
),
items: _buildMenuItems(
context: context,
isDarkMode: isDarkMode,
item: item,
onCopy: onCopy,
onDeleteItem: onDeleteItem,
onClearHistory: onClearHistory,
),
);
}
/// 构建菜单项
static List<PopupMenuEntry> _buildMenuItems({
required BuildContext context,
required bool isDarkMode,
required TranslationItem item,
required Function(TranslationItem) onCopy,
required Function(TranslationItem) onDeleteItem,
required Function() onClearHistory,
}) {
return [
// 复制选项
_buildPopupMenuItem(
Icon(
Icons.copy,
size: 20.w,
color: isDarkMode ? Colors.white : Colors.black87,
),
'copy'.tr, // 复制
isDarkMode ? Colors.white : Colors.black87,
() => onCopy(item),
),
// 分隔线
PopupMenuItem(
height: 1,
enabled: false,
child: Divider(
height: 1,
thickness: 0.8,
indent: 0,
endIndent: 0,
color: isDarkMode ? Colors.grey[700] : Colors.grey[300],
),
),
// 删除该条记录选项
_buildPopupMenuItem(
Icon(
Icons.delete_outline,
size: 20.w,
color: isDarkMode ? Colors.orange[300] : Colors.orange,
),
'delete'.tr, // 删除
isDarkMode ? Colors.orange[300]! : Colors.orange,
() => onDeleteItem(item),
),
// 分隔线
PopupMenuItem(
height: 1,
enabled: false,
child: Divider(
height: 1,
thickness: 0.8,
indent: 0,
endIndent: 0,
color: isDarkMode ? Colors.grey[700] : Colors.grey[300],
),
),
// 删除所有记录选项
_buildPopupMenuItem(
Icon(
Icons.delete_sweep,
size: 20.w,
color: Colors.red,
),
'clearHistory'.tr, // 清除历史记录
Colors.red,
onClearHistory,
),
];
}
/// 构建弹出菜单项
static PopupMenuEntry _buildPopupMenuItem(
Icon icon,
String title,
Color color,
Function() onTap,
) {
return PopupMenuItem(
onTap: onTap,
child: SizedBox(
width: 150.w,
child: Row(
children: [
icon,
8.horizontalSpace,
Text(
title,
style: TextStyle(
color: color,
fontSize: 14.sp,
),
),
],
),
),
);
}
/// 复制翻译条目内容
/// 将原文和翻译文本复制到剪贴板
static void copyTranslationItem(TranslationItem item) {
// 构建复制文本:原文 + 翻译
String copyText = item.sourceText;
if (item.translatedText.isNotEmpty) {
copyText += '\n${item.translatedText}';
}
Clipboard.setData(ClipboardData(text: copyText)).then((_) {
Get.snackbar(
'success'.tr,
'copySuccess'.tr, // 复制成功
backgroundColor: Colors.blue.withOpacity(0.8),
colorText: Colors.white,
snackPosition: SnackPosition.BOTTOM,
duration: const Duration(milliseconds: 1200),
icon: Icon(
Icons.check_circle_outline,
color: Colors.white,
size: 24.sp,
),
);
});
}
}

257
lib/modules/translation/views/translation_view.dart

@ -2,8 +2,10 @@ import 'dart:ui';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:haptic_feedback/haptic_feedback.dart';
import '../controllers/translation_controller.dart';
import '../models/translation_models.dart';
import '../views/translation_history_view.dart';
@ -16,6 +18,7 @@ import 'widgets/face_to_face_layout.dart'; // 面对面翻译布局
import 'widgets/draggable_floating_button.dart'; // 可拖拽的悬浮按钮
import 'dialogs/language_selection_dialog.dart'; // 语言选择对话框
import 'dialogs/translation_mode_selector.dart'; // 翻译模式选择器
import 'dialogs/translation_long_press_menu.dart'; // 长按菜单
// import 'package:intl/intl.dart';
@ -414,103 +417,113 @@ class TranslationView extends GetView<TranslationController> {
Widget _buildTranslationItemWidget(
BuildContext context, TranslationItem item) {
return Container(
margin: const EdgeInsets.only(bottom: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: item.isIntermediate
? Colors.grey.withOpacity(0.1) // 中间结果使用浅灰色底色
: (item.sourceLanguageCode == controller.sourceLanguageCode.value
? Theme.of(context)
.colorScheme
.primary
.withOpacity(0.08) // 源语言匹配时使用主题色底色
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(0.08)), // 否则使用次要色底色
borderRadius: BorderRadius.circular(12),
border: Border.all(
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return GestureDetector(
onLongPressStart: (details) => _onLongPressTranslationItem(
context,
isDarkMode,
details,
item,
),
child: Container(
margin: const EdgeInsets.only(bottom: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: item.isIntermediate
? Colors.grey.withOpacity(0.2)
: Colors.transparent,
width: 1,
? Colors.grey.withOpacity(0.1) // 中间结果使用浅灰色底色
: (item.sourceLanguageCode == controller.sourceLanguageCode.value
? Theme.of(context)
.colorScheme
.primary
.withOpacity(0.08) // 源语言匹配时使用主题色底色
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(0.08)), // 否则使用次要色底色
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: item.isIntermediate
? Colors.grey.withOpacity(0.2)
: Colors.transparent,
width: 1,
),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 源文本和删除按钮行
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 源文本
Expanded(
child: Text(
item.sourceText,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).textTheme.bodyLarge?.color,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 源文本和删除按钮行
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 源文本
Expanded(
child: Text(
item.sourceText,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).textTheme.bodyLarge?.color,
),
),
),
),
// 删除按钮 - 只对完成态记录显示,与源文本平齐
if (!item.isIntermediate)
GestureDetector(
onTap: () => _showDeleteItemConfirmDialog(item),
child: Container(
padding: EdgeInsets.all(4.w),
child: Icon(
Icons.delete_outline,
size: 18.sp,
color: Colors.grey[500],
// 删除按钮 - 只对完成态记录显示,与源文本平齐
if (!item.isIntermediate)
GestureDetector(
onTap: () => _showDeleteItemConfirmDialog(item),
child: Container(
padding: EdgeInsets.all(4.w),
child: Icon(
Icons.delete_outline,
size: 18.sp,
color: Colors.grey[500],
),
),
),
),
],
),
if (item.translatedText.isNotEmpty) ...[
const SizedBox(height: 8),
// 翻译文本
Text(
item.translatedText,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).textTheme.bodyMedium?.color,
fontWeight: FontWeight.w500,
),
],
),
],
// 语言信息和时间戳
const SizedBox(height: 4),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
'${item.sourceLanguageName.tr} → ${item.targetLanguageName.tr}',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).textTheme.bodySmall?.color,
),
if (item.translatedText.isNotEmpty) ...[
const SizedBox(height: 8),
// 翻译文本
Text(
item.translatedText,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).textTheme.bodyMedium?.color,
fontWeight: FontWeight.w500,
),
),
// 播放按钮
if (!item.isIntermediate)
GestureDetector(
onTap: () => controller.playTranslationItem(item),
child: Container(
padding: EdgeInsets.all(4.w),
child: Icon(
Icons.volume_up,
size: 20.sp,
color: Theme.of(context).colorScheme.primary,
],
// 语言信息和时间戳
const SizedBox(height: 4),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
'${item.sourceLanguageName.tr} → ${item.targetLanguageName.tr}',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).textTheme.bodySmall?.color,
),
),
),
],
),
],
// 播放按钮
if (!item.isIntermediate)
GestureDetector(
onTap: () => controller.playTranslationItem(item),
child: Container(
padding: EdgeInsets.all(4.w),
child: Icon(
Icons.volume_up,
size: 20.sp,
color: Theme.of(context).colorScheme.primary,
),
),
),
],
),
],
),
),
);
}
@ -874,6 +887,24 @@ class TranslationView extends GetView<TranslationController> {
});
}
/// 处理翻译条目长按事件
void _onLongPressTranslationItem(
BuildContext context,
bool isDarkMode,
LongPressStartDetails details,
TranslationItem item,
) {
TranslationLongPressMenu.show(
context: context,
isDarkMode: isDarkMode,
details: details,
item: item,
onCopy: (item) => TranslationLongPressMenu.copyTranslationItem(item),
onDeleteItem: (item) => _deleteTranslationItem(item),
onClearHistory: _showClearHistoryConfirmDialog,
);
}
// 显示删除单条记录确认对话框
void _showDeleteItemConfirmDialog(TranslationItem item) {
final isDarkMode = Theme.of(Get.context!).brightness == Brightness.dark;
@ -1006,6 +1037,62 @@ class TranslationView extends GetView<TranslationController> {
}
}
// 显示删除所有记录确认对话框
void _showClearHistoryConfirmDialog() {
final isDarkMode = Get.isDarkMode;
Get.dialog(
AlertDialog(
backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white,
title: Text(
'clearHistory'.tr,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.white : Colors.black,
),
),
content: Text(
'clearHistoryConfirm'.tr,
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode ? Colors.grey[300] : Colors.black87,
),
),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'cancel'.tr,
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[700],
),
),
),
TextButton(
onPressed: () {
// 清除历史记录
controller.clearTranslationHistory();
Get.back();
},
child: Text(
'confirm'.tr,
style: TextStyle(
fontSize: 16.sp,
color: Colors.red,
fontWeight: FontWeight.bold,
),
),
),
],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.r),
),
),
);
}
// 构建语言选择栏
Widget _buildLanguageSelectionBar(bool isDarkMode) {
return Container(

14
local_plugins/location_service/android/src/main/kotlin/com/yunqiinnovation/location_service/LocationService.kt

@ -270,13 +270,19 @@ object LocationService {
if (!hasForegroundPermission) {
return 1 // 前台权限未授予
}
// 前台权限已授予,再根据前后台状态检查后台权限
if (!isAppInForeground(context)) {
// 应用在后台:Android 10+ 需要检查后台权限
return 2 // 后台权限未授予
// 应用在后台:Android 10+ 需要检查后台权限的实际授予状态
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val hasBackgroundPermission = hasBackgroundLocationPermission(context)
if (!hasBackgroundPermission) {
return 2 // 后台权限未授予
}
}
// Android 9 及以下或已授予后台权限
}
// 所有所需权限均已授予
return 0
}

Loading…
Cancel
Save