上次提交补充
This commit is contained in:
64
lib/core/localization/app_localizations.dart
Normal file
64
lib/core/localization/app_localizations.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppLocalizations {
|
||||
final Locale locale;
|
||||
Map<String, dynamic> _localizedStrings = {};
|
||||
|
||||
AppLocalizations(this.locale);
|
||||
|
||||
static AppLocalizations of(BuildContext context) {
|
||||
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
|
||||
}
|
||||
|
||||
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
|
||||
|
||||
Future<bool> load() async {
|
||||
try {
|
||||
String jsonString = await rootBundle.loadString(
|
||||
'assets/languages/${locale.languageCode}-${locale.countryCode}.json',
|
||||
);
|
||||
Map<String, dynamic> jsonMap = json.decode(jsonString);
|
||||
_localizedStrings = jsonMap;
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('❌ [AppLocalizations] 加载语言文件失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String translate(String key) {
|
||||
final keys = key.split('.');
|
||||
dynamic value = _localizedStrings;
|
||||
|
||||
for (final k in keys) {
|
||||
if (value is Map<String, dynamic>) {
|
||||
value = value[k];
|
||||
} else {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return value?.toString() ?? key;
|
||||
}
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||||
const _AppLocalizationsDelegate();
|
||||
|
||||
@override
|
||||
bool isSupported(Locale locale) {
|
||||
return ['zh', 'en'].contains(locale.languageCode);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<AppLocalizations> load(Locale locale) async {
|
||||
final localizations = AppLocalizations(locale);
|
||||
await localizations.load();
|
||||
return localizations;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
||||
}
|
||||
158
lib/features/home/presentation/bloc/permission_request_bloc.dart
Normal file
158
lib/features/home/presentation/bloc/permission_request_bloc.dart
Normal file
@@ -0,0 +1,158 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
import '../../../../core/logging/i_logger_service.dart';
|
||||
import '../../../../core/network/net_message_dispatcher.dart';
|
||||
import '../../../remote_control/domain/repositories/remote_control_repository.dart';
|
||||
import 'permission_request_event.dart';
|
||||
import 'permission_request_state.dart';
|
||||
|
||||
class PermissionRequestBloc extends Bloc<PermissionRequestEvent, PermissionRequestState> {
|
||||
final NetMessageDispatcher _dispatcher;
|
||||
final RemoteControlRepository _repository;
|
||||
final ILoggerService _logger = GetIt.I<ILoggerService>();
|
||||
|
||||
// 🔥 保存订阅引用,用于管理生命周期
|
||||
StreamSubscription? _permissionSubscription;
|
||||
|
||||
PermissionRequestBloc(this._dispatcher, this._repository) : super(const PermissionRequestInitial()) {
|
||||
// 🔥 核心:直接在构造函数中建立 0x12 监听(通过 NetMessageDispatcher)
|
||||
_initPermissionListener();
|
||||
|
||||
// 事件处理
|
||||
on<PermissionRequestReceived>(_handleRequestReceived);
|
||||
on<PermissionDialogDismissed>(_handleDialogDismissed);
|
||||
}
|
||||
|
||||
// 🔥 通过 NetMessageDispatcher 监听 TCP 0x12 指令,解析权限请求
|
||||
void _initPermissionListener() {
|
||||
debugPrint('🔗 [PermissionRequestBloc] 初始化 0x12 权限监听器(通过 NetMessageDispatcher)');
|
||||
_logger.logWithLevel('🔗 [PermissionRequestBloc] 初始化 0x12 权限监听器', shouldLog: true);
|
||||
|
||||
_permissionSubscription = _dispatcher.onCommand(0x12).listen((packet) {
|
||||
|
||||
debugPrint('🔍 [PermissionRequestBloc] ✅✅✅ 0x12 包被监听到了!');
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ✅✅✅ 0x12 包被监听到了!', shouldLog: true);
|
||||
|
||||
try {
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ✅ 收到 0x12 原始包', shouldLog: true);
|
||||
|
||||
// 🔥 关键:手动去掉最后 2 个 CRC 字节
|
||||
String jsonString;
|
||||
if (packet.payload.length > 2) {
|
||||
jsonString = utf8.decode(packet.payload.sublist(0, packet.payload.length - 2));
|
||||
} else {
|
||||
jsonString = utf8.decode(packet.payload);
|
||||
}
|
||||
|
||||
debugPrint('>>> [PermissionRequestBloc] 收到 0x12: $jsonString');
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 收到 0x12: $jsonString', shouldLog: true);
|
||||
|
||||
final jsonMap = jsonDecode(jsonString);
|
||||
final requestType = jsonMap['request'];
|
||||
final platform = jsonMap['platform'];
|
||||
final respondData = jsonMap['respond'];
|
||||
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 解析结果: requestType=$requestType, platform=$platform', shouldLog: true);
|
||||
|
||||
// 情况 1: 响应格式(忽略)
|
||||
if (respondData != null && respondData is Map) {
|
||||
debugPrint('>>> [PermissionRequestBloc] 📊 收到响应格式,忽略');
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 📊 收到响应格式,忽略', shouldLog: true);
|
||||
return;
|
||||
}
|
||||
|
||||
// 情况 2: 请求格式 - switch_control
|
||||
if (requestType == 'switch_control') {
|
||||
// 🔥 关键判断:只有当是其他平台(web)请求时才弹窗
|
||||
if (platform != null && platform.toString().toLowerCase() != 'app') {
|
||||
debugPrint('>>> [PermissionRequestBloc] 🚨 $platform 端请求控制权');
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 🚨 $platform 端请求控制权', shouldLog: true);
|
||||
|
||||
if (!isClosed) {
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 📤 准备 add PermissionRequestReceived 事件', shouldLog: true);
|
||||
add(PermissionRequestReceived(
|
||||
platform: platform.toString(),
|
||||
requestType: requestType,
|
||||
));
|
||||
} else {
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ⚠️ Bloc 已关闭,无法添加事件', shouldLog: true);
|
||||
}
|
||||
} else {
|
||||
debugPrint('>>> [PermissionRequestBloc] ℹ️ APP 自己的请求回显,忽略');
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ℹ️ APP 自己的请求回显,忽略', shouldLog: true);
|
||||
}
|
||||
}
|
||||
// 情况 3: 异地登录通知
|
||||
else if (requestType == 'have_logged_in') {
|
||||
debugPrint('>>> [PermissionRequestBloc] ⚠️ 检测到异地登录');
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ⚠️ 检测到异地登录', shouldLog: true);
|
||||
|
||||
if (!isClosed) {
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 📤 准备 add PermissionRequestReceived 事件(异地登录)', shouldLog: true);
|
||||
add(PermissionRequestReceived(
|
||||
platform: 'unknown',
|
||||
requestType: requestType,
|
||||
));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('>>> [PermissionRequestBloc] ❌ 解析失败:$e');
|
||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ❌ 解析失败:$e', shouldLog: true);
|
||||
}
|
||||
});
|
||||
|
||||
debugPrint('✅ [PermissionRequestBloc] 0x12 监听器已建立完成');
|
||||
_logger.logWithLevel('✅ [PermissionRequestBloc] 0x12 监听器已建立完成', shouldLog: true);
|
||||
}
|
||||
|
||||
Future<void> _handleRequestReceived(
|
||||
PermissionRequestReceived event,
|
||||
Emitter<PermissionRequestState> emit,
|
||||
) async {
|
||||
debugPrint('📤 [PermissionRequestBloc] emit DialogVisible - platform=${event.platform}');
|
||||
_logger.logWithLevel('📤 [PermissionRequestBloc] emit DialogVisible - platform=${event.platform}', shouldLog: true);
|
||||
|
||||
emit(PermissionRequestDialogVisible(
|
||||
platform: event.platform,
|
||||
requestType: event.requestType,
|
||||
));
|
||||
|
||||
_logger.logWithLevel('📤 [PermissionRequestBloc] ✅ 已 emit DialogVisible 状态', shouldLog: true);
|
||||
}
|
||||
|
||||
Future<void> _handleDialogDismissed(
|
||||
PermissionDialogDismissed event,
|
||||
Emitter<PermissionRequestState> emit,
|
||||
) async {
|
||||
debugPrint('📤 [PermissionRequestBloc] emit DialogHidden');
|
||||
_logger.logWithLevel('📤 [PermissionRequestBloc] emit DialogHidden');
|
||||
|
||||
// 🔥 发送响应到机器人(和远程遥控页面一样)
|
||||
if (event.deviceId.isNotEmpty) {
|
||||
debugPrint('📤 [PermissionRequestBloc] 发送权限响应: agree=${event.agree}, deviceId=${event.deviceId}');
|
||||
_repository.respondPermission(event.agree, event.deviceId);
|
||||
}
|
||||
|
||||
emit(const PermissionRequestDialogHidden());
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
debugPrint('🚫 [PermissionRequestBloc] 关闭,取消订阅');
|
||||
_logger.logWithLevel('🚫 [PermissionRequestBloc] 关闭', shouldLog: true);
|
||||
_permissionSubscription?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
/// 🔥 公开方法:重新初始化监听器(TCP 重连后调用)
|
||||
void reinitListener() {
|
||||
debugPrint('🔄 [PermissionRequestBloc] 重新初始化监听器');
|
||||
_logger.logWithLevel('🔄 [PermissionRequestBloc] 重新初始化监听器', shouldLog: true);
|
||||
_permissionSubscription?.cancel();
|
||||
_initPermissionListener();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
abstract class PermissionRequestEvent extends Equatable {
|
||||
const PermissionRequestEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class PermissionRequestReceived extends PermissionRequestEvent {
|
||||
final String platform;
|
||||
final String requestType;
|
||||
|
||||
const PermissionRequestReceived({
|
||||
required this.platform,
|
||||
required this.requestType,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [platform, requestType];
|
||||
}
|
||||
|
||||
class PermissionDialogDismissed extends PermissionRequestEvent {
|
||||
final bool agree;
|
||||
final String deviceId;
|
||||
|
||||
const PermissionDialogDismissed({
|
||||
required this.agree,
|
||||
required this.deviceId,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [agree, deviceId];
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
abstract class PermissionRequestState extends Equatable {
|
||||
const PermissionRequestState();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class PermissionRequestInitial extends PermissionRequestState {
|
||||
const PermissionRequestInitial();
|
||||
}
|
||||
|
||||
class PermissionRequestDialogVisible extends PermissionRequestState {
|
||||
final String platform;
|
||||
final String requestType;
|
||||
|
||||
const PermissionRequestDialogVisible({
|
||||
required this.platform,
|
||||
required this.requestType,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [platform, requestType];
|
||||
}
|
||||
|
||||
class PermissionRequestDialogHidden extends PermissionRequestState {
|
||||
const PermissionRequestDialogHidden();
|
||||
}
|
||||
Reference in New Issue
Block a user