鸿蒙端提交
This commit is contained in:
@@ -114,16 +114,8 @@ enum AppPermission {
|
||||
CupertinoIcons.antenna_radiowaves_left_right,
|
||||
Color(0xFF64D2FF),
|
||||
),
|
||||
microphone(
|
||||
Permission.microphone,
|
||||
CupertinoIcons.mic_fill,
|
||||
Color(0xFFFF3B30),
|
||||
),
|
||||
storage(
|
||||
Permission.storage,
|
||||
CupertinoIcons.folder_fill,
|
||||
Color(0xFFFF9500),
|
||||
),
|
||||
microphone(Permission.microphone, CupertinoIcons.mic_fill, Color(0xFFFF3B30)),
|
||||
storage(Permission.storage, CupertinoIcons.folder_fill, Color(0xFFFF9500)),
|
||||
network(
|
||||
Permission.notification,
|
||||
CupertinoIcons.wifi,
|
||||
@@ -537,37 +529,24 @@ class PermissionService {
|
||||
}
|
||||
|
||||
/// 快捷方法: 请求相机权限
|
||||
static Future<bool> requestCamera(BuildContext context) => requestPermission(
|
||||
context,
|
||||
AppPermission.camera,
|
||||
);
|
||||
static Future<bool> requestCamera(BuildContext context) =>
|
||||
requestPermission(context, AppPermission.camera);
|
||||
|
||||
/// 快捷方法: 请求相册权限
|
||||
static Future<bool> requestPhotos(BuildContext context) => requestPermission(
|
||||
context,
|
||||
AppPermission.photos,
|
||||
);
|
||||
static Future<bool> requestPhotos(BuildContext context) =>
|
||||
requestPermission(context, AppPermission.photos);
|
||||
|
||||
/// 快捷方法: 请求通知权限
|
||||
static Future<bool> requestNotification(BuildContext context) =>
|
||||
requestPermission(
|
||||
context,
|
||||
AppPermission.notification,
|
||||
);
|
||||
requestPermission(context, AppPermission.notification);
|
||||
|
||||
/// 快捷方法: 请求位置权限
|
||||
static Future<bool> requestLocation(BuildContext context) =>
|
||||
requestPermission(
|
||||
context,
|
||||
AppPermission.location,
|
||||
);
|
||||
requestPermission(context, AppPermission.location);
|
||||
|
||||
/// 快捷方法: 请求麦克风权限
|
||||
static Future<bool> requestMicrophone(BuildContext context) =>
|
||||
requestPermission(
|
||||
context,
|
||||
AppPermission.microphone,
|
||||
);
|
||||
requestPermission(context, AppPermission.microphone);
|
||||
|
||||
/// 打开系统设置
|
||||
static Future<bool> openSettings() => openAppSettings();
|
||||
@@ -584,7 +563,8 @@ class PermissionService {
|
||||
static Future<bool> requestTrackingPermission() async {
|
||||
if (!Platform.isIOS) return true;
|
||||
try {
|
||||
final status = await AppTrackingTransparency.requestTrackingAuthorization();
|
||||
final status =
|
||||
await AppTrackingTransparency.requestTrackingAuthorization();
|
||||
_log.i('ATT授权状态: $status');
|
||||
return status == TrackingStatus.authorized;
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// ============================================================
|
||||
// 闲言APP — NearbyService适配器
|
||||
// 创建时间: 2026-05-13
|
||||
// 更新时间: 2026-06-05
|
||||
// 更新时间: 2026-06-06
|
||||
// 作用: 封装nearby_service + nearby_connections三方库,适配项目传输体系
|
||||
// nearby_service: Android Wi-Fi Direct | iOS/macOS MultipeerConnectivity | 鸿蒙
|
||||
// nearby_connections: Google Nearby Connections(蓝牙发现+Wi-Fi Direct传输, 仅Android/iOS)
|
||||
// 上次更新: 集成nearby_connections实现P2P近场设备发现与文件传输
|
||||
// 上次更新: 跨平台兼容修复:鸿蒙端使用ohos属性替代android属性,P2P引擎鸿蒙端跳过
|
||||
// ============================================================
|
||||
|
||||
import 'dart:async';
|
||||
@@ -38,10 +38,13 @@ class NearbyP2pDeviceInfo {
|
||||
|
||||
/// 端点ID
|
||||
final String endpointId;
|
||||
|
||||
/// 端点名称
|
||||
final String endpointName;
|
||||
|
||||
/// 服务ID
|
||||
final String? serviceId;
|
||||
|
||||
/// 连接状态
|
||||
final NearbyP2pConnectionState state;
|
||||
|
||||
@@ -160,10 +163,10 @@ class NearbyServiceAdapter {
|
||||
bool get p2pIsDiscovering => _p2pIsDiscovering;
|
||||
List<NearbyP2pDeviceInfo> get p2pDiscoveredDevices =>
|
||||
_p2pDiscoveredDevices.values.toList();
|
||||
List<NearbyP2pDeviceInfo> get p2pConnectedDevices =>
|
||||
_p2pDiscoveredDevices.values
|
||||
.where((d) => d.state == NearbyP2pConnectionState.connected)
|
||||
.toList();
|
||||
List<NearbyP2pDeviceInfo> get p2pConnectedDevices => _p2pDiscoveredDevices
|
||||
.values
|
||||
.where((d) => d.state == NearbyP2pConnectionState.connected)
|
||||
.toList();
|
||||
|
||||
// ============================================================
|
||||
// 公共流
|
||||
@@ -578,9 +581,18 @@ class NearbyServiceAdapter {
|
||||
}
|
||||
|
||||
Future<bool> requestPermissions() async {
|
||||
if ((!Platform.isAndroid && !pu.isOhos) || _service == null) return true;
|
||||
if (!Platform.isAndroid && !pu.isOhos) return true;
|
||||
if (_service == null) return false;
|
||||
try {
|
||||
return await _service!.android!.requestPermissions();
|
||||
// Android使用android属性,鸿蒙使用ohos属性
|
||||
if (Platform.isAndroid) {
|
||||
return await _service!.android?.requestPermissions() ?? false;
|
||||
}
|
||||
if (pu.isOhos) {
|
||||
// 鸿蒙端权限通过permission_handler统一请求,nearby_service.ohos无独立权限方法
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
Log.e('NearbyService: Request permissions failed: $e');
|
||||
return false;
|
||||
@@ -588,9 +600,15 @@ class NearbyServiceAdapter {
|
||||
}
|
||||
|
||||
Future<bool> checkWifiService() async {
|
||||
if ((!Platform.isAndroid && !pu.isOhos) || _service == null) return true;
|
||||
if (!Platform.isAndroid && !pu.isOhos) return true;
|
||||
if (_service == null) return true;
|
||||
try {
|
||||
return await _service!.android!.checkWifiService();
|
||||
// 仅Android端支持Wi-Fi服务检查
|
||||
if (Platform.isAndroid) {
|
||||
return await _service!.android?.checkWifiService() ?? false;
|
||||
}
|
||||
// 鸿蒙/iOS/macOS端无需检查Wi-Fi服务
|
||||
return true;
|
||||
} catch (e) {
|
||||
Log.e('NearbyService: Check WiFi failed: $e');
|
||||
return false;
|
||||
@@ -729,12 +747,13 @@ class NearbyServiceAdapter {
|
||||
'xianyan_discoverer',
|
||||
Strategy.P2P_CLUSTER,
|
||||
serviceId: _p2pServiceId,
|
||||
onEndpointFound: (String endpointId, String endpointName, String serviceId) {
|
||||
Log.i(
|
||||
'NearbyP2p: 发现设备: $endpointName ($endpointId, service=$serviceId)',
|
||||
);
|
||||
_onP2pEndpointFound(endpointId, endpointName, serviceId);
|
||||
},
|
||||
onEndpointFound:
|
||||
(String endpointId, String endpointName, String serviceId) {
|
||||
Log.i(
|
||||
'NearbyP2p: 发现设备: $endpointName ($endpointId, service=$serviceId)',
|
||||
);
|
||||
_onP2pEndpointFound(endpointId, endpointName, serviceId);
|
||||
},
|
||||
onEndpointLost: (String? endpointId) {
|
||||
if (endpointId != null) {
|
||||
Log.i('NearbyP2p: 设备丢失: $endpointId');
|
||||
@@ -817,9 +836,10 @@ class NearbyServiceAdapter {
|
||||
onPayLoadRecieved: (String endpointId, Payload payload) {
|
||||
_onP2pPayloadReceived(endpointId, payload);
|
||||
},
|
||||
onPayloadTransferUpdate: (String endpointId, PayloadTransferUpdate payloadTransferUpdate) {
|
||||
_onP2pPayloadTransferUpdate(endpointId, payloadTransferUpdate);
|
||||
},
|
||||
onPayloadTransferUpdate:
|
||||
(String endpointId, PayloadTransferUpdate payloadTransferUpdate) {
|
||||
_onP2pPayloadTransferUpdate(endpointId, payloadTransferUpdate);
|
||||
},
|
||||
);
|
||||
Log.i('NearbyP2p: 接受连接: $endpointId');
|
||||
} catch (e) {
|
||||
@@ -883,10 +903,7 @@ class NearbyServiceAdapter {
|
||||
}
|
||||
|
||||
// 通过nearby_connections发送文件payload
|
||||
await Nearby().sendFilePayload(
|
||||
endpointId,
|
||||
filePath,
|
||||
);
|
||||
await Nearby().sendFilePayload(endpointId, filePath);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
@@ -900,10 +917,7 @@ class NearbyServiceAdapter {
|
||||
if (!isP2pSupported) return false;
|
||||
|
||||
try {
|
||||
await Nearby().sendBytesPayload(
|
||||
endpointId,
|
||||
data,
|
||||
);
|
||||
await Nearby().sendBytesPayload(endpointId, data);
|
||||
Log.i('NearbyP2p: 发送数据: ${data.length} bytes');
|
||||
return true;
|
||||
} catch (e) {
|
||||
@@ -1041,8 +1055,7 @@ class NearbyServiceAdapter {
|
||||
final filePath = payload.uri ?? payload.filePath;
|
||||
if (filePath != null) {
|
||||
final fileName = filePath.split('/').last;
|
||||
final mimeType =
|
||||
lookupMimeType(fileName) ?? 'application/octet-stream';
|
||||
final mimeType = lookupMimeType(fileName) ?? 'application/octet-stream';
|
||||
final isImage = mimeType.startsWith('image/');
|
||||
final isVideo = mimeType.startsWith('video/');
|
||||
|
||||
@@ -1168,18 +1181,21 @@ class NearbyServiceAdapter {
|
||||
/// 将P2P设备同步到nearby_service设备流(统一设备列表)
|
||||
void _notifyP2pDeviceAsTransferDevice() {
|
||||
final devices = _p2pDiscoveredDevices.values
|
||||
.map((d) => TransferDevice(
|
||||
id: d.endpointId,
|
||||
alias: d.endpointName,
|
||||
deviceType: DeviceType.mobile,
|
||||
port: 0,
|
||||
pairingMethod: PairingMethod.nearbyP2p,
|
||||
preferredTransport: TransportType.wifiDirect,
|
||||
lastSeen: DateTime.now(),
|
||||
isOnline: d.state == NearbyP2pConnectionState.connected ||
|
||||
d.state == NearbyP2pConnectionState.discovered,
|
||||
isVerified: d.state == NearbyP2pConnectionState.connected,
|
||||
))
|
||||
.map(
|
||||
(d) => TransferDevice(
|
||||
id: d.endpointId,
|
||||
alias: d.endpointName,
|
||||
deviceType: DeviceType.mobile,
|
||||
port: 0,
|
||||
pairingMethod: PairingMethod.nearbyP2p,
|
||||
preferredTransport: TransportType.wifiDirect,
|
||||
lastSeen: DateTime.now(),
|
||||
isOnline:
|
||||
d.state == NearbyP2pConnectionState.connected ||
|
||||
d.state == NearbyP2pConnectionState.discovered,
|
||||
isVerified: d.state == NearbyP2pConnectionState.connected,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
if (!_devicesController.isClosed && devices.isNotEmpty) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import '../../../../shared/widgets/containers/glass_container.dart';
|
||||
import '../../../../shared/widgets/adaptive/adaptive_back_button.dart';
|
||||
import '../../../../shared/widgets/feedback/external_link_dialog.dart';
|
||||
import '../../../../shared/widgets/feedback/app_toast.dart';
|
||||
import 'about_shared_widgets.dart';
|
||||
|
||||
class AboutPage extends ConsumerWidget {
|
||||
const AboutPage({super.key});
|
||||
@@ -464,29 +465,19 @@ class _DeveloperSection extends ConsumerWidget {
|
||||
subtitle: t.about.updateLogMenuDesc,
|
||||
ext: ext,
|
||||
onTap: () {
|
||||
// 拼接共享更新日志数据
|
||||
final logText = AppUpdateLog.entries
|
||||
.map((entry) {
|
||||
final items = entry.changes.map((c) => '• $c').join('\n');
|
||||
return '${entry.version} (${entry.date})\n$items';
|
||||
})
|
||||
.join('\n\n');
|
||||
|
||||
showCupertinoDialog<void>(
|
||||
context: context,
|
||||
builder: (ctx) => CupertinoAlertDialog(
|
||||
title: Text(t.about.updateLog),
|
||||
content: Text(
|
||||
'v${AppVersion.version}\n'
|
||||
'• 修复数据管理/图片缓存页面路由\n'
|
||||
'• 修复返回主页面渲染异常\n'
|
||||
'• 修复发现/灵感页面RenderSliver报错\n'
|
||||
'• 修复工具中心溢出问题\n'
|
||||
'• 优化下拉面板即时打开\n'
|
||||
'• 增强句子列表交错动画\n'
|
||||
'• 修复壁纸按钮颜色重合\n'
|
||||
'• 修复倒计时+号无反应\n'
|
||||
'• 绑定邮箱增加验证码流程\n'
|
||||
'• 检测更新改为"无更新"\n'
|
||||
'• 修复软件权限页面跳转\n'
|
||||
'• 增加收集信息入口\n'
|
||||
'• 日志查看器增加副标题\n'
|
||||
'• 增加导出个人信息功能\n'
|
||||
'• 备案信息迁移至软件信息页\n'
|
||||
'• 统一按钮选中色动态主题',
|
||||
),
|
||||
content: Text(logText),
|
||||
actions: [
|
||||
CupertinoDialogAction(
|
||||
isDefaultAction: true,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/// ============================================================
|
||||
/// 闲言APP — 关于页面共享组件
|
||||
/// 创建时间: 2026-05-29
|
||||
/// 更新时间: 2026-05-29
|
||||
/// 作用: 软件信息页与了解我们页共用的通用组件
|
||||
/// 上次更新: 从 app_info_page / learn_us_page 中提取共享组件
|
||||
/// 更新时间: 2026-06-05
|
||||
/// 作用: 软件信息页与了解我们页共用的通用组件及更新日志数据
|
||||
/// 上次更新: 新增 AppUpdateLog 共享更新日志数据,确保两处展示一致
|
||||
/// ============================================================
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
@@ -14,6 +14,61 @@ import '../../../../core/theme/app_spacing.dart';
|
||||
import '../../../../core/theme/app_typography.dart';
|
||||
import '../../../../core/theme/app_radius.dart';
|
||||
|
||||
// ============================================================
|
||||
// 更新日志数据 — 软件信息页 & 关于页共用
|
||||
// ============================================================
|
||||
|
||||
/// 单条更新日志
|
||||
class UpdateLogEntry {
|
||||
const UpdateLogEntry({
|
||||
required this.version,
|
||||
required this.date,
|
||||
required this.changes,
|
||||
});
|
||||
|
||||
/// 版本号
|
||||
final String version;
|
||||
|
||||
/// 发布日期
|
||||
final String date;
|
||||
|
||||
/// 更新内容列表(中文)
|
||||
final List<String> changes;
|
||||
}
|
||||
|
||||
/// 全局更新日志数据(中文)
|
||||
class AppUpdateLog {
|
||||
AppUpdateLog._();
|
||||
|
||||
static const List<UpdateLogEntry> entries = [
|
||||
UpdateLogEntry(
|
||||
version: 'v6.5.103',
|
||||
date: '2026-06-05',
|
||||
changes: [
|
||||
'🆕 新增桌面快捷方式(主题个性化、通用设置)',
|
||||
'🆕 引导页文件传输预览改为"移动设备/PC设备"',
|
||||
'🔧 修复鸿蒙 module.json5 shortcuts 配置校验报错',
|
||||
'🎨 液态玻璃风格适配优化',
|
||||
],
|
||||
),
|
||||
UpdateLogEntry(
|
||||
version: 'v6.5.1',
|
||||
date: '2026-05-29',
|
||||
changes: ['🔧 修复返回主页面渲染异常', '🎨 统一按钮选中色动态主题'],
|
||||
),
|
||||
UpdateLogEntry(
|
||||
version: 'v6.5.0',
|
||||
date: '2026-05-20',
|
||||
changes: [
|
||||
'🆕 增加收集信息入口',
|
||||
'🔧 增强句子列表交错动画',
|
||||
'🔧 修复软件权限页面跳转',
|
||||
'🔧 日志查看器增加副标题',
|
||||
],
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
class AboutSectionTitle extends StatelessWidget {
|
||||
const AboutSectionTitle({
|
||||
super.key,
|
||||
|
||||
@@ -20,7 +20,18 @@ import '../../../../core/theme/app_typography.dart';
|
||||
import '../../../../core/theme/app_radius.dart';
|
||||
import '../../../../core/utils/platform/platform_utils.dart' as pu;
|
||||
import '../../../../core/constants/app_constants.dart';
|
||||
import '../../../../core/utils/platform/platform_utils.dart' show isOhos, isAndroid, isWindows, isIOS, isMacOS, isLinux, isWeb, isMobile, isDesktop, platformName;
|
||||
import '../../../../core/utils/platform/platform_utils.dart'
|
||||
show
|
||||
isOhos,
|
||||
isAndroid,
|
||||
isWindows,
|
||||
isIOS,
|
||||
isMacOS,
|
||||
isLinux,
|
||||
isWeb,
|
||||
isMobile,
|
||||
isDesktop,
|
||||
platformName;
|
||||
import '../../../../shared/widgets/containers/glass_container.dart';
|
||||
import '../../../../l10n/translations.dart';
|
||||
import 'about_shared_widgets.dart';
|
||||
@@ -606,15 +617,18 @@ class UpdateLogSection extends StatelessWidget {
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
|
||||
child: UpdateItem(
|
||||
version: '${t.about.version} ${AppVersion.version}',
|
||||
date: '2026-05-29',
|
||||
changes: [
|
||||
t.about.updateLog1,
|
||||
t.about.updateLog2,
|
||||
t.about.updateLog3,
|
||||
],
|
||||
ext: ext,
|
||||
child: Column(
|
||||
children: AppUpdateLog.entries.map((entry) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: AppSpacing.sm),
|
||||
child: UpdateItem(
|
||||
version: entry.version,
|
||||
date: entry.date,
|
||||
changes: entry.changes,
|
||||
ext: ext,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppSpacing.md),
|
||||
@@ -650,9 +664,7 @@ class IcpSection extends StatelessWidget {
|
||||
icon: CupertinoIcons.doc_text,
|
||||
title: t.about.icpInfo,
|
||||
ext: ext,
|
||||
trailing: isChinese
|
||||
? null
|
||||
: _IcpInfoIcon(ext: ext, t: t),
|
||||
trailing: isChinese ? null : _IcpInfoIcon(ext: ext, t: t),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
@@ -808,11 +820,7 @@ class _IcpInfoIcon extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => _showIcpInfoHintDialog(context),
|
||||
child: Icon(
|
||||
CupertinoIcons.info_circle,
|
||||
size: 18,
|
||||
color: ext.textHint,
|
||||
),
|
||||
child: Icon(CupertinoIcons.info_circle, size: 18, color: ext.textHint),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:xianyan/core/router/app_nav_extension.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
import '../../../../../../core/services/accessibility/accessibility_service.dart';
|
||||
import '../../../../../../core/constants/app_constants.dart';
|
||||
import '../../../../../../core/router/app_routes.dart';
|
||||
import '../../../../../../core/services/device/app_lock_service.dart';
|
||||
@@ -138,12 +137,6 @@ class _GeneralSettingsPageState extends ConsumerState<GeneralSettingsPage>
|
||||
final t = ref.watch(translationsProvider);
|
||||
final splitState = ref.watch(splitViewProvider);
|
||||
|
||||
// 获取系统无障碍状态
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
final systemHighContrast = mediaQuery.highContrast;
|
||||
final systemReduceAnimations = mediaQuery.disableAnimations;
|
||||
final systemBoldText = mediaQuery.boldText;
|
||||
|
||||
final allSections = buildGeneralSettingSections(
|
||||
settings: settings,
|
||||
notificationEnabled: notificationEnabled,
|
||||
@@ -154,9 +147,6 @@ class _GeneralSettingsPageState extends ConsumerState<GeneralSettingsPage>
|
||||
navBarPositionIndex: splitState.navBarPosition.index,
|
||||
splitRatio: splitState.splitRatio,
|
||||
splitViewEnabled: splitState.splitViewEnabled,
|
||||
systemHighContrast: systemHighContrast,
|
||||
systemReduceAnimations: systemReduceAnimations,
|
||||
systemBoldText: systemBoldText,
|
||||
);
|
||||
return filterSettingSections(
|
||||
allSections,
|
||||
@@ -944,10 +934,6 @@ class _GeneralSettingsPageState extends ConsumerState<GeneralSettingsPage>
|
||||
notifier.setNearbyDiscovery(value);
|
||||
case 'split_view_enabled':
|
||||
ref.read(splitViewProvider.notifier).setSplitViewEnabled(value);
|
||||
case 'semantics_debug':
|
||||
notifier.setSemanticsDebugEnabled(value);
|
||||
// 同步到AccessibilityService
|
||||
AccessibilityService.instance.setSemanticsDebug(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,6 @@ List<SettingSection> buildGeneralSettingSections({
|
||||
required int navBarPositionIndex,
|
||||
required double splitRatio,
|
||||
required bool splitViewEnabled,
|
||||
bool systemHighContrast = false,
|
||||
bool systemReduceAnimations = false,
|
||||
bool systemBoldText = false,
|
||||
}) {
|
||||
return [
|
||||
// ── 交互设置 ──
|
||||
@@ -97,15 +94,15 @@ List<SettingSection> buildGeneralSettingSections({
|
||||
),
|
||||
if (settings.pageTransitionModeId == 'navigate')
|
||||
SettingItem(
|
||||
id: 'predictive_back',
|
||||
icon: CupertinoIcons.arrow_turn_down_left,
|
||||
iconColor: AppColors.iosLightBlue,
|
||||
title: t.predictiveBack,
|
||||
subtitle: t.predictiveBackSubtitle,
|
||||
type: SettingType.toggle,
|
||||
value: settings.predictiveBackEnabled,
|
||||
isLocked: true,
|
||||
),
|
||||
id: 'predictive_back',
|
||||
icon: CupertinoIcons.arrow_turn_down_left,
|
||||
iconColor: AppColors.iosLightBlue,
|
||||
title: t.predictiveBack,
|
||||
subtitle: t.predictiveBackSubtitle,
|
||||
type: SettingType.toggle,
|
||||
value: settings.predictiveBackEnabled,
|
||||
isLocked: true,
|
||||
),
|
||||
SettingItem(
|
||||
id: 'long_press_preview',
|
||||
icon: CupertinoIcons.hand_point_right_fill,
|
||||
@@ -317,51 +314,6 @@ List<SettingSection> buildGeneralSettingSections({
|
||||
],
|
||||
),
|
||||
|
||||
// ── 无障碍设置 ──
|
||||
SettingSection(
|
||||
title: '♿ 无障碍',
|
||||
icon: CupertinoIcons.person_circle_fill,
|
||||
color: AppColors.iosBlue,
|
||||
items: [
|
||||
SettingItem(
|
||||
id: 'semantics_debug',
|
||||
icon: CupertinoIcons.eye_fill,
|
||||
iconColor: AppColors.iosPurple,
|
||||
title: '语义调试',
|
||||
subtitle: '显示语义标注覆盖层,辅助开发无障碍适配',
|
||||
type: SettingType.toggle,
|
||||
value: settings.semanticsDebugEnabled,
|
||||
),
|
||||
SettingItem(
|
||||
id: 'system_high_contrast',
|
||||
icon: CupertinoIcons.circle_lefthalf_fill,
|
||||
iconColor: AppColors.iosOrange,
|
||||
title: '高对比度',
|
||||
subtitle: '跟随系统设置',
|
||||
type: SettingType.selection,
|
||||
displayValue: systemHighContrast ? '已开启' : '未开启',
|
||||
),
|
||||
SettingItem(
|
||||
id: 'system_reduce_animations',
|
||||
icon: CupertinoIcons.wand_stars_inverse,
|
||||
iconColor: AppColors.iosGray,
|
||||
title: '减少动画',
|
||||
subtitle: '跟随系统设置',
|
||||
type: SettingType.selection,
|
||||
displayValue: systemReduceAnimations ? '已开启' : '未开启',
|
||||
),
|
||||
SettingItem(
|
||||
id: 'system_bold_text',
|
||||
icon: CupertinoIcons.bold,
|
||||
iconColor: AppColors.iosGreen,
|
||||
title: '粗体文本',
|
||||
subtitle: '跟随系统设置',
|
||||
type: SettingType.selection,
|
||||
displayValue: systemBoldText ? '已开启' : '未开启',
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// ── 性能设置 ──
|
||||
SettingSection(
|
||||
title: t.performance,
|
||||
|
||||
@@ -18,6 +18,7 @@ import '../../../../core/router/app_nav_extension.dart';
|
||||
import '../../../../core/services/data/data_export_service.dart';
|
||||
import '../../../../core/services/data/settings_export_service.dart';
|
||||
import '../../../../core/services/device/haptic_service.dart';
|
||||
import '../../../../core/services/accessibility/accessibility_service.dart';
|
||||
import '../../../../core/theme/app_theme.dart';
|
||||
import '../../../../core/theme/app_spacing.dart';
|
||||
import '../../../../core/theme/app_typography.dart';
|
||||
@@ -217,6 +218,20 @@ class _OtherSettingsPageState extends ConsumerState<OtherSettingsPage> {
|
||||
ref.read(generalSettingsProvider.notifier).setBoldTextEnabled(v);
|
||||
},
|
||||
),
|
||||
SettingsSwitchTile(
|
||||
icon: CupertinoIcons.eye_fill,
|
||||
iconColor: const Color(0xFFAF52DE),
|
||||
title: '语义调试',
|
||||
subtitle: '显示语义标注覆盖层,辅助开发无障碍适配',
|
||||
value: settings.semanticsDebugEnabled,
|
||||
onChanged: (v) {
|
||||
HapticService.toggleSwitch();
|
||||
ref
|
||||
.read(generalSettingsProvider.notifier)
|
||||
.setSemanticsDebugEnabled(v);
|
||||
AccessibilityService.instance.setSemanticsDebug(v);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -444,7 +459,11 @@ class _OtherSettingsPageState extends ConsumerState<OtherSettingsPage> {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(CupertinoIcons.square_arrow_up, size: 18, color: CupertinoColors.white),
|
||||
const Icon(
|
||||
CupertinoIcons.square_arrow_up,
|
||||
size: 18,
|
||||
color: CupertinoColors.white,
|
||||
),
|
||||
const SizedBox(width: AppSpacing.sm),
|
||||
Text(
|
||||
'导出设置',
|
||||
@@ -475,11 +494,17 @@ class _OtherSettingsPageState extends ConsumerState<OtherSettingsPage> {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(CupertinoIcons.square_arrow_down, size: 18, color: ext.textPrimary),
|
||||
Icon(
|
||||
CupertinoIcons.square_arrow_down,
|
||||
size: 18,
|
||||
color: ext.textPrimary,
|
||||
),
|
||||
const SizedBox(width: AppSpacing.sm),
|
||||
Text(
|
||||
'从文件导入',
|
||||
style: AppTypography.body.copyWith(color: ext.textPrimary),
|
||||
style: AppTypography.body.copyWith(
|
||||
color: ext.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -498,11 +523,17 @@ class _OtherSettingsPageState extends ConsumerState<OtherSettingsPage> {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(CupertinoIcons.doc_on_clipboard, size: 18, color: ext.textPrimary),
|
||||
Icon(
|
||||
CupertinoIcons.doc_on_clipboard,
|
||||
size: 18,
|
||||
color: ext.textPrimary,
|
||||
),
|
||||
const SizedBox(width: AppSpacing.sm),
|
||||
Text(
|
||||
'从剪贴板导入',
|
||||
style: AppTypography.body.copyWith(color: ext.textPrimary),
|
||||
style: AppTypography.body.copyWith(
|
||||
color: ext.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -537,9 +568,7 @@ class _OtherSettingsPageState extends ConsumerState<OtherSettingsPage> {
|
||||
allowedExtensions: ['json'],
|
||||
);
|
||||
} catch (_) {
|
||||
result = await FilePicker.pickFiles(
|
||||
|
||||
);
|
||||
result = await FilePicker.pickFiles();
|
||||
}
|
||||
|
||||
if (result == null || result.files.isEmpty) return;
|
||||
@@ -648,7 +677,9 @@ class _OtherSettingsPageState extends ConsumerState<OtherSettingsPage> {
|
||||
child: const Text('导入'),
|
||||
onPressed: () async {
|
||||
Navigator.pop(ctx);
|
||||
final success = await SettingsExportService.importFromJson(jsonStr);
|
||||
final success = await SettingsExportService.importFromJson(
|
||||
jsonStr,
|
||||
);
|
||||
if (mounted) {
|
||||
_showMessage(success ? '✅ 导入成功,设置已更新' : '❌ 导入失败,请检查文件格式');
|
||||
if (success) {
|
||||
|
||||
@@ -518,7 +518,7 @@ class _WelcomePageState extends ConsumerState<WelcomePage> {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildDeviceIcon(ext, '📱', 'iPhone'),
|
||||
_buildDeviceIcon(ext, '📱', ob.mobileDevice),
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
@@ -543,7 +543,7 @@ class _WelcomePageState extends ConsumerState<WelcomePage> {
|
||||
),
|
||||
],
|
||||
),
|
||||
_buildDeviceIcon(ext, '💻', 'MacBook'),
|
||||
_buildDeviceIcon(ext, '💻', ob.pcDevice),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: AppSpacing.sm),
|
||||
|
||||
@@ -1339,6 +1339,8 @@ const ar = T(
|
||||
templateGlass: 'زجاجي',
|
||||
transferring: 'جارٍ النقل 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: 'جهاز محمول',
|
||||
pcDevice: 'جهاز كمبيوتر',
|
||||
rssLabel: 'خلاصات RSS',
|
||||
addRssSource: 'إضافة خلاصة',
|
||||
welcomeNavLabel: 'ترحيب',
|
||||
|
||||
@@ -1346,6 +1346,8 @@ const bn = T(
|
||||
templateGlass: 'ফ্রস্টেড',
|
||||
transferring: 'স্থানান্তরিত হচ্ছে 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: 'মোবাইল ডিভাইস',
|
||||
pcDevice: 'PC ডিভাইস',
|
||||
rssLabel: 'RSS ফিড',
|
||||
addRssSource: 'ফিড যোগ করুন',
|
||||
welcomeNavLabel: 'স্বাগতম',
|
||||
|
||||
@@ -1362,6 +1362,8 @@ const de = T(
|
||||
templateGlass: 'Milchglas',
|
||||
transferring: 'Übertragung 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: 'Mobilgerät',
|
||||
pcDevice: 'PC-Gerät',
|
||||
rssLabel: 'RSS-Feeds',
|
||||
addRssSource: 'Feed hinzufügen',
|
||||
welcomeNavLabel: 'Willkommen',
|
||||
|
||||
@@ -1356,6 +1356,8 @@ const en = T(
|
||||
templateGlass: 'Frosted',
|
||||
transferring: 'Transferring 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: 'Mobile Device',
|
||||
pcDevice: 'PC Device',
|
||||
rssLabel: 'RSS Feeds',
|
||||
addRssSource: 'Add Feed',
|
||||
welcomeNavLabel: 'Welcome',
|
||||
|
||||
@@ -1374,6 +1374,8 @@ const es = T(
|
||||
templateGlass: 'Esmerilado',
|
||||
transferring: 'Transfiriendo 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: 'Dispositivo móvil',
|
||||
pcDevice: 'Dispositivo PC',
|
||||
rssLabel: 'Fuentes RSS',
|
||||
addRssSource: 'Añadir fuente',
|
||||
welcomeNavLabel: 'Bienvenida',
|
||||
|
||||
@@ -1381,6 +1381,8 @@ const fr = T(
|
||||
templateGlass: 'Givré',
|
||||
transferring: 'Transfert 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: 'Appareil mobile',
|
||||
pcDevice: 'Appareil PC',
|
||||
rssLabel: 'Flux RSS',
|
||||
addRssSource: 'Ajouter un flux',
|
||||
welcomeNavLabel: 'Bienvenue',
|
||||
|
||||
@@ -1341,6 +1341,8 @@ const hi = T(
|
||||
templateGlass: 'फ्रॉस्टेड',
|
||||
transferring: 'स्थानांतरित हो रहा है 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: 'मोबाइल डिवाइस',
|
||||
pcDevice: 'PC डिवाइस',
|
||||
rssLabel: 'RSS फ़ीड',
|
||||
addRssSource: 'फ़ीड जोड़ें',
|
||||
welcomeNavLabel: 'स्वागत',
|
||||
|
||||
@@ -1371,6 +1371,8 @@ const it = T(
|
||||
templateGlass: 'Satinato',
|
||||
transferring: 'Trasferimento 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: 'Dispositivo mobile',
|
||||
pcDevice: 'Dispositivo PC',
|
||||
rssLabel: 'Feed RSS',
|
||||
addRssSource: 'Aggiungi feed',
|
||||
welcomeNavLabel: 'Benvenuto',
|
||||
|
||||
@@ -1301,6 +1301,8 @@ const ja = T(
|
||||
templateGlass: 'すりガラス',
|
||||
transferring: '転送中 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: 'モバイルデバイス',
|
||||
pcDevice: 'PCデバイス',
|
||||
rssLabel: 'RSSフィード',
|
||||
addRssSource: 'フィードを追加',
|
||||
welcomeNavLabel: 'ようこそ',
|
||||
|
||||
@@ -1302,6 +1302,8 @@ const ko = T(
|
||||
templateGlass: '서리유리',
|
||||
transferring: '전송 중 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: '모바일 기기',
|
||||
pcDevice: 'PC 기기',
|
||||
rssLabel: 'RSS 피드',
|
||||
addRssSource: '피드 추가',
|
||||
welcomeNavLabel: '환영',
|
||||
|
||||
@@ -1365,6 +1365,8 @@ const pt = T(
|
||||
templateGlass: 'Fosco',
|
||||
transferring: 'Transferindo 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: 'Dispositivo móvel',
|
||||
pcDevice: 'Dispositivo PC',
|
||||
rssLabel: 'Feeds RSS',
|
||||
addRssSource: 'Adicionar feed',
|
||||
welcomeNavLabel: 'Bem-vindo',
|
||||
|
||||
@@ -1363,6 +1363,8 @@ const ru = T(
|
||||
templateGlass: 'Матовое стекло',
|
||||
transferring: 'Передача 70%',
|
||||
wifiDirect: 'WiFi Direct',
|
||||
mobileDevice: 'Мобильное устройство',
|
||||
pcDevice: 'ПК-устройство',
|
||||
rssLabel: 'RSS-каналы',
|
||||
addRssSource: 'Добавить канал',
|
||||
welcomeNavLabel: 'Приветствие',
|
||||
|
||||
@@ -1289,6 +1289,8 @@ const zhCN = T(
|
||||
templateGlass: '毛玻璃',
|
||||
transferring: '传输中 70%',
|
||||
wifiDirect: 'WiFi直连',
|
||||
mobileDevice: '移动设备',
|
||||
pcDevice: 'PC设备',
|
||||
rssLabel: 'RSS 订阅源',
|
||||
addRssSource: '添加订阅源',
|
||||
welcomeNavLabel: '欢迎与指引',
|
||||
|
||||
@@ -1288,6 +1288,8 @@ const zhTW = T(
|
||||
templateGlass: '毛玻璃',
|
||||
transferring: '傳輸中 70%',
|
||||
wifiDirect: 'WiFi直連',
|
||||
mobileDevice: '行動裝置',
|
||||
pcDevice: 'PC裝置',
|
||||
rssLabel: 'RSS 訂閱源',
|
||||
addRssSource: '添加訂閱源',
|
||||
welcomeNavLabel: '歡迎與指引',
|
||||
|
||||
@@ -36,6 +36,8 @@ class TOnboarding {
|
||||
required this.templateGlass,
|
||||
required this.transferring,
|
||||
required this.wifiDirect,
|
||||
required this.mobileDevice,
|
||||
required this.pcDevice,
|
||||
required this.rssLabel,
|
||||
required this.addRssSource,
|
||||
required this.welcomeNavLabel,
|
||||
@@ -158,6 +160,12 @@ class TOnboarding {
|
||||
/// WiFi直连
|
||||
final String wifiDirect;
|
||||
|
||||
/// 移动设备
|
||||
final String mobileDevice;
|
||||
|
||||
/// PC设备
|
||||
final String pcDevice;
|
||||
|
||||
/// RSS 订阅源
|
||||
final String rssLabel;
|
||||
|
||||
@@ -293,6 +301,8 @@ class TOnboarding {
|
||||
'templateGlass': templateGlass,
|
||||
'transferring': transferring,
|
||||
'wifiDirect': wifiDirect,
|
||||
'mobileDevice': mobileDevice,
|
||||
'pcDevice': pcDevice,
|
||||
'rssLabel': rssLabel,
|
||||
'addRssSource': addRssSource,
|
||||
'welcomeNavLabel': welcomeNavLabel,
|
||||
@@ -329,8 +339,10 @@ class TOnboarding {
|
||||
'completeSetup': completeSetup,
|
||||
};
|
||||
|
||||
static TOnboarding fromMap(Map<String, String> map, {TOnboarding? fallback}) =>
|
||||
TOnboarding(
|
||||
static TOnboarding fromMap(
|
||||
Map<String, String> map, {
|
||||
TOnboarding? fallback,
|
||||
}) => TOnboarding(
|
||||
welcomeTitle: map['welcomeTitle']?.isNotEmpty == true
|
||||
? map['welcomeTitle']!
|
||||
: (fallback?.welcomeTitle ?? ''),
|
||||
@@ -361,8 +373,8 @@ class TOnboarding {
|
||||
featureFileTransferDesc: map['featureFileTransferDesc']?.isNotEmpty == true
|
||||
? map['featureFileTransferDesc']!
|
||||
: (fallback?.featureFileTransferDesc ?? ''),
|
||||
featureFileTransferDetail: map['featureFileTransferDetail']?.isNotEmpty ==
|
||||
true
|
||||
featureFileTransferDetail:
|
||||
map['featureFileTransferDetail']?.isNotEmpty == true
|
||||
? map['featureFileTransferDetail']!
|
||||
: (fallback?.featureFileTransferDetail ?? ''),
|
||||
featureChatFlow: map['featureChatFlow']?.isNotEmpty == true
|
||||
@@ -416,6 +428,12 @@ class TOnboarding {
|
||||
wifiDirect: map['wifiDirect']?.isNotEmpty == true
|
||||
? map['wifiDirect']!
|
||||
: (fallback?.wifiDirect ?? ''),
|
||||
mobileDevice: map['mobileDevice']?.isNotEmpty == true
|
||||
? map['mobileDevice']!
|
||||
: (fallback?.mobileDevice ?? ''),
|
||||
pcDevice: map['pcDevice']?.isNotEmpty == true
|
||||
? map['pcDevice']!
|
||||
: (fallback?.pcDevice ?? ''),
|
||||
rssLabel: map['rssLabel']?.isNotEmpty == true
|
||||
? map['rssLabel']!
|
||||
: (fallback?.rssLabel ?? ''),
|
||||
|
||||
Reference in New Issue
Block a user