From 27cabe1bdeae8a4ddbfc27b8bef3603b02b7728f Mon Sep 17 00:00:00 2001 From: Rodger-Wang <1367893453@qq.com> Date: Sun, 13 Sep 2026 00:27:33 +0800 Subject: [PATCH] =?UTF-8?q?client:=20=E8=AE=BE=E5=A4=87=E5=86=85=E6=A0=B8?= =?UTF-8?q?=E6=8A=BD=E8=B1=A1=E3=80=81Smartcar=20=E8=BD=A6=E8=BD=BD?= =?UTF-8?q?=E9=A6=99=E8=96=B0=E6=8E=A5=E5=85=A5=E4=B8=8E=E8=AF=AD=E9=9F=B3?= =?UTF-8?q?=E7=BA=AA=E8=A6=81=E7=AD=89=E4=B8=80=E6=89=B9=E6=94=B9=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 工作区里累积的 Flutter 客户端改动,随本轮一并入库。主要涉及: - lib/devices/ 设备内核:DeviceHub / DevicePlugin / DeviceSession 抽象, 恒玄(bes)、EaiRec 支架(holder)、Smartcar 车载香薰(smartcar) 各自的插件实现, 业务层不再直接依赖任何厂商类;分层边界由 test/devices/ 下的测试守着 - local_plugins/device_plugin_interface、device_smartcar、recorder_holder: 纯 Dart 契约与原生侧实现 - lib/modules/ 能力模块注册表、语音纪要、OTA 升级等模块 - test/ 新增设备协议、Ogg Opus 时长、模块注册表、路由等金测试 - ios/sync_spm_platform.sh:修 Xcode 直接构建时 SPM 平台版本被打回 13.0 的问题 验证:dart analyze lib 无 error(264 条 warning 均为 HEAD 上既有的 unused_import / avoid_print 等 lint,非本次引入)。未跑真机与打包。 注:这批不是本次会话中由 Claude 编写的,此处仅做入库。 --- .vscode/settings.json | 3 + apps/client/.env.example | 2 + apps/client/.gitignore | 3 + apps/client/GOOGLE_PLAY_RELEASE_CHECKLIST.md | 46 + apps/client/analysis_options.yaml | 22 + apps/client/android/app/build.gradle.kts | 9 +- .../android/app/src/main/AndroidManifest.xml | 8 +- apps/client/android/settings.gradle.kts | 4 - .../client/assets/images/devices/Echomeet.png | Bin 0 -> 465812 bytes .../assets/images/devices/Echomeet_icon.png | Bin 0 -> 15759 bytes apps/client/build_channels.sh | 6 +- apps/client/check_16kb.py | 106 ++ apps/client/ios/Podfile.lock | 6 - .../ios/Runner.xcodeproj/project.pbxproj | 7 +- apps/client/ios/sync_spm_platform.sh | 146 +++ .../lib/core/bindings/initial_binding.dart | 60 +- .../lib/core/services/ai_orb_controller.dart | 1 - .../core/translations/app_translations.dart | 8 +- .../lib/core/translations/language/ar_sa.dart | 204 ++++ .../lib/core/translations/language/bg_bg.dart | 204 ++++ .../lib/core/translations/language/cs_cz.dart | 204 ++++ .../lib/core/translations/language/da_dk.dart | 204 ++++ .../lib/core/translations/language/de_de.dart | 30 + .../lib/core/translations/language/el_gr.dart | 204 ++++ .../lib/core/translations/language/en_us.dart | 16 + .../lib/core/translations/language/es_es.dart | 30 + .../lib/core/translations/language/et_ee.dart | 204 ++++ .../lib/core/translations/language/fa_ir.dart | 204 ++++ .../lib/core/translations/language/fi_fi.dart | 204 ++++ .../lib/core/translations/language/fr_fr.dart | 30 + .../lib/core/translations/language/hi_in.dart | 204 ++++ .../lib/core/translations/language/hr_hr.dart | 204 ++++ .../lib/core/translations/language/hu_hu.dart | 204 ++++ .../lib/core/translations/language/id_id.dart | 204 ++++ .../lib/core/translations/language/is_is.dart | 204 ++++ .../lib/core/translations/language/it_it.dart | 204 ++++ .../lib/core/translations/language/ja_jp.dart | 30 + .../lib/core/translations/language/ko_kr.dart | 30 + .../lib/core/translations/language/lt_lt.dart | 204 ++++ .../lib/core/translations/language/lv_lv.dart | 204 ++++ .../lib/core/translations/language/ms_my.dart | 204 ++++ .../lib/core/translations/language/nb_no.dart | 204 ++++ .../lib/core/translations/language/nl_nl.dart | 359 +++++++ .../lib/core/translations/language/pl_pl.dart | 204 ++++ .../lib/core/translations/language/pt_pt.dart | 30 + .../lib/core/translations/language/ro_ro.dart | 204 ++++ .../lib/core/translations/language/ru_ru.dart | 30 + .../lib/core/translations/language/sk_sk.dart | 204 ++++ .../lib/core/translations/language/sl_si.dart | 204 ++++ .../lib/core/translations/language/sr_rs.dart | 204 ++++ .../lib/core/translations/language/sv_se.dart | 204 ++++ .../lib/core/translations/language/th_th.dart | 204 ++++ .../lib/core/translations/language/tl_ph.dart | 204 ++++ .../lib/core/translations/language/tr_tr.dart | 206 ++++ .../lib/core/translations/language/uk_ua.dart | 204 ++++ .../lib/core/translations/language/vi_vn.dart | 204 ++++ .../lib/core/translations/language/zh_cn.dart | 16 + .../lib/core/translations/language/zh_hk.dart | 30 + .../lib/core/translations/language/zh_tw.dart | 30 + .../lib/core/utils/device_connection.dart | 88 +- .../lib/core/utils/version_compare.dart | 34 + apps/client/lib/data/models/agent_module.dart | 145 +-- apps/client/lib/data/models/appconfig.dart | 5 - .../lib/data/models/appconfig_model.dart | 29 +- .../lib/data/models/appconfig_model.g.dart | 59 +- .../lib/data/models/assistant_directive.dart | 87 +- .../lib/data/models/device_category.dart | 73 +- apps/client/lib/data/models/goods.dart | 28 +- apps/client/lib/data/models/user_Info.dart | 18 + .../lib/data/services/account_service.dart | 6 +- .../data/services/agent_module_defaults.dart | 67 +- .../data/services/agent_module_service.dart | 58 +- .../services/assistant_directive_service.dart | 19 + .../services/bailian_multimodal_service.dart | 23 + .../services/device_ai_session_service.dart | 666 ++++++++++++ .../device_call_recording_service.dart | 296 ++++++ .../services/device_file_import_service.dart | 489 +++++++++ .../services/device_recording_service.dart | 284 ++++++ .../data/services/device_stereo_recorder.dart | 103 ++ .../client/lib/data/services/network/api.dart | 22 +- .../services/network/auth_interceptor.dart | 48 +- .../lib/data/services/ota_check_service.dart | 183 ++-- .../lib/data/services/recording_archive.dart | 14 +- apps/client/lib/data/services/wav_writer.dart | 136 +++ .../lib/data/utils/device_file_match.dart | 27 + .../lib/data/utils/ogg_opus_duration.dart | 93 ++ .../client/lib/data/utils/recording_time.dart | 28 + .../devices/bes/bes_bluetooth_service.dart | 158 +-- .../lib/devices/bes/bes_device_auth.dart | 23 +- .../lib/devices/bes/bes_device_plugin.dart | 637 ++++++++++++ apps/client/lib/devices/bes/bes_ota_port.dart | 203 ++++ apps/client/lib/devices/bes/bes_protocol.dart | 278 +++++ apps/client/lib/devices/device_auth.dart | 71 ++ apps/client/lib/devices/device_bootstrap.dart | 41 + apps/client/lib/devices/device_hub.dart | 265 +++++ apps/client/lib/devices/device_vendors.dart | 14 + .../devices/holder/holder_device_plugin.dart | 437 ++++++++ .../devices/holder/holder_device_service.dart | 293 +++++- .../lib/devices/holder/holder_file_store.dart | 120 +++ .../lib/devices/holder/holder_ota_port.dart | 222 ++++ .../smartcar/smartcar_device_auth.dart | 170 ++++ .../smartcar/smartcar_device_plugin.dart | 959 ++++++++++++++++++ .../lib/devices/smartcar/smartcar_link.dart | 410 ++++++++ .../devices/smartcar/smartcar_ota_port.dart | 159 +++ .../devices/smartcar/smartcar_protocol.dart | 402 ++++++++ .../controllers/bes_test_controller.dart | 100 +- .../call_recording_controller.dart | 316 ++---- .../lib/modules/call_recording/module.dart | 49 + .../modules/devices/views/bes_scan_view.dart | 229 ++--- .../devices/views/device_category_view.dart | 43 +- .../devices/views/holder_scan_view.dart | 237 +++-- .../devices/views/smartcar_scan_view.dart | 398 ++++++++ .../emai/controllers/emai_controller.dart | 65 +- apps/client/lib/modules/emai/module.dart | 28 + .../lib/modules/emai/views/emai_view.dart | 14 +- .../controllers/goods_base_controller.dart | 17 + .../controllers/goodsvip_controller.dart | 79 +- .../modules/goods/views/goodsvip_view.dart | 71 +- .../home/controllers/home_controller.dart | 552 ++-------- .../login/controllers/login_controller.dart | 3 - .../modules/main_tab/views/tabs/ai_tab.dart | 6 +- .../main_tab/views/tabs/device_tab.dart | 373 ++----- .../main_tab/views/widgets/module_card.dart | 56 +- .../controllers/meeting_home_controller.dart | 3 - .../meeting_record_controller.dart | 26 +- .../controllers/mind_map_controller.dart | 64 +- apps/client/lib/modules/meeting/module.dart | 55 + .../meeting/views/meeting_home_view.dart | 57 ++ .../client/lib/modules/module_descriptor.dart | 75 ++ apps/client/lib/modules/module_registry.dart | 128 +++ .../controllers/my_devices_controller.dart | 135 +-- .../my_devices/views/my_devices_view.dart | 20 +- .../bindings/ota_upgrade_binding.dart | 4 +- .../controllers/device_ota_controller.dart | 421 ++++++++ .../controllers/ota_download_service.dart | 6 +- .../ota_upgrade/views/device_ota_view.dart | 6 +- .../views/ota_upgrade_popup_view.dart | 2 +- .../modules/picture_translation/module.dart | 26 + .../controllers/settings_controller.dart | 10 +- .../modules/settings/views/settings_view.dart | 20 - .../bindings/smartcar_chat_binding.dart | 48 + apps/client/lib/modules/smartcar/module.dart | 130 +++ .../lib/modules/text_translation/module.dart | 26 + .../controllers/translation_controller.dart | 307 ++---- .../translation_middleware_controller.dart | 5 +- .../lib/modules/translation/module.dart | 87 ++ .../dialogs/translation_mode_selector.dart | 6 +- apps/client/lib/routes/app_pages.dart | 505 ++------- apps/client/lib/routes/app_routes.dart | 106 +- .../Sources/ble_service/BleService.swift | 7 +- .../bluetooth_manager/android/build.gradle | 6 + .../android/src/main/cpp/CMakeLists.txt | 6 + .../ClassicBluetoothHelper.kt | 86 ++ .../ClassicBluetoothPlugin.kt | 20 + .../ClassicBluetoothHelper.swift | 17 + .../SwiftClassicBluetoothPlugin.swift | 9 + .../lib/classic_bluetooth.dart | 34 + .../ios/device_jieli/Package.swift | 8 + .../local_plugins/device_jieli/pubspec.yaml | 6 +- .../android/build.gradle | 37 - .../android/src/main/AndroidManifest.xml | 3 - .../device_plugin_interface/Assistant.kt | 149 --- .../device_plugin_interface/CallRecording.kt | 126 --- .../CallTranslation.kt | 139 --- .../DevicePluginInterfacePlugin.kt | 9 - .../NativeDeviceManager.kt | 93 -- .../NativeDevicePlugin.kt | 149 --- .../NativeDeviceSession.kt | 88 -- .../NativeDeviceTypes.kt | 208 ---- .../aiagent/device_plugin_interface/Ota.kt | 170 ---- .../Classes/DevicePluginInterfacePlugin.swift | 14 - .../ios/device_plugin_interface.podspec | 19 - .../lib/device_plugin_interface.dart | 2 +- .../lib/src/audio_format.dart | 86 +- .../lib/src/device_capability.dart | 38 +- .../lib/src/device_exception.dart | 8 + .../lib/src/device_files.dart | 87 ++ .../lib/src/device_info.dart | 87 +- .../lib/src/device_manager.dart | 107 -- .../lib/src/device_ota.dart | 7 + .../lib/src/device_plugin.dart | 24 + .../lib/src/device_session.dart | 115 ++- .../device_plugin_interface/pubspec.yaml | 15 +- .../device_smartcar/android/build.gradle | 83 ++ .../libs/jl_rcsp_V0.8.0_705-release.jar | Bin 0 -> 720497 bytes .../android/src/main/AndroidManifest.xml | 10 + .../device_smartcar/DeviceSmartcarPlugin.kt | 280 +++++ .../yimai/device_smartcar/OggOpusExtractor.kt | 137 +++ .../yimai/device_smartcar/SmartcarAudio.kt | 148 +++ .../device_smartcar/SmartcarBleCentral.kt | 185 ++++ .../com/yimai/device_smartcar/SmartcarGatt.kt | 463 +++++++++ .../com/yimai/device_smartcar/SmartcarOta.kt | 325 ++++++ .../com/yimai/device_smartcar/SmartcarRcsp.kt | 182 ++++ .../aar/jl_rcsp_V0.8.0_705-release.aar | Bin 0 -> 664211 bytes .../android/tool/unpack_aars.sh | 24 + .../ios/device_smartcar/Package.swift | 38 + .../DeviceSmartcarPlugin.swift | 259 +++++ .../device_smartcar/JLAssistBridge.swift | 94 ++ .../device_smartcar/OggOpusExtractor.swift | 138 +++ .../device_smartcar/SmartcarAudio.swift | 152 +++ .../device_smartcar/SmartcarBleCentral.swift | 230 +++++ .../Sources/device_smartcar/SmartcarOta.swift | 286 ++++++ .../device_smartcar/SmartcarPeripheral.swift | 338 ++++++ .../device_smartcar/lib/device_smartcar.dart | 82 ++ .../device_smartcar/pubspec.yaml | 31 + ...recorde_protocol.md => EaiRec_protocol.md} | 74 +- .../kotlin/com/recorder/holder/BleConst.kt | 24 + .../kotlin/com/recorder/holder/BleRecord.kt | 4 + .../kotlin/com/recorder/holder/BleService.kt | 174 +++- .../recorder/holder/RecorderHolderPlugin.kt | 18 + .../Sources/recorder_holder/BleConst.swift | 13 + .../Sources/recorder_holder/BleService.swift | 80 +- .../RecorderHolderPlugin.swift | 26 + .../lib/recorder_holder_rec.dart | 13 + .../lib/src/rec/rec_client.dart | 665 ++++++++++++ .../lib/src/rec/rec_frame.dart | 112 ++ .../lib/src/rec/rec_models.dart | 250 +++++ .../lib/src/rec/rec_native_transport.dart | 43 + .../lib/src/rec/rec_protocol.dart | 191 ++++ .../lib/src/rec/rec_transport.dart | 97 ++ .../lib/src/recorder_holder.dart | 46 + .../recorder_protocol(2)(1).md | 489 --------- .../recorder_holder}/recorder_protocol.md | 0 .../sdk/lib/echomeet_device_sdk.dart | 17 + .../recorder_holder/sdk/lib/src/client.dart | 93 +- .../test/rec/rec_client_test.dart | 458 +++++++++ .../test/rec/rec_frame_test.dart | 248 +++++ apps/client/pubspec.lock | 44 +- apps/client/pubspec.yaml | 36 +- apps/client/test/appconfig_model_test.dart | 73 ++ .../client/test/assistant_directive_test.dart | 54 + apps/client/test/device_file_match_test.dart | 43 + .../test/devices/bes_protocol_test.dart | 110 ++ .../devices/bes_session_commands_test.dart | 52 + .../devices/device_hub_boundary_test.dart | 62 ++ .../test/devices/smartcar_protocol_test.dart | 258 +++++ apps/client/test/module_registry_test.dart | 94 ++ apps/client/test/ogg_opus_duration_test.dart | 65 ++ apps/client/test/recording_time_test.dart | 38 + apps/client/test/routes_test.dart | 50 + .../client/test/user_device_license_test.dart | 52 + apps/client/tools/i18n_fill_missing.py | 220 ++++ 242 files changed, 24986 insertions(+), 4784 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 apps/client/assets/images/devices/Echomeet.png create mode 100644 apps/client/assets/images/devices/Echomeet_icon.png create mode 100755 apps/client/check_16kb.py create mode 100755 apps/client/ios/sync_spm_platform.sh create mode 100644 apps/client/lib/core/utils/version_compare.dart create mode 100644 apps/client/lib/data/services/device_ai_session_service.dart create mode 100644 apps/client/lib/data/services/device_call_recording_service.dart create mode 100644 apps/client/lib/data/services/device_file_import_service.dart create mode 100644 apps/client/lib/data/services/device_recording_service.dart create mode 100644 apps/client/lib/data/services/device_stereo_recorder.dart create mode 100644 apps/client/lib/data/services/wav_writer.dart create mode 100644 apps/client/lib/data/utils/device_file_match.dart create mode 100644 apps/client/lib/data/utils/ogg_opus_duration.dart create mode 100644 apps/client/lib/data/utils/recording_time.dart create mode 100644 apps/client/lib/devices/bes/bes_device_plugin.dart create mode 100644 apps/client/lib/devices/bes/bes_ota_port.dart create mode 100644 apps/client/lib/devices/bes/bes_protocol.dart create mode 100644 apps/client/lib/devices/device_auth.dart create mode 100644 apps/client/lib/devices/device_bootstrap.dart create mode 100644 apps/client/lib/devices/device_hub.dart create mode 100644 apps/client/lib/devices/device_vendors.dart create mode 100644 apps/client/lib/devices/holder/holder_device_plugin.dart create mode 100644 apps/client/lib/devices/holder/holder_file_store.dart create mode 100644 apps/client/lib/devices/holder/holder_ota_port.dart create mode 100644 apps/client/lib/devices/smartcar/smartcar_device_auth.dart create mode 100644 apps/client/lib/devices/smartcar/smartcar_device_plugin.dart create mode 100644 apps/client/lib/devices/smartcar/smartcar_link.dart create mode 100644 apps/client/lib/devices/smartcar/smartcar_ota_port.dart create mode 100644 apps/client/lib/devices/smartcar/smartcar_protocol.dart create mode 100644 apps/client/lib/modules/call_recording/module.dart create mode 100644 apps/client/lib/modules/devices/views/smartcar_scan_view.dart create mode 100644 apps/client/lib/modules/emai/module.dart create mode 100644 apps/client/lib/modules/meeting/module.dart create mode 100644 apps/client/lib/modules/module_descriptor.dart create mode 100644 apps/client/lib/modules/module_registry.dart create mode 100644 apps/client/lib/modules/ota_upgrade/controllers/device_ota_controller.dart create mode 100644 apps/client/lib/modules/picture_translation/module.dart create mode 100644 apps/client/lib/modules/smartcar/bindings/smartcar_chat_binding.dart create mode 100644 apps/client/lib/modules/smartcar/module.dart create mode 100644 apps/client/lib/modules/text_translation/module.dart create mode 100644 apps/client/lib/modules/translation/module.dart delete mode 100644 apps/client/local_plugins/device_plugin_interface/android/build.gradle delete mode 100644 apps/client/local_plugins/device_plugin_interface/android/src/main/AndroidManifest.xml delete mode 100644 apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/Assistant.kt delete mode 100644 apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/CallRecording.kt delete mode 100644 apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/CallTranslation.kt delete mode 100644 apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/DevicePluginInterfacePlugin.kt delete mode 100644 apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceManager.kt delete mode 100644 apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDevicePlugin.kt delete mode 100644 apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceSession.kt delete mode 100644 apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceTypes.kt delete mode 100644 apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/Ota.kt delete mode 100644 apps/client/local_plugins/device_plugin_interface/ios/Classes/DevicePluginInterfacePlugin.swift delete mode 100644 apps/client/local_plugins/device_plugin_interface/ios/device_plugin_interface.podspec create mode 100644 apps/client/local_plugins/device_plugin_interface/lib/src/device_files.dart delete mode 100644 apps/client/local_plugins/device_plugin_interface/lib/src/device_manager.dart create mode 100644 apps/client/local_plugins/device_smartcar/android/build.gradle create mode 100644 apps/client/local_plugins/device_smartcar/android/libs/jl_rcsp_V0.8.0_705-release.jar create mode 100644 apps/client/local_plugins/device_smartcar/android/src/main/AndroidManifest.xml create mode 100644 apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/DeviceSmartcarPlugin.kt create mode 100644 apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/OggOpusExtractor.kt create mode 100644 apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarAudio.kt create mode 100644 apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarBleCentral.kt create mode 100644 apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarGatt.kt create mode 100644 apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarOta.kt create mode 100644 apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarRcsp.kt create mode 100644 apps/client/local_plugins/device_smartcar/android/third_party/aar/jl_rcsp_V0.8.0_705-release.aar create mode 100755 apps/client/local_plugins/device_smartcar/android/tool/unpack_aars.sh create mode 100644 apps/client/local_plugins/device_smartcar/ios/device_smartcar/Package.swift create mode 100644 apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/DeviceSmartcarPlugin.swift create mode 100644 apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/JLAssistBridge.swift create mode 100644 apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/OggOpusExtractor.swift create mode 100644 apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarAudio.swift create mode 100644 apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarBleCentral.swift create mode 100644 apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarOta.swift create mode 100644 apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarPeripheral.swift create mode 100644 apps/client/local_plugins/device_smartcar/lib/device_smartcar.dart create mode 100644 apps/client/local_plugins/device_smartcar/pubspec.yaml rename apps/client/local_plugins/recorder_holder/{eai_recorde_protocol.md => EaiRec_protocol.md} (85%) create mode 100644 apps/client/local_plugins/recorder_holder/lib/recorder_holder_rec.dart create mode 100644 apps/client/local_plugins/recorder_holder/lib/src/rec/rec_client.dart create mode 100644 apps/client/local_plugins/recorder_holder/lib/src/rec/rec_frame.dart create mode 100644 apps/client/local_plugins/recorder_holder/lib/src/rec/rec_models.dart create mode 100644 apps/client/local_plugins/recorder_holder/lib/src/rec/rec_native_transport.dart create mode 100644 apps/client/local_plugins/recorder_holder/lib/src/rec/rec_protocol.dart create mode 100644 apps/client/local_plugins/recorder_holder/lib/src/rec/rec_transport.dart delete mode 100644 apps/client/local_plugins/recorder_holder/recorder_protocol(2)(1).md rename apps/client/{docs => local_plugins/recorder_holder}/recorder_protocol.md (100%) create mode 100644 apps/client/local_plugins/recorder_holder/test/rec/rec_client_test.dart create mode 100644 apps/client/local_plugins/recorder_holder/test/rec/rec_frame_test.dart create mode 100644 apps/client/test/appconfig_model_test.dart create mode 100644 apps/client/test/device_file_match_test.dart create mode 100644 apps/client/test/devices/bes_protocol_test.dart create mode 100644 apps/client/test/devices/bes_session_commands_test.dart create mode 100644 apps/client/test/devices/device_hub_boundary_test.dart create mode 100644 apps/client/test/devices/smartcar_protocol_test.dart create mode 100644 apps/client/test/module_registry_test.dart create mode 100644 apps/client/test/ogg_opus_duration_test.dart create mode 100644 apps/client/test/recording_time_test.dart create mode 100644 apps/client/test/routes_test.dart create mode 100644 apps/client/test/user_device_license_test.dart create mode 100644 apps/client/tools/i18n_fill_missing.py diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..e0f15db2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "automatic" +} \ No newline at end of file diff --git a/apps/client/.env.example b/apps/client/.env.example index 7e31dab1..f75c040a 100644 --- a/apps/client/.env.example +++ b/apps/client/.env.example @@ -72,3 +72,5 @@ VOLCANO_TRANSLATION_REGION= APP_IOS_IAP_PREFIX= APP_IOS_IAP_SUFFIX= APP_IOS_IAP_ID_MAP= +# 请求签名密钥(可选,不配用内置默认值;须与服务端一致) +API_SIGN_KEY= diff --git a/apps/client/.gitignore b/apps/client/.gitignore index 078e08fe..ced95f15 100644 --- a/apps/client/.gitignore +++ b/apps/client/.gitignore @@ -69,3 +69,6 @@ app.*.map.json # ---- 本机私密配置 ---- # .env 含火山/OpenAI/COS 等第三方密钥,只提交 .env.example .env + +# 多渠道打包产物(build_channels.sh 的默认输出目录) +build_outputs/ diff --git a/apps/client/GOOGLE_PLAY_RELEASE_CHECKLIST.md b/apps/client/GOOGLE_PLAY_RELEASE_CHECKLIST.md index 9f7cfd86..b56acc61 100644 --- a/apps/client/GOOGLE_PLAY_RELEASE_CHECKLIST.md +++ b/apps/client/GOOGLE_PLAY_RELEASE_CHECKLIST.md @@ -5,6 +5,52 @@ --- +## 进度(2026-09-12 更新) + +基线产物换成 `build_outputs/EAIMAR_0912_1.0.1_google.aab`(1.0.1+7,Channel=GLOBAL_GOOGLE), +下面每条都是在**这个 aab 上复验**过的,不是改完就算数。 + +| 项 | 状态 | 复验方式 | +|---|---|---| +| 1.1 targetSdk 36 | ✅ 已改 | 合并 manifest `targetSdkVersion="36"` | +| 1.2 Play Billing 8 | ✅ 已改 | aab 的 `dependencies.pb` 里 `com.android.billingclient:billing 8.0.0` | +| 1.3 16KB 页对齐 | ✅ 已改 | `python3 check_16kb.py ` → 64 位 .so 44/44 合规 | +| 2. 支付回退 | ✅ 已改 | Google 渠道硬闸门,见下 | +| 3. 权限瘦身 | 🟡 部分 | `GET_TASKS`、`MEDIA_CONTENT_CONTROL` 已移除(44→40 条),其余待定 | +| 4. 构建脚本 | ✅ 已改 | `./build_channels.sh google` 实测跑通 | +| 5. Play Console 事项 | ⬜ 未做 | 外部系统 | + +⚠️ **Billing 8 的迁移成本远低于本文当初的估计**:0.5.0 唯一的破坏性变更是移除 +`queryPurchaseHistory`,本项目零引用。实际改动就是 `in_app_purchase: ^3.3.0` + +`in_app_purchase_android: ^0.5.0` 两行,没碰一行业务代码。 + +⚠️ **支付回退的修法与本文第 2 节的建议不同,刻意的**:本文建议「安卓端兜底只留 google」, +但那会连带改掉国内五家渠道的兜底行为(后端没下发 paychannels 时国内用户就付不了款)。 +实际实现是**只对 Google 渠道加硬闸门**:`_isGooglePlayBuild` 为真时直接返回 +`[google]`,既不信后端下发的渠道列表、也不走任何回退分支;其它渠道逻辑原封不动。 +渠道判定读的是**编译期烧进包里的 `.env` 的 `Channel`**,⚠️ 不要换成 +`VersionUpdateService.cachedChannel`——那个值在版本检查跑完前会回退成 `GLOBAL_GOOGLE`, +用它会在国内包启动初期把微信/支付宝误杀。 + +⚠️ **`check_16kb.py` 当初并没有入库**(本文 1.3 节说「仓库里已有」是错的), +2026-09-12 才补写并提交。 + +### 仍然待办 + +- **`ACCESS_BACKGROUND_LOCATION` + `WRITE_SETTINGS` 主要由 `amap_service` 插件拖进来** + (`ACCESS_BACKGROUND_LOCATION` 另有 `location_service` 和主工程两个来源)。 + 而 `NavigationManager` 全项目只在 `initial_binding.dart` 用 `Get.lazyPut` 注册过, + **没有任何一处 `Get.find`**——高德导航在当前 App 里是走不到的死代码。 + 所以「Google 渠道不引入 `amap_service`」能一次干掉这两条最难过审的权限, + 且不会有功能损失(也顺带证明了排除高德 `.so` 不会崩:没有代码路径去加载它)。 +- `QUERY_ALL_PACKAGES`(主工程)、`SYSTEM_ALERT_WINDOW`(主工程 + `floating_ui_plugin`)、 + `SCHEDULE_EXACT_ALARM`(主工程)仍需声明表或删除。 +- **targetSdk 36 的真机回归没做**(edge-to-edge / 前台服务类型校验),见 1.1 节的警告。 +- **iOS 侧有同类的支付政策风险**:本次的闸门只加在 Google 渠道,App Store 包在 + `paychannels` 缺失时仍会回退成展示微信/支付宝/PayPal。 + +--- + ## 0. 先决定:要不要申请延期 有两条硬期限是 **2026-08-31**,也就是排查次日。两条都可以在 Play Console 申请延期到 **2026-11-01**。 diff --git a/apps/client/analysis_options.yaml b/apps/client/analysis_options.yaml index f9b30346..af3263ba 100644 --- a/apps/client/analysis_options.yaml +++ b/apps/client/analysis_options.yaml @@ -1 +1,23 @@ include: package:flutter_lints/flutter.yaml + +analyzer: + exclude: + - "**/*.g.dart" + - "local_plugins/**" + - "build/**" + errors: + # 这几类几乎总是「写了没接上」或「删了没删干净」,提级成 warning 让 CI 拦住 + unused_import: warning + unused_element: warning + unused_field: warning + unused_local_variable: warning + dead_code: warning + dead_null_aware_expression: warning + avoid_print: warning + # 老代码里的大写常量不在本轮整改范围,先降噪 + constant_identifier_names: ignore + +linter: + rules: + avoid_print: true + prefer_const_constructors: false diff --git a/apps/client/android/app/build.gradle.kts b/apps/client/android/app/build.gradle.kts index ee0eb9d6..49ba147f 100644 --- a/apps/client/android/app/build.gradle.kts +++ b/apps/client/android/app/build.gradle.kts @@ -5,7 +5,6 @@ repositories { mavenCentral() flatDir { dirs(project(":qq_music").projectDir.resolve("libs")) // 添加这行 - dirs(project(":device_jieli").projectDir.resolve("libs")) // 杰理 SDK 运行时 .aar } } @@ -81,7 +80,7 @@ android { // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = 26 // 更新为26以满足ble_service库的要求 - targetSdk = 35 // 设置为 Android 15 (API 35),以满足应用市场要求 + targetSdk = 36 // Android 16 (API 36),Google Play 2026-08-31 起的最低要求 versionCode = flutter.versionCode // 对应构建号,自动同步flutter构建号 versionName = flutter.versionName // 对应版本号,自动同步flutter版本号 } @@ -151,12 +150,6 @@ dependencies { // 添加 CardView 依赖 implementation("androidx.cardview:cardview:1.0.0") - // device_jieli 杰理 SDK 运行时依赖(.aar 在 device_jieli 模块只能 compileOnly, - // host app 必须自己引入,否则 RCSPController 等类在运行时找不到 → scanFeature 不会被初始化) - implementation(":jl_bluetooth_rcsp_V4.2.0_beta1_40255_20260324@aar") - implementation(":jl_audio_v2_V1.0.0_9-release@aar") - implementation(":jldecryption_v0.4-release@aar") - // jl_audio_decode 已经被 ble_service 通过 com.jieli.audio:jl_audio_decode:2.1.0 引入,无需重复 } flutter { diff --git a/apps/client/android/app/src/main/AndroidManifest.xml b/apps/client/android/app/src/main/AndroidManifest.xml index 377d797f..816b5935 100644 --- a/apps/client/android/app/src/main/AndroidManifest.xml +++ b/apps/client/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,13 @@ xmlns:tools="http://schemas.android.com/tools"> - + + + + diff --git a/apps/client/android/settings.gradle.kts b/apps/client/android/settings.gradle.kts index e28f2041..7984d0cc 100644 --- a/apps/client/android/settings.gradle.kts +++ b/apps/client/android/settings.gradle.kts @@ -34,7 +34,6 @@ plugins { include(":app") include(":azure_speech") include(":chat_storage") -include(":jieli") include(":ble_service") include(":classic_bluetooth") include(":agent_service") @@ -42,13 +41,11 @@ include(":speech") include(":chat_api") include(":bytedance_speech") include(":qq_music") // 添加这行 -include(":jl_opus") include(":bluetooth_manager") // 恒玄(BES)经典蓝牙连接 + G722/mSBC 音频编解码 // 设置项目路径 project(":azure_speech").projectDir = file("../local_plugins/azure_speech/android") project(":chat_storage").projectDir = file("../local_plugins/chat_storage/android") -project(":jieli").projectDir = file("../local_plugins/jieli/android") project(":ble_service").projectDir = file("../local_plugins/ble_service/android") project(":classic_bluetooth").projectDir = file("../local_plugins/classic_bluetooth/android") project(":agent_service").projectDir = file("../local_plugins/agent_service/android") @@ -56,5 +53,4 @@ project(":speech").projectDir = file("../local_plugins/speech/android") project(":chat_api").projectDir = file("../local_plugins/chat_api/android") project(":bytedance_speech").projectDir = file("../local_plugins/bytedance_speech/android") project(":qq_music").projectDir = file("../local_plugins/qq_music/android") // 添加这行 -project(":jl_opus").projectDir = file("../local_plugins/jl_opus/android") project(":bluetooth_manager").projectDir = file("../local_plugins/bluetooth_manager/android") diff --git a/apps/client/assets/images/devices/Echomeet.png b/apps/client/assets/images/devices/Echomeet.png new file mode 100644 index 0000000000000000000000000000000000000000..14a3203b841444a2f2989aa202c0e25c19d38f76 GIT binary patch literal 465812 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�#}ou0gbZPWx6fqgXPJVHBdd7_YRS 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 z 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 z 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 literal 0 HcmV?d00001 diff --git a/apps/client/build_channels.sh b/apps/client/build_channels.sh index 558d7f35..eb02b5c4 100755 --- a/apps/client/build_channels.sh +++ b/apps/client/build_channels.sh @@ -14,7 +14,9 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" ENV_FILE="${SCRIPT_DIR}/.env" PUBSPEC_FILE="${SCRIPT_DIR}/pubspec.yaml" -OUTPUT_DIR="/Users/liuxiamin/work/build_outputs" +# 产物输出目录。默认落在仓库内的 build_outputs/(已在 .gitignore 里), +# 需要放别处时用环境变量覆盖:BUILD_OUTPUT_DIR=/path/to/out ./build_channels.sh google +OUTPUT_DIR="${BUILD_OUTPUT_DIR:-${SCRIPT_DIR}/build_outputs}" APP_NAME="EAIMAR" BUILD_DATE=$(date +"%m%d") @@ -314,7 +316,7 @@ build_channel() { 2>&1 | tee "${OUTPUT_DIR}/build_${channel_name}.log" || build_result=$? source_file="${SCRIPT_DIR}/build/app/outputs/flutter-apk/app-release.apk" else - flutter build aab \ + flutter build appbundle \ --obfuscate \ --split-debug-info=./build/app/outputs/symbols \ 2>&1 | tee "${OUTPUT_DIR}/build_${channel_name}.log" || build_result=$? diff --git a/apps/client/check_16kb.py b/apps/client/check_16kb.py new file mode 100755 index 00000000..8b307b7e --- /dev/null +++ b/apps/client/check_16kb.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +"""校验 APK/AAB 里 64 位 .so 是否满足 Google Play 的 16KB 页对齐要求。 + +Google Play 自 2025-11-01 起要求 64 位原生库(arm64-v8a / x86_64)的每个 +PT_LOAD 段 p_align >= 0x4000(16KB),不合规直接拒收,且**无延期**。 +32 位(armeabi-v7a / x86)不受约束,脚本会列出但不判失败。 + +用法: + python3 check_16kb.py build/app/outputs/bundle/release/app-release.aab + python3 check_16kb.py build/app/outputs/flutter-apk/app-release.apk + +退出码: 0=全部合规, 1=有不合规的 64 位库, 2=用法/文件错误 +""" +import struct +import sys +import zipfile + +REQUIRED_ALIGN = 0x4000 +ABI64 = ("arm64-v8a", "x86_64") + +PT_LOAD = 1 + + +def max_load_align(data: bytes): + """返回 ELF 所有 PT_LOAD 段里最小的 p_align;不是 64 位 ELF 返回 None。""" + if len(data) < 64 or data[:4] != b"\x7fELF": + return None + if data[4] != 2: # EI_CLASS: 2 = ELFCLASS64,32 位不参与判定 + return None + little = data[5] == 1 + end = "<" if little else ">" + + # Elf64_Ehdr: e_phoff@0x20, e_phentsize@0x36, e_phnum@0x38 + (e_phoff,) = struct.unpack_from(end + "Q", data, 0x20) + (e_phentsize,) = struct.unpack_from(end + "H", data, 0x36) + (e_phnum,) = struct.unpack_from(end + "H", data, 0x38) + + aligns = [] + for i in range(e_phnum): + off = e_phoff + i * e_phentsize + if off + 56 > len(data): + break + (p_type,) = struct.unpack_from(end + "I", data, off) + if p_type != PT_LOAD: + continue + # Elf64_Phdr: p_align 是最后一个字段,偏移 0x30 + (p_align,) = struct.unpack_from(end + "Q", data, off + 0x30) + aligns.append(p_align) + return min(aligns) if aligns else None + + +def abi_of(name: str): + for abi in ("arm64-v8a", "armeabi-v7a", "x86_64", "x86"): + if "/%s/" % abi in name: + return abi + return "?" + + +def main(argv): + if len(argv) != 2: + print(__doc__) + return 2 + path = argv[1] + try: + zf = zipfile.ZipFile(path) + except Exception as exc: # noqa: BLE001 + print("无法打开 %s: %s" % (path, exc)) + return 2 + + bad, ok, skipped = [], [], [] + with zf: + for info in zf.infolist(): + if not info.filename.endswith(".so"): + continue + data = zf.read(info.filename) + align = max_load_align(data) + abi = abi_of(info.filename) + if align is None: + # 32 位或非 ELF:不参与 16KB 判定 + skipped.append((info.filename, abi)) + continue + if align < REQUIRED_ALIGN: + bad.append((info.filename, abi, align)) + else: + ok.append((info.filename, abi, align)) + + print("包: %s" % path) + print("64 位 .so 合规 %d 个,不合规 %d 个;32 位/非 ELF 跳过 %d 个\n" + % (len(ok), len(bad), len(skipped))) + + if bad: + print("❌ 不合规(p_align < 0x4000,Play 会拒收):") + for name, abi, align in sorted(bad): + print(" %-60s %-12s p_align=0x%x" % (name, abi, align)) + print("") + print("修法:给产出该库的模块声明 NDK r28+(`ndkVersion`),或在 CMake 里加") + print(" target_link_options( PRIVATE \"-Wl,-z,max-page-size=16384\")") + print(" 改完记得清掉该模块的 android/.cxx 缓存,否则会复用旧产物。") + return 1 + + print("✅ 全部 64 位 .so 均满足 16KB 页对齐") + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) diff --git a/apps/client/ios/Podfile.lock b/apps/client/ios/Podfile.lock index 6dd9dfc3..99ae5440 100644 --- a/apps/client/ios/Podfile.lock +++ b/apps/client/ios/Podfile.lock @@ -11,8 +11,6 @@ PODS: - Flutter - bluetooth_manager (0.0.1): - Flutter - - device_plugin_interface (0.1.0): - - Flutter - floating_ui_plugin (0.0.1): - Flutter - Flutter (1.0.0) @@ -60,7 +58,6 @@ DEPENDENCIES: - audio_waveforms (from `.symlinks/plugins/audio_waveforms/ios`) - bes_ota_manager (from `.symlinks/plugins/bes_ota_manager/ios`) - bluetooth_manager (from `.symlinks/plugins/bluetooth_manager/ios`) - - device_plugin_interface (from `.symlinks/plugins/device_plugin_interface/ios`) - floating_ui_plugin (from `.symlinks/plugins/floating_ui_plugin/ios`) - Flutter (from `Flutter`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) @@ -92,8 +89,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/bes_ota_manager/ios" bluetooth_manager: :path: ".symlinks/plugins/bluetooth_manager/ios" - device_plugin_interface: - :path: ".symlinks/plugins/device_plugin_interface/ios" floating_ui_plugin: :path: ".symlinks/plugins/floating_ui_plugin/ios" Flutter: @@ -126,7 +121,6 @@ SPEC CHECKSUMS: audio_waveforms: cd736909ebc6b6a164eb74701d8c705ce3241e1c bes_ota_manager: 4fcdbe6962548a1ac69421f0c3212837e76c0af4 bluetooth_manager: f09915bb90e61cc30cbf93f1f5b127b86d957e43 - device_plugin_interface: ee316d62288f942bd08a05acdf417ec4671639a7 floating_ui_plugin: d218b25dcd922d3a66a536dd2190ecd47451e5a8 Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 flutter_local_notifications: df98d66e515e1ca797af436137b4459b160ad8c9 diff --git a/apps/client/ios/Runner.xcodeproj/project.pbxproj b/apps/client/ios/Runner.xcodeproj/project.pbxproj index 46cca1d3..9a329526 100644 --- a/apps/client/ios/Runner.xcodeproj/project.pbxproj +++ b/apps/client/ios/Runner.xcodeproj/project.pbxproj @@ -144,7 +144,6 @@ 75F9C6FC394EA5D10CEE9FE1 /* BroadcastExtension.entitlements */, 6C2968D7A4F3A0D478C6EF09 /* Extension.xcconfig */, ); - name = BroadcastExtension; path = BroadcastExtension; sourceTree = ""; }; @@ -642,7 +641,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = B8AJQ7ACU7; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -836,7 +835,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = B8AJQ7ACU7; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -870,7 +869,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = B8AJQ7ACU7; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/apps/client/ios/sync_spm_platform.sh b/apps/client/ios/sync_spm_platform.sh new file mode 100755 index 00000000..0996be7f --- /dev/null +++ b/apps/client/ios/sync_spm_platform.sh @@ -0,0 +1,146 @@ +#!/usr/bin/env bash +# +# 把 Flutter 生成的 SPM 中间包的 iOS 平台版本,对齐到本工程的 deployment target。 +# +# ── 解决什么问题 ──────────────────────────────────────────────────────────── +# Flutter 3.29+ 的 Swift Package Manager 集成会生成 +# ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift +# 所有插件都挂在这个包下面。**它生成时的平台版本写死是 Flutter 自己的最低版本 +# (iOS 13.0)**,而本项目有十几个本地插件声明了 `.iOS("16.0")`。SPM 不允许依赖的 +# 平台版本高于上层包,于是 Xcode 报: +# +# The package product 'xxx' requires minimum platform version 16.0 +# for the iOS platform, but this target supports 13.0 +# +# Flutter 自己有补救(SwiftPackageManager.updateMinimumDeployment:读 Runner 的 +# IPHONEOS_DEPLOYMENT_TARGET 把生成包改写上去),但**只在 `flutter build/run` 里跑**。 +# 而 Xcode 直接构建时,SPM 解析发生在所有 Flutter 步骤之前,看到的还是 13.0 —— 所以 +# `flutter build ios` 能过、Xcode 里点构建就炸。 +# +# ⚠️ 任何重新生成插件清单的操作都会把它打回 13.0:flutter pub get / clean / install、 +# 改完 pubspec 的自动 pub get。也就是说这不是一次性问题,会反复出现。 +# +# ── 怎么用 ────────────────────────────────────────────────────────────────── +# ./ios/sync_spm_platform.sh # 在 apps/client 下随时手动跑,幂等 +# ./ios/sync_spm_platform.sh --check # 只检查不改写,不一致时退出码 1(给 CI 用) +# +# 挂进 Xcode(推荐,省得每次记着手动跑): +# Product → Scheme → Edit Scheme → Build → Pre-actions → + New Run Script Action +# Provide build settings from: Runner +# 脚本内容: "$SRCROOT/sync_spm_platform.sh" +# +# ⚠️ 不依赖 flutter 命令:Xcode 的 pre-action 环境 PATH 很干净,调 flutter 经常找不到。 +# 这里只做纯文本改写,几毫秒完成。代价是生成包必须已经存在(跑过一次 +# flutter pub get 即可),不存在时脚本会明确告诉你先跑什么。 +# +# ⚠️ 别改 Package.swift 本身来"修好"这个问题——它头上写着 Generated file. Do not edit., +# 下次 pub get 就被覆盖,属于假修好。本脚本做的是同一件事,但可重复执行。 + +# ⚠️ macOS 自带 bash 3.2 不认多字节字符边界:`$VAR,` 会被当成变量名 `VAR,`, +# 在 set -u 下报 unbound variable。所以本文件里凡是变量后面紧跟中文标点的, +# 一律写成 ${VAR}。 +set -euo pipefail + +IOS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CLIENT_DIR="$(cd "$IOS_DIR/.." && pwd)" +PBXPROJ="$IOS_DIR/Runner.xcodeproj/project.pbxproj" +MANIFEST="$IOS_DIR/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift" + +CHECK_ONLY=0 +[[ "${1:-}" == "--check" ]] && CHECK_ONLY=1 + +red() { printf "\033[31m%s\033[0m\n" "$*"; } +green() { printf "\033[32m%s\033[0m\n" "$*"; } +blue() { printf "\033[34m%s\033[0m\n" "$*"; } + +# 把 .iOS(.v16) / .iOS("16.0") / 16 统一成可比较的 x.y 形式 +normalize() { + local v="$1" + v="${v#.v}" # .v16 → 16 + v="${v//\"/}" # 去引号 + [[ "$v" == *.* ]] || v="$v.0" # 16 → 16.0 + printf '%s' "$v" +} + +# 版本比较:$1 <= $2 ? +le() { [[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -1)" == "$1" ]]; } + +[[ -f "$PBXPROJ" ]] || { red "✗ 找不到 $PBXPROJ"; exit 1; } + +# ── 1) 工程能接受的上限 ───────────────────────────────────────────────────── +# 生成包的平台版本必须 ≤ 每个链接它的 target,所以取全工程最低的那个 deployment target。 +CEILING="$(grep -o 'IPHONEOS_DEPLOYMENT_TARGET = [0-9.]*' "$PBXPROJ" \ + | awk '{print $3}' | sed 's/;$//' | sort -V | head -1)" +[[ -n "$CEILING" ]] || { red "✗ 没能从 project.pbxproj 读出 IPHONEOS_DEPLOYMENT_TARGET"; exit 1; } +CEILING="$(normalize "$CEILING")" + +# ── 2) 插件要求的下限 ─────────────────────────────────────────────────────── +# 扫本地插件的 Package.swift,取声明得最高的那个。 +FLOOR="0.0"; FLOOR_OWNER="" +while IFS= read -r f; do + raw="$(grep -o '\.iOS([^)]*)' "$f" | head -1 | sed 's/^\.iOS(//; s/)$//')" || true + [[ -n "$raw" ]] || continue + v="$(normalize "$raw")" + if ! le "$v" "$FLOOR"; then FLOOR="$v"; FLOOR_OWNER="${f#"$CLIENT_DIR"/}"; fi +done < <(find "$CLIENT_DIR/local_plugins" -name Package.swift -not -path '*/.*' 2>/dev/null | sort) + +blue "工程 deployment target(取最低) = ${CEILING} 本地插件最高要求 = ${FLOOR}${FLOOR_OWNER:+ (${FLOOR_OWNER})}" + +# ── 3) 插件要求超过工程上限 = 真问题,脚本救不了,直接点名 ─────────────────── +if ! le "$FLOOR" "$CEILING"; then + red "✗ 插件要求 iOS ${FLOOR},但工程最低 target 只有 ${CEILING} —— 这个脚本改不了。" + red " 要么把工程的 IPHONEOS_DEPLOYMENT_TARGET 抬到 ${FLOOR}(Runner + Podfile 都要)," + red " 要么把 ${FLOOR_OWNER} 的平台声明降下来。" + exit 1 +fi + +# ── 4) 对齐生成包 ─────────────────────────────────────────────────────────── +if [[ ! -f "$MANIFEST" ]]; then + red "✗ 生成包还不存在:${MANIFEST#"$CLIENT_DIR"/}" + red " 先在 apps/client 下跑一次 \`flutter pub get\`(或 \`flutter build ios --config-only\`)再执行本脚本。" + exit 1 +fi + +# ── 本地插件之间的相对路径依赖 ──────────────────────────────────────────── +# 若干本地插件的 Package.swift 用 `../../..//ios/` 引用兄弟插件 +# (agent_service→test、azure_speech→classic_bluetooth、recorder_holder→device_jieli、 +# chat_api→swift_sdk_local)。这些路径是按 `local_plugins//ios/` 的真实 +# 目录写的,但 Flutter 把插件以符号链接挂在 `ephemeral/Packages/.packages/` 下, +# SPM 不解析符号链接,`../../..` 就落到了 `ephemeral/`——于是报 +# "the package at 'ephemeral//ios/' cannot be accessed"。 +# 这里在 ephemeral/ 下给每个本地插件目录补一个同名链接,让那些相对路径能落地。 +# 幂等;`flutter pub get` 不会清掉它们。 +ensure_local_plugin_links() { + local eph="$IOS_DIR/Flutter/ephemeral" + local plugins_dir="$CLIENT_DIR/local_plugins" + [ -d "$eph" ] || return 0 + for d in "$plugins_dir"/*/; do + local name + name="$(basename "$d")" + [ -e "$eph/$name" ] && continue + ln -s "../../../local_plugins/$name" "$eph/$name" + done +} +ensure_local_plugin_links + +CURRENT_RAW="$(grep -o '\.iOS([^)]*)' "$MANIFEST" | head -1 | sed 's/^\.iOS(//; s/)$//')" +CURRENT="$(normalize "$CURRENT_RAW")" + +if [[ "$CURRENT" == "$CEILING" ]]; then + green "✓ 生成包已是 iOS ${CURRENT},无需改动" + exit 0 +fi + +if [[ $CHECK_ONLY -eq 1 ]]; then + red "✗ 生成包是 iOS ${CURRENT},应为 ${CEILING}(跑 ./ios/sync_spm_platform.sh 修)" + exit 1 +fi + +# 只替换 platforms 段里的第一个 .iOS(...),不碰文件其余内容 +/usr/bin/sed -i '' "s/\.iOS($(printf '%s' "$CURRENT_RAW" | sed 's/[.[\*^$\/]/\\&/g'))/.iOS(\"$CEILING\")/" "$MANIFEST" + +NEW="$(normalize "$(grep -o '\.iOS([^)]*)' "$MANIFEST" | head -1 | sed 's/^\.iOS(//; s/)$//')")" +if [[ "$NEW" != "$CEILING" ]]; then + red "✗ 改写失败,现在是 ${NEW}"; exit 1 +fi +green "✓ 生成包平台版本 ${CURRENT} → ${CEILING},可以回 Xcode 构建了" diff --git a/apps/client/lib/core/bindings/initial_binding.dart b/apps/client/lib/core/bindings/initial_binding.dart index 6f965f9b..8b32d93f 100644 --- a/apps/client/lib/core/bindings/initial_binding.dart +++ b/apps/client/lib/core/bindings/initial_binding.dart @@ -16,21 +16,20 @@ import '../../data/services/speech_factory.dart'; import '../../data/services/alibaba_image_translation_service.dart'; import '../../data/services/assistant_directive_service.dart'; import '../../data/services/bailian_multimodal_service.dart'; -import '../../data/services/bes_ai_session_service.dart'; import '../../data/services/emai_chat_store.dart'; import '../../data/services/id_verify_service.dart'; import '../../data/services/microsoft_translation_service.dart'; import '../../data/services/server_translation_service.dart'; import '../../data/services/language_manager.dart'; import '../../core/utils/logger.dart'; -import '../../data/services/bluetooth_manager.dart'; -import '../../data/services/ble_manager.dart'; -import '../../data/services/bes_bluetooth_service.dart'; -import '../../data/services/holder_device_service.dart'; -import '../../data/services/holder_recording_service.dart'; -import '/data/services/bes_recording_service.dart'; -import '/data/services/bes_call_recording_service.dart'; -import '/data/services/face_to_face_ble_service.dart'; +import '../../data/services/agent_module_defaults.dart'; +import '../../data/services/device_ai_session_service.dart'; +import '../../data/services/device_call_recording_service.dart'; +import '../../data/services/device_file_import_service.dart'; +import '../../data/services/device_recording_service.dart'; +import '../../devices/device_bootstrap.dart'; +import '../../devices/device_hub.dart'; +import '../../modules/module_registry.dart'; import '../services/ai_orb_controller.dart'; import '../../data/services/account_service.dart'; import '../../data/services/memory_reminder_scheduler.dart'; @@ -83,31 +82,30 @@ class InitialBinding extends Bindings { // 会话都往它送指令,代办页又要读它,任何一方被回收都会丢记录。 Get.put(AssistantDirectiveService(), permanent: true); + // Agent 能力模块注册表:路由/跳转/指令/文案/常驻服务都由模块自带 + ModuleRegistry.install(); + ModuleRegistry.registerServices(); + AssistantDirectiveService.to + .registerHandlers(ModuleRegistry.directiveHandlers); // 阿里通义千问 VL:拍照翻译(识别 + 翻译一次完成) Get.lazyPut( () => AlibabaImageTranslationService(), fenix: true); - // BleManager —— 提前 put(不用 lazyPut),让原生杰理 SDK 在 onInit 里立即开始 initialize - Get.put(BleManager(), permanent: true); - // 蓝牙服务(经典蓝牙系统状态观测,仅用于通话音频路由判断) - Get.lazyPut(() => BluetoothManager(), fenix: true); - // 恒玄(BES)蓝牙服务:经典蓝牙 SPP 主动连接 + 音频编解码,独立于杰理 BLE 链路 - // 常驻:状态监听与冷启动自动回连都要在任意页面生效 - Get.put(BesBluetoothService(), permanent: true); - // 蓝讯方案设备(AI手机支架 / AI Pencil):BLE 连接 + Opus 录音流, - // 协议实现来自 echomeet 的 recorder_holder 插件 - Get.put(HolderDeviceService(), permanent: true); - // 支架录音的全局采集/归档:设备端按键在任意页面(含页面未打开)都生效, - // 所以必须常驻,不能挂在录音页控制器上 - Get.put(HolderRecordingService(), permanent: true); - // 恒玄耳机录音的全局采集/归档,与支架那条完全独立 - Get.put(BesRecordingService(), permanent: true); - // 恒玄耳机通话录音(双声道:左本端 / 右对端),跟随通话状态自动起停 - Get.put(BesCallRecordingService(), + // 设备中枢:注册所有厂商插件(恒玄耳机 / EaiRec 支架 / …),业务层只认它。 + // 常驻:状态监听与冷启动自动回连都要在任意页面生效。 + installDeviceHub(); + // 设备品类首次连上时把默认功能铺到 AI 页 + AgentDefaults.bind(DeviceHub.to); + // 设备主麦录音(现场录音)的全局采集/归档:设备端按键在任意页面都生效 + Get.put(DeviceRecordingService(), permanent: true); + // 通话录音(双声道:左本端 / 右对端),跟随通话状态自动起停 + Get.put(DeviceCallRecordingService(), + permanent: true); + // 把「设备自己录在 TF 卡 / flash 里的音频」同步进语音纪要。 + // 常驻:支架连上(含后台自动回连)就该开始同步,不能等用户进某个页面。 + Get.put(DeviceFileImportService(), permanent: true); - // 面对面翻译的左右耳独立 BLE(底层待固件命令,先占好位) - Get.put(FaceToFaceBleService(), permanent: true); // EMAI 对话记录:手机页面与耳机会话共用一份,必须先于 BesAiSessionService // 注册(后者一起来就可能收到耳机唤醒并往里写) Get.put(EmaiChatStore(), permanent: true); @@ -115,9 +113,9 @@ class InitialBinding extends Bindings { // 实名认证状态:AI 页闸门与「我的」页都读它,全局常驻。 // onInit 里会自动拉一次服务端状态(游客跳过)。 Get.put(IdVerifyService(), permanent: true); - // 恒玄耳机按键唤醒的 AI 实时对话(接百炼多模态)。必须常驻: - // 耳机按键在任意页面、甚至 App 在后台时都要能起会话 - Get.put(BesAiSessionService(), permanent: true); + // 设备按键唤醒的 AI 实时对话(接百炼多模态)。必须常驻: + // 按键在任意页面、甚至 App 在后台时都要能起会话 + Get.put(DeviceAiSessionService(), permanent: true); // MusicManager Get.lazyPut(() => MusicManager(), fenix: true); diff --git a/apps/client/lib/core/services/ai_orb_controller.dart b/apps/client/lib/core/services/ai_orb_controller.dart index feb506a7..8724a5e6 100644 --- a/apps/client/lib/core/services/ai_orb_controller.dart +++ b/apps/client/lib/core/services/ai_orb_controller.dart @@ -21,7 +21,6 @@ class AiOrbController extends GetxController { static const Set _hiddenRoutes = { Routes.splash, Routes.login, - Routes.agent, Routes.emai, Routes.mobileElf, }; diff --git a/apps/client/lib/core/translations/app_translations.dart b/apps/client/lib/core/translations/app_translations.dart index 2395cfbf..90a8e8b1 100644 --- a/apps/client/lib/core/translations/app_translations.dart +++ b/apps/client/lib/core/translations/app_translations.dart @@ -3,6 +3,8 @@ import 'dart:ui'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; +import '../../modules/module_registry.dart'; + import 'language/en_us.dart'; // 英语 import 'language/zh_cn.dart'; // 简体中文 import 'language/es_es.dart'; // 西班牙语 @@ -302,8 +304,12 @@ class AppTranslations extends Translations { return fallbackLocale; } + /// 全局语言表 + 各能力模块自带的文案(见 ModuleRegistry.mergeTranslations) @override - Map> get keys => { + Map> get keys => + ModuleRegistry.mergeTranslations(_base); + + static final Map> _base = { 'en_US': enUS, 'zh_CN': zhCN, 'zh_HK': zhHK, // 添加繁体中文映射 diff --git a/apps/client/lib/core/translations/language/ar_sa.dart b/apps/client/lib/core/translations/language/ar_sa.dart index 7f67e3d0..0b0ac548 100644 --- a/apps/client/lib/core/translations/language/ar_sa.dart +++ b/apps/client/lib/core/translations/language/ar_sa.dart @@ -1868,4 +1868,208 @@ const Map arSA = { 'unmarkFavorite': 'إزالة من المفضلة', 'unnamedDevice': 'جهاز بلا اسم', 'userDataParseFailed': 'تعذّر تحليل بيانات المستخدم', + 'catEarphone': 'سماعات ذكية', + 'catEarphoneDesc': 'سماعات بلوتوث كلاسيكي / BLE', + 'catPhoneHolder': 'حامل هاتف ذكي', + 'catPhoneHolderDesc': 'أجهزة الحوامل', + 'catCarAroma': 'معطر سيارة ذكي', + 'catCarAromaDesc': 'موزع عطر للسيارة', + 'agreeAndContinue': 'موافقة ومتابعة', + 'memberServiceAgreement': 'اتفاقية خدمة العضوية', + 'memberServiceAgreementTitle': 'اتفاقية خدمة العضوية', + 'memberServiceAgreementIntro': 'لتقديم خدمات عضوية أفضل لك، يرجى القراءة بعناية قبل الاشتراك: ', + 'memberServiceAgreementOutro': '. بالنقر على «موافقة ومتابعة» فإنك تؤكد أنك قرأت الاتفاقية أعلاه بالكامل ووافقت عليها.', + 'memberAgreementRejectedTip': 'يجب الموافقة على اتفاقية خدمة العضوية للمتابعة.', + 'translationCallExitTitle': 'الخروج من ترجمة المكالمة', + 'translationCallExitMessage': 'اختر ما تريد فعله قبل المغادرة', + 'translationCallEnd': 'إنهاء ترجمة المكالمة', + 'translationContinueInBackground': 'متابعة الترجمة في الخلفية', + 'backgroundRecordingIndicatorBody': 'التسجيل مستمر في الخلفية. اضغط للعودة.', + 'backgroundTranslationIndicatorBody': 'ترجمة المكالمة مستمرة في الخلفية. اضغط للعودة.', + 'meetingRecordScreenCapturePermissionDenied': 'إذن تسجيل الشاشة مطلوب لالتقاط صوت النظام. يرجى منحه ثم إعادة المحاولة.', + 'pleaseGrantBluetoothPermission': 'يرجى منح إذن البلوتوث للمسح', + 'startScanFailed': 'فشل بدء المسح', + 'pleaseLoginFirst': 'يرجى تسجيل الدخول أولاً', + 'deviceUnauthorized': 'الجهاز غير مصرح به، يرجى إعادة المحاولة', + 'boundDevices': 'الأجهزة المرتبطة', + 'currentConnection': 'الاتصال الحالي', + 'binding': 'جارٍ الربط...', + 'permissionDisabled': 'معطّل', + 'confirmDisablePermissionTitle': 'إيقاف الإذن', + 'confirmDisablePermissionContent': 'هل تريد إيقاف إذن {permission}؟ ستحتاج إلى الذهاب إلى إعدادات النظام لإعادة تفعيله.', + 'confirmPermanentlyDisallowTitle': 'التوقف عن السؤال؟', + 'confirmPermanentlyDisallowContent': 'لقد رفضت إذن {permission}. هل تريد التوقف عن السؤال من الآن فصاعداً؟ إذا اخترت «عدم السماح»، يمكنك تفعيله لاحقاً من إعدادات النظام.', + 'notNow': 'ليس الآن', + 'permanentlyDisallow': 'عدم السماح', + 'otaBesNotSupported': 'هذه السماعة لا تدعم ترقية البرنامج الثابت داخل التطبيق بعد. يرجى التواصل مع الدعم.', + 'tabDevice': 'الأجهزة', + 'tabPlaza': 'الساحة', + 'sloganHome': 'تقنية لحياة أذكى', + 'sloganAi': 'ذكاء بلا حدود', + 'sloganDevice': 'أجهزة ذكية جاهزة للمستقبل', + 'sloganPlaza': 'عالم ذكي يفهمك', + 'aiEditHint': 'اضغط مطولاً على بطاقة لسحبها وإعادة ترتيب الوحدات', + 'aiEmptyTitle': 'لم تتم إضافة أي وحدات بعد', + 'aiEmptyDesc': 'اختر الوكلاء الذين تحتاجهم من الساحة', + 'goToPlaza': 'الذهاب إلى الساحة', + 'plazaOnline': 'متاح', + 'plazaPlanned': 'قريباً', + 'plazaSearchHint': 'ابحث عن الوكلاء، مثل «ترجمة» أو «تسجيل»', + 'moduleRemove': 'إزالة', + 'moduleAdd': 'إضافة', + 'moduleRemoved': 'تمت الإزالة', + 'moduleAdded': 'تمت الإضافة', + 'goSee': 'عرض', + 'comingSoonTag': 'قريباً', + 'needDeviceTag': 'يتطلب جهازاً', + 'featureInDev': 'هذه الميزة قيد التطوير', + 'featureNotWired': 'غير متاح بعد', + 'todayLabel': 'اليوم', + 'deviceConnected': 'متصل', + 'licenseUnknown': 'الترخيص غير معروف', + 'selectDevice': 'اختر جهازاً', + 'catNoteCard': 'بطاقة تسجيل AI', + 'catNoteCardDesc': 'مسجّل على شكل بطاقة', + 'catParkerPen': 'قلم AI', + 'catParkerPenDesc': 'أقلام تسجيل صوتي', + 'catStylusPen': 'قلم لمس AI', + 'catStylusPenDesc': 'أجهزة الكتابة اليدوية / أقلام اللمس', + 'catStudyMachine': 'لوح تعلّم AI', + 'catStudyMachineDesc': 'أجهزة التعلّم', + 'besAddTitle': 'إضافة سماعات AI', + 'besConnecting': 'جارٍ الاتصال بالسماعات…', + 'besNotFound': 'لم يتم العثور على السماعات', + 'besNotFoundIosDesc': 'قم بتوصيل السماعات أولاً من الإعدادات ← البلوتوث، ثم عد إلى هنا', + 'besNotFoundAndroidDesc': 'قم بإقران السماعات أولاً من الإعدادات ← البلوتوث، ثم اتصل من هنا', + 'besReadFailed': 'فشلت القراءة', + 'besConnectFailIos': 'تأكد من ظهور السماعات بحالة «متصل» في بلوتوث النظام، ثم أعد المحاولة', + 'besConnectFailAndroid': 'تأكد من أن السماعات قيد التشغيل وقريبة وغير متصلة بجهاز آخر. ستعيد الاتصال تلقائياً بمجرد الارتباط.', + 'holderAddTitle': 'إضافة حامل هاتف AI', + 'holderConnecting': 'جارٍ الاتصال بالجهاز…', + 'holderSearching': 'جارٍ البحث عن الأجهزة…', + 'holderNotFound': 'لم يتم العثور على أجهزة', + 'holderPairHint': 'تأكد من أن الحامل قيد التشغيل وفي وضع الإقران', + 'holderRetryHint': 'تأكد من أن الجهاز قيد التشغيل وقريب منك، ثم أعد المحاولة', + 'autoConnectTitle': 'الاتصال التلقائي بالأجهزة', + 'autoConnectDesc': 'إيقاظ التطبيق لإعادة الاتصال واستقبال التسجيلات عند تشغيل جهازك أو اقترابه', + 'autoConnectConsentTitle': 'تفعيل الاتصال التلقائي', + 'autoConnectConsentIntro': 'للسماح لجهازك (سماعات AI / حامل هاتف AI) بالاتصال تلقائياً وحفظ التسجيلات عند الضغط على زر التسجيل فيه، نحتاج إلى موافقتك:', + 'autoConnectConsentB1': 'تسجيل مسح بلوتوث في الخلفية بحيث يتم إيقاظ التطبيق (بدء تلقائي) عند اكتشاف جهازك المرتبط، لإعادة الاتصال واستقبال التسجيلات', + 'autoConnectConsentB2': 'بعد الإيقاظ، يُستخدم فقط لاتصال الجهاز والتسجيل والرفع — لا شيء آخر، ولا يتم تشغيل أي تطبيقات أخرى', + 'autoConnectConsentB3': 'يمكنك الاستمرار في استخدام التطبيق بدونه — فقط اتصل بالجهاز يدوياً في كل مرة', + 'autoConnectConsentB4': 'يمكنك إيقافه في أي وقت من الإعدادات ← الاتصال التلقائي بالأجهزة', + 'autoConnectAgree': 'موافقة وتفعيل', + 'autoConnectLater': 'ليس الآن', + 'autoConnectRequired': 'الاتصال التلقائي متوقف', + 'autoConnectRequiredDesc': 'فعّل الاتصال التلقائي لربط هذا الجهاز', + 'recordTapToStart': 'اضغط على الزر أدناه لبدء التسجيل', + 'recordPaused': 'متوقف مؤقتاً', + 'recordMark': 'علامة', + 'recordDeleteTitle': 'حذف التسجيل', + 'accountAndProfile': 'الحساب والملف الشخصي', + 'nicknameUnset': 'لم يتم تعيين لقب', + 'nicknameInput': 'أدخل لقباً', + 'loginMethod': 'طريقة تسجيل الدخول', + 'manageMyLogin': 'إدارة تسجيل الدخول', + 'logoutAction': 'تسجيل الخروج', + 'warningLabel': 'تحذير:', + 'deleteAccountWarn': 'سيتم حذف حسابك وجميع ملفاتك نهائياً.', + 'icpFiling': 'تسجيل ICP', + 'logExport': 'تصدير السجلات', + 'logExportDesc': 'عرض سجلات التطبيق وتصديرها', + 'permLoadFailed': 'فشل تحميل مجموعات الأذونات', + 'permInsufficient': 'تم رفض الإذن', + 'voiceCloneCreating': 'جارٍ إنشاء صوتك…', + 'voiceCloneCreate': 'إنشاء صوتي', + 'voiceCloneAgree': 'الموافقة وقراءة البيان بصوت عالٍ', + 'voiceCloneReadPrompt': 'يرجى قراءة:', + 'voiceCloneFirstMonthFree': 'الشهر الأول مجاناً', + 'voiceCloneEnable': 'تفعيل استنساخ الصوت', + 'noMusicPlaying': 'لا يوجد شيء قيد التشغيل', + 'qqMusicNoSeek': 'التقديم غير مدعوم في QQ Music', + 'bleScanTitle': 'مسح BLE', + 'bluetoothOn': 'البلوتوث مفعّل', + 'bleScanning': 'جارٍ المسح…', + 'bleConnectedDevices': 'الأجهزة المتصلة', + 'bleUnknownDevice': 'جهاز غير معروف', + 'bleTapToScan': 'اضغط على مسح للبحث عن أجهزة BLE', + 'weekMon': 'الاثنين', + 'weekTue': 'الثلاثاء', + 'weekWed': 'الأربعاء', + 'weekThu': 'الخميس', + 'weekFri': 'الجمعة', + 'weekSat': 'السبت', + 'weekSun': 'الأحد', + 'agentMeeting': 'محاضر صوتية', + 'agentMeetingDesc': 'تلخيص التسجيلات ومركز الذاكرة', + 'agentEmai': 'مساعد EMAI', + 'agentEmaiDesc': 'تحدث واسأل أي شيء بصوتك', + 'agentSimultaneous': 'الترجمة الفورية', + 'agentSimultaneousDesc': 'ترجمة أثناء حديثك', + 'agentFaceToFace': 'وجهاً لوجه', + 'agentFaceToFaceDesc': 'ترجمة محادثة ثنائية الاتجاه', + 'agentCallRecording': 'تسجيل المكالمات', + 'agentCallRecordingDesc': 'حفظ المكالمات تلقائياً', + 'agentFieldRecording': 'التسجيل الميداني', + 'agentFieldRecordingDesc': 'ميكروفون الجهاز أو الهاتف', + 'agentCall': 'ترجمة المكالمات', + 'agentCallDesc': 'ترجمة فورية أثناء المكالمات', + 'agentAudioVideo': 'ترجمة الوسائط', + 'agentAudioVideoDesc': 'تأطير الكاميرا / ترجمة الصوت والفيديو', + 'agentEnglishChat': 'محادثة بالإنجليزية', + 'agentEnglishChatDesc': 'تدريب غامر على التحدث', + 'agentEnglishStudy': 'دراسة الإنجليزية', + 'agentEnglishStudyDesc': 'دروس المفردات والقواعد', + 'agentKidsStory': 'قصص الأطفال', + 'agentKidsStoryDesc': 'قصص ما قبل النوم وأسئلة وأجوبة', + 'moduleRemovedDesc': 'تمت إزالته من صفحة AI', + 'moduleAddedDesc': 'تمت إضافته إلى أسفل صفحة AI', + 'calNoRecords': 'لا توجد إدخالات', + 'calNoRecordsDay': 'لا يوجد شيء مجدول', + 'calTodos': 'المهام', + 'calExpenses': 'المصروفات', + 'calTodoCount': '@count مهام', + 'calExpenseCount': '@count مصروفات', + 'calEntryCount': '@count إدخالات', + 'calItemsUnit': 'عناصر', + 'calCountUnit': 'إدخالات', + 'calTotalAmount': 'الإجمالي', + 'recordPause': 'إيقاف مؤقت', + 'recordResume': 'استئناف', + 'recordDeleteConfirm': 'حذف هذا التسجيل؟', + 'scopeDay': 'يوم', + 'scopeWeek': 'أسبوع', + 'scopeMonth': 'شهر', + 'allDay': 'طوال اليوم', + 'guestModeTitle': 'وضع الضيف', + 'guestModeDesc': 'يمكن للضيوف التصفح فقط. سجّل الدخول لاستخدام الملاحظات الصوتية والترجمة والتسجيل — وسيتم حفظ بياناتك في حسابك.', + 'guestKeepBrowsing': 'متابعة التصفح', + 'guestGoLogin': 'تسجيل الدخول', + 'guestViewOnlyTag': 'للعرض فقط', + 'autoConnectReenableHint': 'الاتصال التلقائي متوقف. أعد تفعيله من الإعدادات ← الاتصال التلقائي بالأجهزة.', + 'plazaEntryDesc': 'تصفح وأضف المزيد من الوكلاء', + 'agentTextTranslation': 'ترجمة النصوص', + 'agentTextTranslationDesc': 'ترجمة النص المكتوب أو الملصق', + 'agentPictureTranslation': 'ترجمة الصور', + 'agentPictureTranslationDesc': 'التقط صورة أو اختر واحدة لترجمتها', + 'callRequiredTitle': 'يتطلب مكالمة', + 'callRequiredDesc': 'تعمل هذه الميزة أثناء المكالمة فقط', + 'inCallBusyTitle': 'غير متاح أثناء المكالمة', + 'inCallBusyDesc': 'الميكروفون ومسار الصوت مشغولان بالمكالمة. حاول مرة أخرى بعد إنهاء المكالمة.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'مجاني', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/bg_bg.dart b/apps/client/lib/core/translations/language/bg_bg.dart index ee28a3c8..9b789b04 100644 --- a/apps/client/lib/core/translations/language/bg_bg.dart +++ b/apps/client/lib/core/translations/language/bg_bg.dart @@ -1931,4 +1931,208 @@ const Map bgBG = { 'unmarkFavorite': 'Премахни от любими', 'unnamedDevice': 'Устройство без име', 'userDataParseFailed': 'Данните на потребителя не бяха разчетени', + 'catEarphone': 'AI слушалки', + 'catEarphoneDesc': 'Класически Bluetooth / BLE слушалки', + 'catPhoneHolder': 'AI стойка за телефон', + 'catPhoneHolderDesc': 'Устройства тип стойка', + 'catCarAroma': 'AI ароматизатор за кола', + 'catCarAromaDesc': 'Ароматизатор за автомобил', + 'agreeAndContinue': 'Приемам и продължавам', + 'memberServiceAgreement': 'Споразумение за членски услуги', + 'memberServiceAgreementTitle': 'Споразумение за членски услуги', + 'memberServiceAgreementIntro': 'За да ви предоставим по-добри членски услуги, моля, прочетете внимателно, преди да се абонирате: ', + 'memberServiceAgreementOutro': '. С натискане на „Приемам и продължавам“ потвърждавате, че сте прочели изцяло и приемате горното споразумение.', + 'memberAgreementRejectedTip': 'Трябва да приемете Споразумението за членски услуги, за да продължите.', + 'translationCallExitTitle': 'Изход от превода на разговор', + 'translationCallExitMessage': 'Изберете какво да направите, преди да излезете', + 'translationCallEnd': 'Край на превода на разговор', + 'translationContinueInBackground': 'Продължи превода във фонов режим', + 'backgroundRecordingIndicatorBody': 'Записът продължава във фонов режим. Натиснете, за да се върнете.', + 'backgroundTranslationIndicatorBody': 'Преводът на разговора продължава във фонов режим. Натиснете, за да се върнете.', + 'meetingRecordScreenCapturePermissionDenied': 'Необходимо е разрешение за запис на екрана, за да се записва системното аудио. Моля, разрешете го и опитайте отново.', + 'pleaseGrantBluetoothPermission': 'Моля, разрешете достъп до Bluetooth за сканиране', + 'startScanFailed': 'Неуспешно стартиране на сканирането', + 'pleaseLoginFirst': 'Моля, първо влезте', + 'deviceUnauthorized': 'Устройството не е оторизирано, опитайте отново', + 'boundDevices': 'Обвързани устройства', + 'currentConnection': 'Текуща връзка', + 'binding': 'Обвързване...', + 'permissionDisabled': 'Изключено', + 'confirmDisablePermissionTitle': 'Изключване на разрешение', + 'confirmDisablePermissionContent': 'Да се изключи ли разрешението {permission}? Ще трябва да го включите отново от системните настройки.', + 'confirmPermanentlyDisallowTitle': 'Спиране на запитванията?', + 'confirmPermanentlyDisallowContent': 'Отказахте разрешението {permission}. Да спрем ли да питаме занапред? Ако изберете „Не разрешавай“, пак можете да го включите по-късно от системните настройки.', + 'notNow': 'Не сега', + 'permanentlyDisallow': 'Не разрешавай', + 'otaBesNotSupported': 'Тези слушалки все още не поддържат обновяване на фърмуера от приложението. Моля, свържете се с поддръжката.', + 'tabDevice': 'Устройства', + 'tabPlaza': 'Площад', + 'sloganHome': 'Технология за по-умен живот', + 'sloganAi': 'Безграничен интелект', + 'sloganDevice': 'Умен хардуер, готов за бъдещето', + 'sloganPlaza': 'Умен свят, който те разбира', + 'aiEditHint': 'Задръжте карта, за да плъзнете и пренаредите модулите', + 'aiEmptyTitle': 'Все още няма добавени модули', + 'aiEmptyDesc': 'Изберете нужните агенти в Площад', + 'goToPlaza': 'Към Площад', + 'plazaOnline': 'Наличен', + 'plazaPlanned': 'Очаквайте скоро', + 'plazaSearchHint': 'Търсене на агенти, напр. „превод“, „запис“', + 'moduleRemove': 'Премахни', + 'moduleAdd': 'Добави', + 'moduleRemoved': 'Премахнато', + 'moduleAdded': 'Добавено', + 'goSee': 'Виж', + 'comingSoonTag': 'Очаквайте скоро', + 'needDeviceTag': 'Изисква устройство', + 'featureInDev': 'Тази функция е в разработка', + 'featureNotWired': 'Все още не е налична', + 'todayLabel': 'Днес', + 'deviceConnected': 'Свързано', + 'licenseUnknown': 'Неизвестен лиценз', + 'selectDevice': 'Изберете устройство', + 'catNoteCard': 'AI карта за запис', + 'catNoteCardDesc': 'Рекордер с форма на карта', + 'catParkerPen': 'AI писалка', + 'catParkerPenDesc': 'Писалки с диктофон', + 'catStylusPen': 'AI стилус', + 'catStylusPenDesc': 'Устройства за ръкопис / стилус', + 'catStudyMachine': 'AI таблет за учене', + 'catStudyMachineDesc': 'Устройства за обучение', + 'besAddTitle': 'Добавяне на AI слушалки', + 'besConnecting': 'Свързване със слушалките…', + 'besNotFound': 'Слушалките не са намерени', + 'besNotFoundIosDesc': 'Първо свържете слушалките в Настройки → Bluetooth, след което се върнете тук', + 'besNotFoundAndroidDesc': 'Първо сдвоете слушалките в Настройки → Bluetooth, след което ги свържете тук', + 'besReadFailed': 'Неуспешно четене', + 'besConnectFailIos': 'Уверете се, че слушалките са показани като „Свързани“ в системния Bluetooth, след което опитайте отново', + 'besConnectFailAndroid': 'Уверете се, че слушалките са включени, наблизо и не са свързани с друго устройство. След свързване ще се свързват отново автоматично.', + 'holderAddTitle': 'Добавяне на AI стойка за телефон', + 'holderConnecting': 'Свързване с устройството…', + 'holderSearching': 'Търсене на устройства…', + 'holderNotFound': 'Не са намерени устройства', + 'holderPairHint': 'Уверете се, че стойката е включена и в режим на сдвояване', + 'holderRetryHint': 'Уверете се, че устройството е включено и наблизо, след което опитайте отново', + 'autoConnectTitle': 'Автоматично свързване на устройства', + 'autoConnectDesc': 'Събужда приложението, за да се свърже отново и да получи записите, когато устройството ви се включи или е наблизо', + 'autoConnectConsentTitle': 'Включване на автоматичното свързване', + 'autoConnectConsentIntro': 'За да може устройството ви (AI слушалки / AI стойка за телефон) да се свързва автоматично и да запазва записи при натискане на бутона му за запис, ни е нужно вашето съгласие:', + 'autoConnectConsentB1': 'Регистриране на фоново Bluetooth сканиране, за да се събуди (стартира автоматично) приложението при откриване на обвързаното ви устройство, да се свърже отново и да получи записите', + 'autoConnectConsentB2': 'След събуждане се използва само за свързване с устройството, запис и качване — нищо друго, и не се стартират други приложения', + 'autoConnectConsentB3': 'Можете да използвате приложението и без това — просто свързвайте устройството ръчно всеки път', + 'autoConnectConsentB4': 'Можете да го изключите по всяко време в Настройки → Автоматично свързване на устройства', + 'autoConnectAgree': 'Приемам и включвам', + 'autoConnectLater': 'Не сега', + 'autoConnectRequired': 'Автоматичното свързване е изключено', + 'autoConnectRequiredDesc': 'Включете автоматичното свързване, за да обвържете това устройство', + 'recordTapToStart': 'Натиснете бутона по-долу, за да започнете запис', + 'recordPaused': 'На пауза', + 'recordMark': 'Маркер', + 'recordDeleteTitle': 'Изтриване на запис', + 'accountAndProfile': 'Акаунт и профил', + 'nicknameUnset': 'Няма зададен прякор', + 'nicknameInput': 'Въведете прякор', + 'loginMethod': 'Начин на вход', + 'manageMyLogin': 'Управление на входа', + 'logoutAction': 'Излизане', + 'warningLabel': 'Предупреждение:', + 'deleteAccountWarn': 'Вашият акаунт и всички файлове ще бъдат изтрити завинаги.', + 'icpFiling': 'ICP регистрация', + 'logExport': 'Експорт на логове', + 'logExportDesc': 'Преглед и експорт на логовете на приложението', + 'permLoadFailed': 'Неуспешно зареждане на групите разрешения', + 'permInsufficient': 'Отказано разрешение', + 'voiceCloneCreating': 'Създаване на вашия глас…', + 'voiceCloneCreate': 'Създай моя глас', + 'voiceCloneAgree': 'Приемам и прочитам декларацията на глас', + 'voiceCloneReadPrompt': 'Моля, прочетете:', + 'voiceCloneFirstMonthFree': 'Първият месец безплатно', + 'voiceCloneEnable': 'Включване на клониране на глас', + 'noMusicPlaying': 'Нищо не се възпроизвежда', + 'qqMusicNoSeek': 'Превъртането не се поддържа за QQ Music', + 'bleScanTitle': 'BLE сканиране', + 'bluetoothOn': 'Bluetooth е включен', + 'bleScanning': 'Сканиране…', + 'bleConnectedDevices': 'Свързани устройства', + 'bleUnknownDevice': 'Неизвестно устройство', + 'bleTapToScan': 'Натиснете „Сканирай“, за да търсите BLE устройства', + 'weekMon': 'Пн', + 'weekTue': 'Вт', + 'weekWed': 'Ср', + 'weekThu': 'Чт', + 'weekFri': 'Пт', + 'weekSat': 'Сб', + 'weekSun': 'Нд', + 'agentMeeting': 'Гласови бележки', + 'agentMeetingDesc': 'Резюме на записи, център за памет', + 'agentEmai': 'EMAI асистент', + 'agentEmaiDesc': 'Разговаряйте и питайте всичко с глас', + 'agentSimultaneous': 'Превод на живо', + 'agentSimultaneousDesc': 'Превод, докато говорите', + 'agentFaceToFace': 'Лице в лице', + 'agentFaceToFaceDesc': 'Двупосочен превод на разговор', + 'agentCallRecording': 'Запис на разговор', + 'agentCallRecordingDesc': 'Разговорите се записват автоматично', + 'agentFieldRecording': 'Запис на място', + 'agentFieldRecordingDesc': 'Микрофон на устройството или телефона', + 'agentCall': 'Превод на разговори', + 'agentCallDesc': 'Превод в реално време по време на разговор', + 'agentAudioVideo': 'Превод на медия', + 'agentAudioVideoDesc': 'Кадриране с камера / превод на аудио и видео', + 'agentEnglishChat': 'Разговор на английски', + 'agentEnglishChatDesc': 'Потапяща практика на говорене', + 'agentEnglishStudy': 'Учене на английски', + 'agentEnglishStudyDesc': 'Уроци по лексика и граматика', + 'agentKidsStory': 'Детски приказки', + 'agentKidsStoryDesc': 'Приказки за лека нощ и въпроси и отговори', + 'moduleRemovedDesc': 'премахнато от страницата AI', + 'moduleAddedDesc': 'добавено в края на страницата AI', + 'calNoRecords': 'Няма записи', + 'calNoRecordsDay': 'Нищо планирано', + 'calTodos': 'Задачи', + 'calExpenses': 'Разходи', + 'calTodoCount': '@count задачи', + 'calExpenseCount': '@count разходи', + 'calEntryCount': '@count записи', + 'calItemsUnit': 'елемента', + 'calCountUnit': 'записа', + 'calTotalAmount': 'Общо', + 'recordPause': 'Пауза', + 'recordResume': 'Продължи', + 'recordDeleteConfirm': 'Да се изтрие ли този запис?', + 'scopeDay': 'Ден', + 'scopeWeek': 'Седмица', + 'scopeMonth': 'Месец', + 'allDay': 'Цял ден', + 'guestModeTitle': 'Режим гост', + 'guestModeDesc': 'Гостите могат само да разглеждат. Влезте, за да използвате гласови бележки, превод и запис — данните ви ще се запазват в акаунта ви.', + 'guestKeepBrowsing': 'Продължи разглеждането', + 'guestGoLogin': 'Вход', + 'guestViewOnlyTag': 'Само преглед', + 'autoConnectReenableHint': 'Автоматичното свързване е изключено. Включете го отново в Настройки → Автоматично свързване на устройства.', + 'plazaEntryDesc': 'Разгледайте и добавете още агенти', + 'agentTextTranslation': 'Текстов превод', + 'agentTextTranslationDesc': 'Превод на въведен или поставен текст', + 'agentPictureTranslation': 'Превод на снимки', + 'agentPictureTranslationDesc': 'Снимайте или изберете снимка за превод', + 'callRequiredTitle': 'Необходим е разговор', + 'callRequiredDesc': 'Тази функция работи само по време на разговор', + 'inCallBusyTitle': 'Недостъпно по време на разговор', + 'inCallBusyDesc': 'Микрофонът и аудио каналът се използват от разговора. Опитайте отново след затваряне на разговора.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Безплатно', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/cs_cz.dart b/apps/client/lib/core/translations/language/cs_cz.dart index 254aff2d..166713f9 100644 --- a/apps/client/lib/core/translations/language/cs_cz.dart +++ b/apps/client/lib/core/translations/language/cs_cz.dart @@ -1899,4 +1899,208 @@ const Map csCZ = { 'unmarkFavorite': 'Odebrat z oblíbených', 'unnamedDevice': 'Nepojmenované zařízení', 'userDataParseFailed': 'Data uživatele se nepodařilo načíst', + 'catEarphone': 'AI sluchátka', + 'catEarphoneDesc': 'Klasická Bluetooth / BLE sluchátka', + 'catPhoneHolder': 'AI držák telefonu', + 'catPhoneHolderDesc': 'Zařízení typu držák', + 'catCarAroma': 'AI vůně do auta', + 'catCarAromaDesc': 'Difuzér vůně do auta', + 'agreeAndContinue': 'Souhlasím a pokračovat', + 'memberServiceAgreement': 'Smlouva o členských službách', + 'memberServiceAgreementTitle': 'Smlouva o členských službách', + 'memberServiceAgreementIntro': 'Abychom vám mohli poskytovat lepší členské služby, před předplacením si prosím pečlivě přečtěte: ', + 'memberServiceAgreementOutro': '. Klepnutím na „Souhlasím a pokračovat“ potvrzujete, že jste si výše uvedenou smlouvu celou přečetli a přijímáte ji.', + 'memberAgreementRejectedTip': 'Pro pokračování musíte souhlasit se Smlouvou o členských službách.', + 'translationCallExitTitle': 'Opustit překlad hovoru', + 'translationCallExitMessage': 'Vyberte, co udělat před odchodem', + 'translationCallEnd': 'Ukončit překlad hovoru', + 'translationContinueInBackground': 'Pokračovat v překladu na pozadí', + 'backgroundRecordingIndicatorBody': 'Nahrávání pokračuje na pozadí. Klepnutím se vrátíte.', + 'backgroundTranslationIndicatorBody': 'Překlad hovoru pokračuje na pozadí. Klepnutím se vrátíte.', + 'meetingRecordScreenCapturePermissionDenied': 'K nahrávání systémového zvuku je potřeba oprávnění k nahrávání obrazovky. Udělte ho prosím a zkuste to znovu.', + 'pleaseGrantBluetoothPermission': 'Pro skenování udělte prosím oprávnění Bluetooth', + 'startScanFailed': 'Spuštění skenování selhalo', + 'pleaseLoginFirst': 'Nejprve se prosím přihlaste', + 'deviceUnauthorized': 'Zařízení není autorizováno, zkuste to znovu', + 'boundDevices': 'Propojená zařízení', + 'currentConnection': 'Aktuální připojení', + 'binding': 'Propojování…', + 'permissionDisabled': 'Vypnuto', + 'confirmDisablePermissionTitle': 'Vypnout oprávnění', + 'confirmDisablePermissionContent': 'Vypnout oprávnění {permission}? Pro opětovné zapnutí bude nutné přejít do nastavení systému.', + 'confirmPermanentlyDisallowTitle': 'Přestat se ptát?', + 'confirmPermanentlyDisallowContent': 'Odepřeli jste oprávnění {permission}. Přestat se od nynějška ptát? Pokud zvolíte „Nepovolit“, můžete ho později zapnout v nastavení systému.', + 'notNow': 'Teď ne', + 'permanentlyDisallow': 'Nepovolit', + 'otaBesNotSupported': 'Tato sluchátka zatím nepodporují aktualizaci firmwaru v aplikaci. Kontaktujte prosím podporu.', + 'tabDevice': 'Zařízení', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Technologie pro chytřejší život', + 'sloganAi': 'Inteligence bez hranic', + 'sloganDevice': 'Chytrý hardware připravený na budoucnost', + 'sloganPlaza': 'Chytrý svět, který vám rozumí', + 'aiEditHint': 'Dlouhým stisknutím karty přetáhnete a přeuspořádáte moduly', + 'aiEmptyTitle': 'Zatím žádné moduly', + 'aiEmptyDesc': 'Vyberte si potřebné agenty v Plaza', + 'goToPlaza': 'Přejít do Plaza', + 'plazaOnline': 'K dispozici', + 'plazaPlanned': 'Již brzy', + 'plazaSearchHint': 'Hledat agenty, např. „překlad“, „nahrávání“', + 'moduleRemove': 'Odebrat', + 'moduleAdd': 'Přidat', + 'moduleRemoved': 'Odebráno', + 'moduleAdded': 'Přidáno', + 'goSee': 'Zobrazit', + 'comingSoonTag': 'Již brzy', + 'needDeviceTag': 'Vyžaduje zařízení', + 'featureInDev': 'Tato funkce se připravuje', + 'featureNotWired': 'Zatím není k dispozici', + 'todayLabel': 'Dnes', + 'deviceConnected': 'Připojeno', + 'licenseUnknown': 'Licence neznámá', + 'selectDevice': 'Vyberte zařízení', + 'catNoteCard': 'AI záznamová karta', + 'catNoteCardDesc': 'Záznamník ve tvaru karty', + 'catParkerPen': 'AI pero', + 'catParkerPenDesc': 'Pera s hlasovým záznamníkem', + 'catStylusPen': 'AI stylus', + 'catStylusPenDesc': 'Zařízení pro ruční psaní / stylusy', + 'catStudyMachine': 'AI výukový tablet', + 'catStudyMachineDesc': 'Výuková zařízení', + 'besAddTitle': 'Přidat AI sluchátka', + 'besConnecting': 'Připojování ke sluchátkům…', + 'besNotFound': 'Sluchátka nenalezena', + 'besNotFoundIosDesc': 'Nejprve připojte sluchátka v Nastavení → Bluetooth a poté se vraťte', + 'besNotFoundAndroidDesc': 'Nejprve spárujte sluchátka v Nastavení → Bluetooth a poté je zde připojte', + 'besReadFailed': 'Čtení selhalo', + 'besConnectFailIos': 'Ujistěte se, že jsou sluchátka v systémovém Bluetooth zobrazena jako Připojeno, a zkuste to znovu', + 'besConnectFailAndroid': 'Ujistěte se, že jsou sluchátka zapnutá, poblíž a nejsou připojena k jinému zařízení. Po propojení se budou připojovat automaticky.', + 'holderAddTitle': 'Přidat AI stojánek na telefon', + 'holderConnecting': 'Připojování k zařízení…', + 'holderSearching': 'Hledání zařízení…', + 'holderNotFound': 'Žádná zařízení nenalezena', + 'holderPairHint': 'Ujistěte se, že je stojánek zapnutý a v režimu párování', + 'holderRetryHint': 'Ujistěte se, že je zařízení zapnuté a poblíž, a zkuste to znovu', + 'autoConnectTitle': 'Automatické připojení zařízení', + 'autoConnectDesc': 'Probudí aplikaci, aby se znovu připojila a přijala nahrávky, když se vaše zařízení zapne nebo přiblíží', + 'autoConnectConsentTitle': 'Zapnout automatické připojení', + 'autoConnectConsentIntro': 'Aby se vaše zařízení (AI sluchátka / AI stojánek na telefon) mohlo připojovat automaticky a ukládat nahrávky po stisknutí tlačítka nahrávání, potřebujeme váš souhlas:', + 'autoConnectConsentB1': 'Zaregistrovat skenování Bluetooth na pozadí, aby se aplikace při zjištění propojeného zařízení probudila (automaticky spustila), znovu připojila a přijala nahrávky', + 'autoConnectConsentB2': 'Po probuzení se používá pouze pro připojení zařízení, nahrávání a odesílání — nic jiného, žádné další aplikace se nespouštějí', + 'autoConnectConsentB3': 'Aplikaci můžete používat i bez toho — stačí zařízení pokaždé připojit ručně', + 'autoConnectConsentB4': 'Kdykoli to můžete vypnout v Nastavení → Automatické připojení zařízení', + 'autoConnectAgree': 'Souhlasím a zapnout', + 'autoConnectLater': 'Teď ne', + 'autoConnectRequired': 'Automatické připojení je vypnuté', + 'autoConnectRequiredDesc': 'Pro propojení tohoto zařízení zapněte automatické připojení', + 'recordTapToStart': 'Klepnutím na tlačítko níže spustíte nahrávání', + 'recordPaused': 'Pozastaveno', + 'recordMark': 'Značka', + 'recordDeleteTitle': 'Smazat nahrávku', + 'accountAndProfile': 'Účet a profil', + 'nicknameUnset': 'Přezdívka nenastavena', + 'nicknameInput': 'Zadejte přezdívku', + 'loginMethod': 'Způsob přihlášení', + 'manageMyLogin': 'Spravovat přihlášení', + 'logoutAction': 'Odhlásit se', + 'warningLabel': 'Upozornění:', + 'deleteAccountWarn': 'Váš účet a všechny soubory budou trvale smazány.', + 'icpFiling': 'Registrace ICP', + 'logExport': 'Export protokolů', + 'logExportDesc': 'Zobrazit a exportovat protokoly aplikace', + 'permLoadFailed': 'Načtení skupin oprávnění selhalo', + 'permInsufficient': 'Oprávnění odepřeno', + 'voiceCloneCreating': 'Vytváření vašeho hlasu…', + 'voiceCloneCreate': 'Vytvořit můj hlas', + 'voiceCloneAgree': 'Souhlasím a přečtu prohlášení nahlas', + 'voiceCloneReadPrompt': 'Přečtěte prosím:', + 'voiceCloneFirstMonthFree': 'První měsíc zdarma', + 'voiceCloneEnable': 'Zapnout klonování hlasu', + 'noMusicPlaying': 'Nic se nepřehrává', + 'qqMusicNoSeek': 'QQ Music nepodporuje přetáčení', + 'bleScanTitle': 'Skenování BLE', + 'bluetoothOn': 'Bluetooth zapnutý', + 'bleScanning': 'Skenování…', + 'bleConnectedDevices': 'Připojená zařízení', + 'bleUnknownDevice': 'Neznámé zařízení', + 'bleTapToScan': 'Klepnutím na Skenovat vyhledáte BLE zařízení', + 'weekMon': 'Po', + 'weekTue': 'Út', + 'weekWed': 'St', + 'weekThu': 'Čt', + 'weekFri': 'Pá', + 'weekSat': 'So', + 'weekSun': 'Ne', + 'agentMeeting': 'Hlasové zápisy', + 'agentMeetingDesc': 'Shrnutí nahrávek, centrum paměti', + 'agentEmai': 'Asistent EMAI', + 'agentEmaiDesc': 'Povídejte si a ptejte se hlasem na cokoli', + 'agentSimultaneous': 'Živý překlad', + 'agentSimultaneousDesc': 'Překlad během řeči', + 'agentFaceToFace': 'Tváří v tvář', + 'agentFaceToFaceDesc': 'Obousměrný překlad konverzace', + 'agentCallRecording': 'Nahrávání hovorů', + 'agentCallRecordingDesc': 'Hovory se ukládají automaticky', + 'agentFieldRecording': 'Terénní nahrávání', + 'agentFieldRecordingDesc': 'Mikrofon zařízení nebo telefonu', + 'agentCall': 'Překlad hovoru', + 'agentCallDesc': 'Překlad v reálném čase během hovorů', + 'agentAudioVideo': 'Překlad médií', + 'agentAudioVideoDesc': 'Záběr kamery / překlad audia a videa', + 'agentEnglishChat': 'Konverzace v angličtině', + 'agentEnglishChatDesc': 'Imerzivní procvičování mluvení', + 'agentEnglishStudy': 'Studium angličtiny', + 'agentEnglishStudyDesc': 'Lekce slovní zásoby a gramatiky', + 'agentKidsStory': 'Dětské pohádky', + 'agentKidsStoryDesc': 'Pohádky na dobrou noc a otázky s odpověďmi', + 'moduleRemovedDesc': 'odebráno ze stránky AI', + 'moduleAddedDesc': 'přidáno na konec stránky AI', + 'calNoRecords': 'Žádné záznamy', + 'calNoRecordsDay': 'Nic naplánováno', + 'calTodos': 'Úkoly', + 'calExpenses': 'Výdaje', + 'calTodoCount': 'Úkoly: @count', + 'calExpenseCount': 'Výdaje: @count', + 'calEntryCount': 'Záznamy: @count', + 'calItemsUnit': 'položek', + 'calCountUnit': 'záznamů', + 'calTotalAmount': 'Celkem', + 'recordPause': 'Pozastavit', + 'recordResume': 'Pokračovat', + 'recordDeleteConfirm': 'Smazat tuto nahrávku?', + 'scopeDay': 'Den', + 'scopeWeek': 'Týden', + 'scopeMonth': 'Měsíc', + 'allDay': 'Celý den', + 'guestModeTitle': 'Režim hosta', + 'guestModeDesc': 'Hosté mohou pouze prohlížet. Přihlaste se a používejte hlasové poznámky, překlad a nahrávání — vaše data se uloží k vašemu účtu.', + 'guestKeepBrowsing': 'Pokračovat v prohlížení', + 'guestGoLogin': 'Přihlásit se', + 'guestViewOnlyTag': 'Pouze prohlížení', + 'autoConnectReenableHint': 'Automatické připojení je vypnuté. Znovu ho zapněte v Nastavení → Automatické připojení zařízení.', + 'plazaEntryDesc': 'Procházejte a přidávejte další agenty', + 'agentTextTranslation': 'Překlad textu', + 'agentTextTranslationDesc': 'Překlad napsaného nebo vloženého textu', + 'agentPictureTranslation': 'Překlad fotek', + 'agentPictureTranslationDesc': 'Vyfoťte nebo vyberte fotku k překladu', + 'callRequiredTitle': 'Vyžadován hovor', + 'callRequiredDesc': 'Tato funkce funguje pouze během hovoru', + 'inCallBusyTitle': 'Během hovoru nedostupné', + 'inCallBusyDesc': 'Mikrofon a zvukovou cestu používá hovor. Zkuste to znovu po zavěšení.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Zdarma', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/da_dk.dart b/apps/client/lib/core/translations/language/da_dk.dart index 3ebb0210..15d8da9b 100644 --- a/apps/client/lib/core/translations/language/da_dk.dart +++ b/apps/client/lib/core/translations/language/da_dk.dart @@ -1901,4 +1901,208 @@ const Map daDK = { 'unmarkFavorite': 'Fjern fra favoritter', 'unnamedDevice': 'Enhed uden navn', 'userDataParseFailed': 'Brugerdata kunne ikke læses', + 'catEarphone': 'AI-ørepropper', + 'catEarphoneDesc': 'Klassiske Bluetooth- / BLE-ørepropper', + 'catPhoneHolder': 'AI-mobilholder', + 'catPhoneHolderDesc': 'Holderenheder', + 'catCarAroma': 'AI-bilduft', + 'catCarAromaDesc': 'Aromadiffuser til bil', + 'agreeAndContinue': 'Accepter og fortsæt', + 'memberServiceAgreement': 'Medlemsserviceaftale', + 'memberServiceAgreementTitle': 'Medlemsserviceaftale', + 'memberServiceAgreementIntro': 'For at give dig bedre medlemsservice bedes du læse følgende omhyggeligt, før du abonnerer: ', + 'memberServiceAgreementOutro': '. Ved at trykke på "Accepter og fortsæt" bekræfter du, at du har læst og accepterer ovenstående aftale.', + 'memberAgreementRejectedTip': 'Du skal acceptere medlemsserviceaftalen for at fortsætte.', + 'translationCallExitTitle': 'Forlad opkaldsoversættelse', + 'translationCallExitMessage': 'Vælg, hvad der skal ske, før du forlader', + 'translationCallEnd': 'Afslut opkaldsoversættelse', + 'translationContinueInBackground': 'Fortsæt oversættelse i baggrunden', + 'backgroundRecordingIndicatorBody': 'Optagelsen fortsætter i baggrunden. Tryk for at vende tilbage.', + 'backgroundTranslationIndicatorBody': 'Opkaldsoversættelsen fortsætter i baggrunden. Tryk for at vende tilbage.', + 'meetingRecordScreenCapturePermissionDenied': 'Skærmoptagelsestilladelse kræves for at optage systemlyd. Giv tilladelse, og prøv igen.', + 'pleaseGrantBluetoothPermission': 'Giv Bluetooth-tilladelse for at scanne', + 'startScanFailed': 'Kunne ikke starte scanning', + 'pleaseLoginFirst': 'Log venligst ind først', + 'deviceUnauthorized': 'Enheden er ikke autoriseret, prøv igen', + 'boundDevices': 'Tilknyttede enheder', + 'currentConnection': 'Aktuel forbindelse', + 'binding': 'Tilknytter...', + 'permissionDisabled': 'Deaktiveret', + 'confirmDisablePermissionTitle': 'Slå tilladelse fra', + 'confirmDisablePermissionContent': 'Slå {permission}-tilladelse fra? Du skal gå til systemindstillinger for at aktivere den igen.', + 'confirmPermanentlyDisallowTitle': 'Stop med at spørge?', + 'confirmPermanentlyDisallowContent': 'Du afviste {permission}-tilladelse. Stop med at spørge fremover? Hvis du vælger "Tillad ikke", kan du stadig aktivere den senere i systemindstillinger.', + 'notNow': 'Ikke nu', + 'permanentlyDisallow': 'Tillad ikke', + 'otaBesNotSupported': 'Dette headset understøtter endnu ikke firmwareopgradering i appen. Kontakt venligst support.', + 'tabDevice': 'Enheder', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Teknologi til et smartere liv', + 'sloganAi': 'Grænseløs intelligens', + 'sloganDevice': 'Smart hardware, klar til fremtiden', + 'sloganPlaza': 'En smart verden, der forstår dig', + 'aiEditHint': 'Hold et kort nede for at trække og omarrangere moduler', + 'aiEmptyTitle': 'Ingen moduler tilføjet endnu', + 'aiEmptyDesc': 'Vælg de agenter, du har brug for, i Plaza', + 'goToPlaza': 'Gå til Plaza', + 'plazaOnline': 'Tilgængelig', + 'plazaPlanned': 'Kommer snart', + 'plazaSearchHint': 'Søg efter agenter, f.eks. “oversæt”, “optag”', + 'moduleRemove': 'Fjern', + 'moduleAdd': 'Tilføj', + 'moduleRemoved': 'Fjernet', + 'moduleAdded': 'Tilføjet', + 'goSee': 'Se', + 'comingSoonTag': 'Kommer snart', + 'needDeviceTag': 'Kræver enhed', + 'featureInDev': 'Denne funktion er under udvikling', + 'featureNotWired': 'Ikke tilgængelig endnu', + 'todayLabel': 'I dag', + 'deviceConnected': 'Tilsluttet', + 'licenseUnknown': 'Licens ukendt', + 'selectDevice': 'Vælg en enhed', + 'catNoteCard': 'AI-optagerkort', + 'catNoteCardDesc': 'Kortformet optager', + 'catParkerPen': 'AI-pen', + 'catParkerPenDesc': 'Stemmeoptagerpenne', + 'catStylusPen': 'AI-stylus', + 'catStylusPenDesc': 'Håndskrifts-/stylusenheder', + 'catStudyMachine': 'AI-læringstablet', + 'catStudyMachineDesc': 'Læringsenheder', + 'besAddTitle': 'Tilføj AI-øretelefoner', + 'besConnecting': 'Tilslutter øretelefoner…', + 'besNotFound': 'Øretelefoner ikke fundet', + 'besNotFoundIosDesc': 'Tilslut først øretelefonerne under Indstillinger → Bluetooth, og kom så tilbage', + 'besNotFoundAndroidDesc': 'Par først øretelefonerne under Indstillinger → Bluetooth, og tilslut dem så her', + 'besReadFailed': 'Læsning mislykkedes', + 'besConnectFailIos': 'Sørg for, at øretelefonerne vises som Tilsluttet i systemets Bluetooth, og prøv igen', + 'besConnectFailAndroid': 'Sørg for, at øretelefonerne er tændt, i nærheden og ikke tilsluttet en anden enhed. De genopretter forbindelsen automatisk, når de er parret.', + 'holderAddTitle': 'Tilføj AI-telefonholder', + 'holderConnecting': 'Tilslutter enhed…', + 'holderSearching': 'Søger efter enheder…', + 'holderNotFound': 'Ingen enheder fundet', + 'holderPairHint': 'Sørg for, at holderen er tændt og i parringstilstand', + 'holderRetryHint': 'Sørg for, at enheden er tændt og i nærheden, og prøv igen', + 'autoConnectTitle': 'Tilslut enheder automatisk', + 'autoConnectDesc': 'Væk appen for at genoprette forbindelsen og modtage optagelser, når din enhed tændes eller kommer i nærheden', + 'autoConnectConsentTitle': 'Aktivér automatisk tilslutning', + 'autoConnectConsentIntro': 'For at din enhed (AI-øretelefoner / AI-telefonholder) kan tilslutte automatisk og gemme optagelser, når du trykker på dens optageknap, har vi brug for dit samtykke:', + 'autoConnectConsentB1': 'Registrere en Bluetooth-scanning i baggrunden, så appen vækkes (startes automatisk), når din tilknyttede enhed registreres, for at genoprette forbindelsen og modtage optagelser', + 'autoConnectConsentB2': 'Når appen er vækket, bruges den kun til enhedstilslutning, optagelse og upload — intet andet, og ingen andre apps startes', + 'autoConnectConsentB3': 'Du kan stadig bruge appen uden — tilslut blot enheden manuelt hver gang', + 'autoConnectConsentB4': 'Du kan slå det fra når som helst under Indstillinger → Tilslut enheder automatisk', + 'autoConnectAgree': 'Accepter og aktivér', + 'autoConnectLater': 'Ikke nu', + 'autoConnectRequired': 'Automatisk tilslutning er slået fra', + 'autoConnectRequiredDesc': 'Aktivér automatisk tilslutning for at tilknytte denne enhed', + 'recordTapToStart': 'Tryk på knappen nedenfor for at starte optagelsen', + 'recordPaused': 'Sat på pause', + 'recordMark': 'Markér', + 'recordDeleteTitle': 'Slet optagelse', + 'accountAndProfile': 'Konto og profil', + 'nicknameUnset': 'Intet kaldenavn angivet', + 'nicknameInput': 'Indtast et kaldenavn', + 'loginMethod': 'Loginmetode', + 'manageMyLogin': 'Administrer login', + 'logoutAction': 'Log ud', + 'warningLabel': 'Advarsel:', + 'deleteAccountWarn': 'Din konto og alle filer slettes permanent.', + 'icpFiling': 'ICP-registrering', + 'logExport': 'Eksportér logfiler', + 'logExportDesc': 'Se og eksportér app-logfiler', + 'permLoadFailed': 'Kunne ikke indlæse tilladelsesgrupper', + 'permInsufficient': 'Tilladelse nægtet', + 'voiceCloneCreating': 'Opretter din stemme…', + 'voiceCloneCreate': 'Opret min stemme', + 'voiceCloneAgree': 'Accepter og læs erklæringen højt', + 'voiceCloneReadPrompt': 'Læs venligst:', + 'voiceCloneFirstMonthFree': 'Første måned gratis', + 'voiceCloneEnable': 'Aktivér stemmekloning', + 'noMusicPlaying': 'Intet afspilles', + 'qqMusicNoSeek': 'Spoling understøttes ikke for QQ Music', + 'bleScanTitle': 'BLE-scanning', + 'bluetoothOn': 'Bluetooth er tændt', + 'bleScanning': 'Scanner…', + 'bleConnectedDevices': 'Tilsluttede enheder', + 'bleUnknownDevice': 'Ukendt enhed', + 'bleTapToScan': 'Tryk på scan for at søge efter BLE-enheder', + 'weekMon': 'Man', + 'weekTue': 'Tir', + 'weekWed': 'Ons', + 'weekThu': 'Tor', + 'weekFri': 'Fre', + 'weekSat': 'Lør', + 'weekSun': 'Søn', + 'agentMeeting': 'Talereferat', + 'agentMeetingDesc': 'Opsummer optagelser, hukommelsescenter', + 'agentEmai': 'EMAI-assistent', + 'agentEmaiDesc': 'Chat og spørg om alt med stemmen', + 'agentSimultaneous': 'Realtidsoversættelse', + 'agentSimultaneousDesc': 'Oversæt, mens du taler', + 'agentFaceToFace': 'Ansigt-til-ansigt', + 'agentFaceToFaceDesc': 'Tovejs samtaleoversættelse', + 'agentCallRecording': 'Opkaldsoptagelse', + 'agentCallRecordingDesc': 'Opkald gemmes automatisk', + 'agentFieldRecording': 'Feltoptagelse', + 'agentFieldRecordingDesc': 'Enhedens eller telefonens mikrofon', + 'agentCall': 'Opkaldsoversættelse', + 'agentCallDesc': 'Realtidsoversættelse under opkald', + 'agentAudioVideo': 'Medieoversættelse', + 'agentAudioVideoDesc': 'Kameraindramning / lyd- og videooversættelse', + 'agentEnglishChat': 'Engelsk samtale', + 'agentEnglishChatDesc': 'Fordybende taletræning', + 'agentEnglishStudy': 'Engelskstudie', + 'agentEnglishStudyDesc': 'Ordforråds- og grammatiklektioner', + 'agentKidsStory': 'Børnehistorier', + 'agentKidsStoryDesc': 'Godnathistorier og spørgsmål og svar', + 'moduleRemovedDesc': 'fjernet fra AI-siden', + 'moduleAddedDesc': 'tilføjet nederst på AI-siden', + 'calNoRecords': 'Ingen poster', + 'calNoRecordsDay': 'Intet planlagt', + 'calTodos': 'To-do', + 'calExpenses': 'Udgifter', + 'calTodoCount': '@count to-dos', + 'calExpenseCount': '@count udgifter', + 'calEntryCount': '@count poster', + 'calItemsUnit': 'stk.', + 'calCountUnit': 'poster', + 'calTotalAmount': 'I alt', + 'recordPause': 'Pause', + 'recordResume': 'Fortsæt', + 'recordDeleteConfirm': 'Slet denne optagelse?', + 'scopeDay': 'Dag', + 'scopeWeek': 'Uge', + 'scopeMonth': 'Måned', + 'allDay': 'Hele dagen', + 'guestModeTitle': 'Gæstetilstand', + 'guestModeDesc': 'Gæster kan kun kigge. Log ind for at bruge talereferater, oversættelse og optagelse — dine data gemmes på din konto.', + 'guestKeepBrowsing': 'Fortsæt med at kigge', + 'guestGoLogin': 'Log ind', + 'guestViewOnlyTag': 'Kun visning', + 'autoConnectReenableHint': 'Automatisk tilslutning er slået fra. Slå det til igen under Indstillinger → Tilslut enheder automatisk.', + 'plazaEntryDesc': 'Gennemse og tilføj flere agenter', + 'agentTextTranslation': 'Tekstoversættelse', + 'agentTextTranslationDesc': 'Oversæt indtastet eller indsat tekst', + 'agentPictureTranslation': 'Billedoversættelse', + 'agentPictureTranslationDesc': 'Tag eller vælg et billede for at oversætte', + 'callRequiredTitle': 'Opkald påkrævet', + 'callRequiredDesc': 'Denne funktion virker kun under et opkald', + 'inCallBusyTitle': 'Ikke tilgængelig under et opkald', + 'inCallBusyDesc': 'Mikrofonen og lydvejen bruges af opkaldet. Prøv igen, når du har lagt på.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Gratis', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/de_de.dart b/apps/client/lib/core/translations/language/de_de.dart index a3d854c2..9b4bca76 100644 --- a/apps/client/lib/core/translations/language/de_de.dart +++ b/apps/client/lib/core/translations/language/de_de.dart @@ -1887,6 +1887,8 @@ const Map deDE = { 'catNoteCardDesc': 'Rekorder im Kartenformat', 'catPhoneHolder': 'KI-Handyhalterung', 'catPhoneHolderDesc': 'Halterungsgeräte', + 'catCarAroma': 'KI-Autoduft', + 'catCarAromaDesc': 'Auto-Aromadiffusor', 'catParkerPen': 'KI-Stift', 'catParkerPenDesc': 'Aufnahmestifte', 'catStylusPen': 'KI-Stylus', @@ -2142,4 +2144,32 @@ const Map deDE = { 'unmarkFavorite': 'Aus Favoriten entfernen', 'unnamedDevice': 'Unbenanntes Gerät', 'userDataParseFailed': 'Benutzerdaten konnten nicht gelesen werden', + 'translationCallExitTitle': 'Anruf-Übersetzung verlassen', + 'translationCallExitMessage': 'Wählen Sie, was beim Verlassen geschehen soll', + 'translationCallEnd': 'Anruf-Übersetzung beenden', + 'translationContinueInBackground': 'Im Hintergrund weiter übersetzen', + 'backgroundRecordingIndicatorBody': 'Die Aufnahme läuft im Hintergrund weiter. Zum Zurückkehren tippen.', + 'backgroundTranslationIndicatorBody': 'Die Anruf-Übersetzung läuft im Hintergrund weiter. Zum Zurückkehren tippen.', + 'permissionDisabled': 'Deaktiviert', + 'confirmDisablePermissionTitle': 'Berechtigung deaktivieren', + 'confirmDisablePermissionContent': 'Berechtigung {permission} deaktivieren? Sie müssen sie danach in den Systemeinstellungen erneut aktivieren.', + 'confirmPermanentlyDisallowTitle': 'Nicht mehr fragen?', + 'confirmPermanentlyDisallowContent': 'Sie haben die Berechtigung {permission} abgelehnt. Ab jetzt nicht mehr fragen? Wenn Sie „Nicht erlauben“ wählen, können Sie sie später in den Systemeinstellungen aktivieren.', + 'notNow': 'Nicht jetzt', + 'permanentlyDisallow': 'Nicht erlauben', + 'otaBesNotSupported': 'Dieses Headset unterstützt das Firmware-Upgrade in der App noch nicht. Bitte wenden Sie sich an den Support.', + 'smartcarConnected': 'Verbunden', + 'smartcarConnectFailed': 'Verbindung fehlgeschlagen', + 'smartcarConnecting': 'Verbinde…', + 'smartcarSearching': 'Suche nach Auto-Diffusoren in der Nähe…', + 'smartcarNotFound': 'Kein Gerät gefunden', + 'smartcarScanHint': 'Stellen Sie sicher, dass das Gerät eingeschaltet und in der Nähe ist', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/el_gr.dart b/apps/client/lib/core/translations/language/el_gr.dart index 638927b5..216bc0f7 100644 --- a/apps/client/lib/core/translations/language/el_gr.dart +++ b/apps/client/lib/core/translations/language/el_gr.dart @@ -1935,4 +1935,208 @@ const Map elGR = { 'unmarkFavorite': 'Αφαίρεση από τα αγαπημένα', 'unnamedDevice': 'Συσκευή χωρίς όνομα', 'userDataParseFailed': 'Αποτυχία ανάγνωσης δεδομένων χρήστη', + 'catEarphone': 'Ακουστικά AI', + 'catEarphoneDesc': 'Ακουστικά κλασικού Bluetooth / BLE', + 'catPhoneHolder': 'Βάση κινητού AI', + 'catPhoneHolderDesc': 'Συσκευές βάσης', + 'catCarAroma': 'Αρωματικό αυτοκινήτου AI', + 'catCarAromaDesc': 'Διαχύτης αρώματος αυτοκινήτου', + 'agreeAndContinue': 'Συμφωνώ και συνέχεια', + 'memberServiceAgreement': 'Συμφωνία υπηρεσιών μέλους', + 'memberServiceAgreementTitle': 'Συμφωνία υπηρεσιών μέλους', + 'memberServiceAgreementIntro': 'Για να σας παρέχουμε καλύτερες υπηρεσίες μέλους, διαβάστε προσεκτικά πριν από τη συνδρομή: ', + 'memberServiceAgreementOutro': '. Πατώντας «Συμφωνώ και συνέχεια», επιβεβαιώνετε ότι έχετε διαβάσει πλήρως και αποδέχεστε την παραπάνω συμφωνία.', + 'memberAgreementRejectedTip': 'Πρέπει να αποδεχτείτε τη Συμφωνία υπηρεσιών μέλους για να συνεχίσετε.', + 'translationCallExitTitle': 'Έξοδος από τη μετάφραση κλήσης', + 'translationCallExitMessage': 'Επιλέξτε τι θα κάνετε πριν φύγετε', + 'translationCallEnd': 'Τερματισμός μετάφρασης κλήσης', + 'translationContinueInBackground': 'Συνέχιση μετάφρασης στο παρασκήνιο', + 'backgroundRecordingIndicatorBody': 'Η εγγραφή συνεχίζεται στο παρασκήνιο. Πατήστε για επιστροφή.', + 'backgroundTranslationIndicatorBody': 'Η μετάφραση κλήσης συνεχίζεται στο παρασκήνιο. Πατήστε για επιστροφή.', + 'meetingRecordScreenCapturePermissionDenied': 'Απαιτείται δικαίωμα εγγραφής οθόνης για την καταγραφή ήχου συστήματος. Παραχωρήστε το και δοκιμάστε ξανά.', + 'pleaseGrantBluetoothPermission': 'Παραχωρήστε δικαίωμα Bluetooth για σάρωση', + 'startScanFailed': 'Αποτυχία έναρξης σάρωσης', + 'pleaseLoginFirst': 'Συνδεθείτε πρώτα', + 'deviceUnauthorized': 'Η συσκευή δεν είναι εξουσιοδοτημένη, δοκιμάστε ξανά', + 'boundDevices': 'Συνδεδεμένες συσκευές', + 'currentConnection': 'Τρέχουσα σύνδεση', + 'binding': 'Σύνδεση...', + 'permissionDisabled': 'Απενεργοποιημένο', + 'confirmDisablePermissionTitle': 'Απενεργοποίηση δικαιώματος', + 'confirmDisablePermissionContent': 'Απενεργοποίηση δικαιώματος {permission}; Θα χρειαστεί να μεταβείτε στις ρυθμίσεις συστήματος για να το ενεργοποιήσετε ξανά.', + 'confirmPermanentlyDisallowTitle': 'Να μην ξαναρωτηθείτε;', + 'confirmPermanentlyDisallowContent': 'Απορρίψατε το δικαίωμα {permission}. Να μην ξαναρωτηθείτε από εδώ και πέρα; Αν επιλέξετε «Να μην επιτραπεί», μπορείτε να το ενεργοποιήσετε αργότερα από τις ρυθμίσεις συστήματος.', + 'notNow': 'Όχι τώρα', + 'permanentlyDisallow': 'Να μην επιτραπεί', + 'otaBesNotSupported': 'Αυτά τα ακουστικά δεν υποστηρίζουν ακόμα αναβάθμιση υλικολογισμικού μέσα από την εφαρμογή. Επικοινωνήστε με την υποστήριξη.', + 'tabDevice': 'Συσκευές', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Τεχνολογία για μια πιο έξυπνη ζωή', + 'sloganAi': 'Απεριόριστη νοημοσύνη', + 'sloganDevice': 'Έξυπνο hardware, έτοιμο για το μέλλον', + 'sloganPlaza': 'Ένας έξυπνος κόσμος που σας καταλαβαίνει', + 'aiEditHint': 'Πατήστε παρατεταμένα μια κάρτα για να σύρετε και να αναδιατάξετε τις ενότητες', + 'aiEmptyTitle': 'Δεν έχουν προστεθεί ενότητες ακόμα', + 'aiEmptyDesc': 'Επιλέξτε τους πράκτορες που χρειάζεστε στο Plaza', + 'goToPlaza': 'Μετάβαση στο Plaza', + 'plazaOnline': 'Διαθέσιμο', + 'plazaPlanned': 'Σύντομα', + 'plazaSearchHint': 'Αναζήτηση πρακτόρων, π.χ. «μετάφραση», «εγγραφή»', + 'moduleRemove': 'Αφαίρεση', + 'moduleAdd': 'Προσθήκη', + 'moduleRemoved': 'Αφαιρέθηκε', + 'moduleAdded': 'Προστέθηκε', + 'goSee': 'Προβολή', + 'comingSoonTag': 'Σύντομα', + 'needDeviceTag': 'Απαιτείται συσκευή', + 'featureInDev': 'Αυτή η λειτουργία βρίσκεται υπό ανάπτυξη', + 'featureNotWired': 'Δεν είναι διαθέσιμο ακόμα', + 'todayLabel': 'Σήμερα', + 'deviceConnected': 'Συνδεδεμένο', + 'licenseUnknown': 'Άγνωστη άδεια', + 'selectDevice': 'Επιλέξτε συσκευή', + 'catNoteCard': 'Κάρτα εγγραφής AI', + 'catNoteCardDesc': 'Συσκευή εγγραφής σε σχήμα κάρτας', + 'catParkerPen': 'Στυλό AI', + 'catParkerPenDesc': 'Στυλό εγγραφής φωνής', + 'catStylusPen': 'Γραφίδα AI', + 'catStylusPenDesc': 'Συσκευές γραφής / γραφίδας', + 'catStudyMachine': 'Tablet μάθησης AI', + 'catStudyMachineDesc': 'Συσκευές μάθησης', + 'besAddTitle': 'Προσθήκη ακουστικών AI', + 'besConnecting': 'Σύνδεση με τα ακουστικά…', + 'besNotFound': 'Δεν βρέθηκαν ακουστικά', + 'besNotFoundIosDesc': 'Συνδέστε πρώτα τα ακουστικά από Ρυθμίσεις → Bluetooth και μετά επιστρέψτε εδώ', + 'besNotFoundAndroidDesc': 'Κάντε πρώτα σύζευξη των ακουστικών από Ρυθμίσεις → Bluetooth και μετά συνδεθείτε εδώ', + 'besReadFailed': 'Αποτυχία ανάγνωσης', + 'besConnectFailIos': 'Βεβαιωθείτε ότι τα ακουστικά εμφανίζονται ως Συνδεδεμένα στο Bluetooth του συστήματος και δοκιμάστε ξανά', + 'besConnectFailAndroid': 'Βεβαιωθείτε ότι τα ακουστικά είναι ενεργοποιημένα, κοντά σας και δεν είναι συνδεδεμένα σε άλλη συσκευή. Μόλις συνδεθούν, θα επανασυνδέονται αυτόματα.', + 'holderAddTitle': 'Προσθήκη βάσης κινητού AI', + 'holderConnecting': 'Σύνδεση με τη συσκευή…', + 'holderSearching': 'Αναζήτηση συσκευών…', + 'holderNotFound': 'Δεν βρέθηκαν συσκευές', + 'holderPairHint': 'Βεβαιωθείτε ότι η βάση είναι ενεργοποιημένη και σε λειτουργία σύζευξης', + 'holderRetryHint': 'Βεβαιωθείτε ότι η συσκευή είναι ενεργοποιημένη και κοντά σας και δοκιμάστε ξανά', + 'autoConnectTitle': 'Αυτόματη σύνδεση συσκευών', + 'autoConnectDesc': 'Αφύπνιση της εφαρμογής για επανασύνδεση και λήψη εγγραφών όταν η συσκευή σας ενεργοποιείται ή βρίσκεται κοντά', + 'autoConnectConsentTitle': 'Ενεργοποίηση αυτόματης σύνδεσης', + 'autoConnectConsentIntro': 'Για να συνδέεται αυτόματα η συσκευή σας (ακουστικά AI / βάση κινητού AI) και να αποθηκεύονται οι εγγραφές όταν πατάτε το κουμπί εγγραφής της, χρειαζόμαστε τη συγκατάθεσή σας:', + 'autoConnectConsentB1': 'Καταχώριση σάρωσης Bluetooth στο παρασκήνιο, ώστε η εφαρμογή να αφυπνίζεται (να ξεκινά αυτόματα) όταν εντοπίζεται η συνδεδεμένη συσκευή σας, για επανασύνδεση και λήψη εγγραφών', + 'autoConnectConsentB2': 'Μετά την αφύπνιση, χρησιμοποιείται μόνο για σύνδεση συσκευής, εγγραφή και μεταφόρτωση — τίποτα άλλο, και δεν εκκινούνται άλλες εφαρμογές', + 'autoConnectConsentB3': 'Μπορείτε να χρησιμοποιείτε την εφαρμογή και χωρίς αυτό — απλώς συνδέετε τη συσκευή χειροκίνητα κάθε φορά', + 'autoConnectConsentB4': 'Μπορείτε να το απενεργοποιήσετε ανά πάσα στιγμή από Ρυθμίσεις → Αυτόματη σύνδεση συσκευών', + 'autoConnectAgree': 'Συμφωνώ και ενεργοποίηση', + 'autoConnectLater': 'Όχι τώρα', + 'autoConnectRequired': 'Η αυτόματη σύνδεση είναι απενεργοποιημένη', + 'autoConnectRequiredDesc': 'Ενεργοποιήστε την αυτόματη σύνδεση για να συνδέσετε αυτή τη συσκευή', + 'recordTapToStart': 'Πατήστε το παρακάτω κουμπί για να ξεκινήσει η εγγραφή', + 'recordPaused': 'Σε παύση', + 'recordMark': 'Σήμανση', + 'recordDeleteTitle': 'Διαγραφή εγγραφής', + 'accountAndProfile': 'Λογαριασμός & προφίλ', + 'nicknameUnset': 'Δεν έχει οριστεί ψευδώνυμο', + 'nicknameInput': 'Εισαγάγετε ψευδώνυμο', + 'loginMethod': 'Τρόπος σύνδεσης', + 'manageMyLogin': 'Διαχείριση σύνδεσης', + 'logoutAction': 'Αποσύνδεση', + 'warningLabel': 'Προειδοποίηση:', + 'deleteAccountWarn': 'Ο λογαριασμός σας και όλα τα αρχεία θα διαγραφούν οριστικά.', + 'icpFiling': 'Καταχώριση ICP', + 'logExport': 'Εξαγωγή αρχείων καταγραφής', + 'logExportDesc': 'Προβολή και εξαγωγή αρχείων καταγραφής της εφαρμογής', + 'permLoadFailed': 'Αποτυχία φόρτωσης ομάδων δικαιωμάτων', + 'permInsufficient': 'Δεν παραχωρήθηκε δικαίωμα', + 'voiceCloneCreating': 'Δημιουργία της φωνής σας…', + 'voiceCloneCreate': 'Δημιουργία της φωνής μου', + 'voiceCloneAgree': 'Συμφωνώ και διαβάζω τη δήλωση δυνατά', + 'voiceCloneReadPrompt': 'Διαβάστε:', + 'voiceCloneFirstMonthFree': 'Ο πρώτος μήνας δωρεάν', + 'voiceCloneEnable': 'Ενεργοποίηση κλωνοποίησης φωνής', + 'noMusicPlaying': 'Δεν αναπαράγεται τίποτα', + 'qqMusicNoSeek': 'Η αναζήτηση θέσης δεν υποστηρίζεται για το QQ Music', + 'bleScanTitle': 'Σάρωση BLE', + 'bluetoothOn': 'Bluetooth ενεργοποιημένο', + 'bleScanning': 'Σάρωση…', + 'bleConnectedDevices': 'Συνδεδεμένες συσκευές', + 'bleUnknownDevice': 'Άγνωστη συσκευή', + 'bleTapToScan': 'Πατήστε σάρωση για αναζήτηση συσκευών BLE', + 'weekMon': 'Δευ', + 'weekTue': 'Τρί', + 'weekWed': 'Τετ', + 'weekThu': 'Πέμ', + 'weekFri': 'Παρ', + 'weekSat': 'Σάβ', + 'weekSun': 'Κυρ', + 'agentMeeting': 'Φωνητικά πρακτικά', + 'agentMeetingDesc': 'Σύνοψη εγγραφών, κέντρο μνήμης', + 'agentEmai': 'Βοηθός EMAI', + 'agentEmaiDesc': 'Συνομιλήστε και ρωτήστε οτιδήποτε με τη φωνή σας', + 'agentSimultaneous': 'Ζωντανή μετάφραση', + 'agentSimultaneousDesc': 'Μετάφραση καθώς μιλάτε', + 'agentFaceToFace': 'Πρόσωπο με πρόσωπο', + 'agentFaceToFaceDesc': 'Αμφίδρομη μετάφραση συνομιλίας', + 'agentCallRecording': 'Εγγραφή κλήσεων', + 'agentCallRecordingDesc': 'Οι κλήσεις αποθηκεύονται αυτόματα', + 'agentFieldRecording': 'Εγγραφή πεδίου', + 'agentFieldRecordingDesc': 'Μικρόφωνο συσκευής ή τηλεφώνου', + 'agentCall': 'Μετάφραση κλήσης', + 'agentCallDesc': 'Μετάφραση σε πραγματικό χρόνο κατά τις κλήσεις', + 'agentAudioVideo': 'Μετάφραση πολυμέσων', + 'agentAudioVideoDesc': 'Καδράρισμα κάμερας / μετάφραση ήχου & βίντεο', + 'agentEnglishChat': 'Συνομιλία στα Αγγλικά', + 'agentEnglishChatDesc': 'Εξάσκηση ομιλίας με πλήρη εμβύθιση', + 'agentEnglishStudy': 'Μελέτη Αγγλικών', + 'agentEnglishStudyDesc': 'Μαθήματα λεξιλογίου και γραμματικής', + 'agentKidsStory': 'Παιδικές ιστορίες', + 'agentKidsStoryDesc': 'Ιστορίες για ύπνο και ερωτήσεις-απαντήσεις', + 'moduleRemovedDesc': 'αφαιρέθηκε από τη σελίδα AI', + 'moduleAddedDesc': 'προστέθηκε στο τέλος της σελίδας AI', + 'calNoRecords': 'Δεν υπάρχουν καταχωρίσεις', + 'calNoRecordsDay': 'Τίποτα προγραμματισμένο', + 'calTodos': 'Εργασίες', + 'calExpenses': 'Έξοδα', + 'calTodoCount': '@count εργασίες', + 'calExpenseCount': '@count έξοδα', + 'calEntryCount': '@count καταχωρίσεις', + 'calItemsUnit': 'στοιχεία', + 'calCountUnit': 'καταχωρίσεις', + 'calTotalAmount': 'Σύνολο', + 'recordPause': 'Παύση', + 'recordResume': 'Συνέχιση', + 'recordDeleteConfirm': 'Διαγραφή αυτής της εγγραφής;', + 'scopeDay': 'Ημέρα', + 'scopeWeek': 'Εβδομάδα', + 'scopeMonth': 'Μήνας', + 'allDay': 'Ολοήμερο', + 'guestModeTitle': 'Λειτουργία επισκέπτη', + 'guestModeDesc': 'Οι επισκέπτες μπορούν μόνο να περιηγηθούν. Συνδεθείτε για να χρησιμοποιήσετε φωνητικές σημειώσεις, μετάφραση και εγγραφή — τα δεδομένα σας θα αποθηκεύονται στον λογαριασμό σας.', + 'guestKeepBrowsing': 'Συνέχιση περιήγησης', + 'guestGoLogin': 'Σύνδεση', + 'guestViewOnlyTag': 'Μόνο προβολή', + 'autoConnectReenableHint': 'Η αυτόματη σύνδεση είναι απενεργοποιημένη. Ενεργοποιήστε την ξανά από Ρυθμίσεις → Αυτόματη σύνδεση συσκευών.', + 'plazaEntryDesc': 'Περιηγηθείτε και προσθέστε περισσότερους πράκτορες', + 'agentTextTranslation': 'Μετάφραση κειμένου', + 'agentTextTranslationDesc': 'Μετάφραση πληκτρολογημένου ή επικολλημένου κειμένου', + 'agentPictureTranslation': 'Μετάφραση φωτογραφίας', + 'agentPictureTranslationDesc': 'Τραβήξτε ή επιλέξτε μια φωτογραφία για μετάφραση', + 'callRequiredTitle': 'Απαιτείται κλήση', + 'callRequiredDesc': 'Αυτή η λειτουργία λειτουργεί μόνο κατά τη διάρκεια κλήσης', + 'inCallBusyTitle': 'Μη διαθέσιμο κατά τη διάρκεια κλήσης', + 'inCallBusyDesc': 'Το μικρόφωνο και η διαδρομή ήχου χρησιμοποιούνται από την κλήση. Δοκιμάστε ξανά αφού τερματίσετε την κλήση.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Δωρεάν', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/en_us.dart b/apps/client/lib/core/translations/language/en_us.dart index 22711eed..47d5c750 100644 --- a/apps/client/lib/core/translations/language/en_us.dart +++ b/apps/client/lib/core/translations/language/en_us.dart @@ -1857,6 +1857,8 @@ const Map enUS = { 'catNoteCardDesc': 'Card-shaped recorder', 'catPhoneHolder': 'AI Phone Stand', 'catPhoneHolderDesc': 'Stand devices', + 'catCarAroma': 'AI Car Diffuser', + 'catCarAromaDesc': 'In-car aroma diffuser', 'catParkerPen': 'AI Pen', 'catParkerPenDesc': 'Voice recorder pens', 'catStylusPen': 'AI Stylus', @@ -2112,4 +2114,18 @@ const Map enUS = { 'unmarkFavorite': 'Remove from Favorites', 'unnamedDevice': 'Unnamed Device', 'userDataParseFailed': 'Failed to parse user data', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/es_es.dart b/apps/client/lib/core/translations/language/es_es.dart index 2fc83bf2..4962439a 100644 --- a/apps/client/lib/core/translations/language/es_es.dart +++ b/apps/client/lib/core/translations/language/es_es.dart @@ -1859,6 +1859,8 @@ const Map esES = { 'catNoteCardDesc': 'Grabadora tipo tarjeta', 'catPhoneHolder': 'Soporte de móvil IA', 'catPhoneHolderDesc': 'Dispositivos tipo soporte', + 'catCarAroma': 'Ambientador de coche IA', + 'catCarAromaDesc': 'Difusor de aroma para coche', 'catParkerPen': 'Bolígrafo IA', 'catParkerPenDesc': 'Bolígrafos grabadores', 'catStylusPen': 'Lápiz óptico IA', @@ -2136,4 +2138,32 @@ const Map esES = { 'unmarkFavorite': 'Quitar de favoritos', 'unnamedDevice': 'Dispositivo sin nombre', 'userDataParseFailed': 'Error al procesar los datos del usuario', + 'translationCallExitTitle': 'Salir de la traducción de llamadas', + 'translationCallExitMessage': 'Elige qué hacer antes de salir', + 'translationCallEnd': 'Finalizar traducción de llamada', + 'translationContinueInBackground': 'Seguir traduciendo en segundo plano', + 'backgroundRecordingIndicatorBody': 'La grabación continúa en segundo plano. Toca para volver.', + 'backgroundTranslationIndicatorBody': 'La traducción de llamada continúa en segundo plano. Toca para volver.', + 'permissionDisabled': 'Desactivado', + 'confirmDisablePermissionTitle': 'Desactivar permiso', + 'confirmDisablePermissionContent': '¿Desactivar el permiso de {permission}? Tendrás que ir a los ajustes del sistema para volver a activarlo.', + 'confirmPermanentlyDisallowTitle': '¿Dejar de preguntar?', + 'confirmPermanentlyDisallowContent': 'Has denegado el permiso de {permission}. ¿No volver a preguntar? Si eliges «No permitir», podrás activarlo más tarde en los ajustes del sistema.', + 'notNow': 'Ahora no', + 'permanentlyDisallow': 'No permitir', + 'otaBesNotSupported': 'Estos auriculares aún no admiten la actualización de firmware desde la app. Ponte en contacto con el soporte.', + 'smartcarConnected': 'Conectado', + 'smartcarConnectFailed': 'Error de conexión', + 'smartcarConnecting': 'Conectando…', + 'smartcarSearching': 'Buscando difusores de coche cercanos…', + 'smartcarNotFound': 'No se encontró ningún dispositivo', + 'smartcarScanHint': 'Asegúrate de que el dispositivo esté encendido y cerca del teléfono', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/et_ee.dart b/apps/client/lib/core/translations/language/et_ee.dart index 1638b870..cf6bf38e 100644 --- a/apps/client/lib/core/translations/language/et_ee.dart +++ b/apps/client/lib/core/translations/language/et_ee.dart @@ -1895,4 +1895,208 @@ const Map etEE = { 'unmarkFavorite': 'Eemalda lemmikutest', 'unnamedDevice': 'Nimeta seade', 'userDataParseFailed': 'Kasutajaandmete lugemine ebaõnnestus', + 'catEarphone': 'AI kõrvaklapid', + 'catEarphoneDesc': 'Klassikalised Bluetooth / BLE kõrvaklapid', + 'catPhoneHolder': 'AI telefonihoidik', + 'catPhoneHolderDesc': 'Hoidikuseadmed', + 'catCarAroma': 'AI auto lõhnastaja', + 'catCarAromaDesc': 'Auto aroomihajuti', + 'agreeAndContinue': 'Nõustu ja jätka', + 'memberServiceAgreement': 'Liikmeteenuse leping', + 'memberServiceAgreementTitle': 'Liikmeteenuse leping', + 'memberServiceAgreementIntro': 'Parema liikmeteenuse pakkumiseks loe enne tellimist hoolikalt läbi: ', + 'memberServiceAgreementOutro': '. Klõpsates „Nõustu ja jätka“ kinnitad, et oled ülaltoodud lepingu täielikult läbi lugenud ja sellega nõustud.', + 'memberAgreementRejectedTip': 'Jätkamiseks pead nõustuma liikmeteenuse lepinguga.', + 'translationCallExitTitle': 'Välju kõnetõlkest', + 'translationCallExitMessage': 'Vali, mida enne lahkumist teha', + 'translationCallEnd': 'Lõpeta kõnetõlge', + 'translationContinueInBackground': 'Jätka tõlkimist taustal', + 'backgroundRecordingIndicatorBody': 'Salvestamine jätkub taustal. Naasmiseks puuduta.', + 'backgroundTranslationIndicatorBody': 'Kõnetõlge jätkub taustal. Naasmiseks puuduta.', + 'meetingRecordScreenCapturePermissionDenied': 'Süsteemiheli salvestamiseks on vajalik ekraanisalvestuse luba. Anna luba ja proovi uuesti.', + 'pleaseGrantBluetoothPermission': 'Skannimiseks anna Bluetoothi luba', + 'startScanFailed': 'Skannimise käivitamine ebaõnnestus', + 'pleaseLoginFirst': 'Palun logi esmalt sisse', + 'deviceUnauthorized': 'Seade pole autoriseeritud, proovi uuesti', + 'boundDevices': 'Seotud seadmed', + 'currentConnection': 'Praegune ühendus', + 'binding': 'Sidumine...', + 'permissionDisabled': 'Keelatud', + 'confirmDisablePermissionTitle': 'Lülita luba välja', + 'confirmDisablePermissionContent': 'Kas lülitada {permission} luba välja? Uuesti lubamiseks pead minema süsteemi seadetesse.', + 'confirmPermanentlyDisallowTitle': 'Ei küsi enam?', + 'confirmPermanentlyDisallowContent': 'Keeldusid {permission} loast. Kas edaspidi enam mitte küsida? Kui valid „Ära luba“, saad selle hiljem süsteemi seadetes siiski sisse lülitada.', + 'notNow': 'Mitte praegu', + 'permanentlyDisallow': 'Ära luba', + 'otaBesNotSupported': 'See peakomplekt ei toeta veel rakendusesisest püsivara uuendamist. Palun võta ühendust klienditoega.', + 'tabDevice': 'Seadmed', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Tehnoloogia nutikama elu heaks', + 'sloganAi': 'Piiritu intelligentsus', + 'sloganDevice': 'Nutikas riistvara, tulevikuks valmis', + 'sloganPlaza': 'Nutikas maailm, mis sind mõistab', + 'aiEditHint': 'Moodulite ümberpaigutamiseks hoia kaarti all ja lohista', + 'aiEmptyTitle': 'Mooduleid pole veel lisatud', + 'aiEmptyDesc': 'Vali Plazast vajalikud agendid', + 'goToPlaza': 'Mine Plazasse', + 'plazaOnline': 'Saadaval', + 'plazaPlanned': 'Peagi tulekul', + 'plazaSearchHint': 'Otsi agente, nt „tõlgi“, „salvesta“', + 'moduleRemove': 'Eemalda', + 'moduleAdd': 'Lisa', + 'moduleRemoved': 'Eemaldatud', + 'moduleAdded': 'Lisatud', + 'goSee': 'Vaata', + 'comingSoonTag': 'Peagi tulekul', + 'needDeviceTag': 'Vajab seadet', + 'featureInDev': 'See funktsioon on arendamisel', + 'featureNotWired': 'Pole veel saadaval', + 'todayLabel': 'Täna', + 'deviceConnected': 'Ühendatud', + 'licenseUnknown': 'Litsents teadmata', + 'selectDevice': 'Vali seade', + 'catNoteCard': 'AI salvestuskaart', + 'catNoteCardDesc': 'Kaardikujuline salvesti', + 'catParkerPen': 'AI pastakas', + 'catParkerPenDesc': 'Salvestavad pastakad', + 'catStylusPen': 'AI pliiats', + 'catStylusPenDesc': 'Käsitsi kirjutamise / pliiatsiga seadmed', + 'catStudyMachine': 'AI õppetahvel', + 'catStudyMachineDesc': 'Õppeseadmed', + 'besAddTitle': 'Lisa AI kõrvaklapid', + 'besConnecting': 'Ühendan kõrvaklappidega…', + 'besNotFound': 'Kõrvaklappe ei leitud', + 'besNotFoundIosDesc': 'Ühenda kõrvaklapid esmalt menüüs Seaded → Bluetooth ja tule siis tagasi', + 'besNotFoundAndroidDesc': 'Seo kõrvaklapid esmalt menüüs Seaded → Bluetooth ja ühenda siis siin', + 'besReadFailed': 'Lugemine ebaõnnestus', + 'besConnectFailIos': 'Veendu, et kõrvaklapid on süsteemi Bluetoothis olekus „Ühendatud“, seejärel proovi uuesti', + 'besConnectFailAndroid': 'Veendu, et kõrvaklapid on sisse lülitatud, lähedal ega ole ühendatud teise seadmega. Pärast sidumist ühenduvad need automaatselt uuesti.', + 'holderAddTitle': 'Lisa AI telefonialus', + 'holderConnecting': 'Ühendan seadmega…', + 'holderSearching': 'Otsin seadmeid…', + 'holderNotFound': 'Seadmeid ei leitud', + 'holderPairHint': 'Veendu, et alus on sisse lülitatud ja sidumisrežiimis', + 'holderRetryHint': 'Veendu, et seade on sisse lülitatud ja lähedal, seejärel proovi uuesti', + 'autoConnectTitle': 'Seadmete automaatne ühendamine', + 'autoConnectDesc': 'Äratab rakenduse, et taasühenduda ja salvestusi vastu võtta, kui seade sisse lülitub või lähedale tuleb', + 'autoConnectConsentTitle': 'Luba automaatne ühendamine', + 'autoConnectConsentIntro': 'Et sinu seade (AI kõrvaklapid / AI telefonialus) saaks automaatselt ühenduda ja salvestusnupu vajutamisel salvestusi salvestada, vajame sinu nõusolekut:', + 'autoConnectConsentB1': 'Registreerime Bluetoothi taustaskannimise, et rakendus äratataks (käivitataks automaatselt) seotud seadme tuvastamisel, et taasühenduda ja salvestusi vastu võtta', + 'autoConnectConsentB2': 'Pärast äratamist kasutatakse seda ainult seadme ühendamiseks, salvestamiseks ja üleslaadimiseks — mitte millekski muuks, ja teisi rakendusi ei käivitata', + 'autoConnectConsentB3': 'Saad rakendust kasutada ka ilma selleta — ühenda seade lihtsalt iga kord käsitsi', + 'autoConnectConsentB4': 'Saad selle igal ajal välja lülitada menüüs Seaded → Seadmete automaatne ühendamine', + 'autoConnectAgree': 'Nõustu ja luba', + 'autoConnectLater': 'Mitte praegu', + 'autoConnectRequired': 'Automaatne ühendamine on välja lülitatud', + 'autoConnectRequiredDesc': 'Selle seadme sidumiseks lülita sisse automaatne ühendamine', + 'recordTapToStart': 'Salvestamise alustamiseks puuduta allolevat nuppu', + 'recordPaused': 'Peatatud', + 'recordMark': 'Märgi', + 'recordDeleteTitle': 'Kustuta salvestus', + 'accountAndProfile': 'Konto ja profiil', + 'nicknameUnset': 'Hüüdnime pole määratud', + 'nicknameInput': 'Sisesta hüüdnimi', + 'loginMethod': 'Sisselogimisviis', + 'manageMyLogin': 'Halda sisselogimist', + 'logoutAction': 'Logi välja', + 'warningLabel': 'Hoiatus:', + 'deleteAccountWarn': 'Sinu konto ja kõik failid kustutatakse jäädavalt.', + 'icpFiling': 'ICP registreering', + 'logExport': 'Ekspordi logid', + 'logExportDesc': 'Vaata ja ekspordi rakenduse logisid', + 'permLoadFailed': 'Loagruppide laadimine ebaõnnestus', + 'permInsufficient': 'Luba puudub', + 'voiceCloneCreating': 'Loon sinu häält…', + 'voiceCloneCreate': 'Loo minu hääl', + 'voiceCloneAgree': 'Nõustu ja loe avaldus valjusti ette', + 'voiceCloneReadPrompt': 'Palun loe:', + 'voiceCloneFirstMonthFree': 'Esimene kuu tasuta', + 'voiceCloneEnable': 'Luba hääle kloneerimine', + 'noMusicPlaying': 'Midagi ei mängi', + 'qqMusicNoSeek': 'QQ Music ei toeta kerimist', + 'bleScanTitle': 'BLE skannimine', + 'bluetoothOn': 'Bluetooth sees', + 'bleScanning': 'Skannin…', + 'bleConnectedDevices': 'Ühendatud seadmed', + 'bleUnknownDevice': 'Tundmatu seade', + 'bleTapToScan': 'BLE-seadmete otsimiseks puuduta „Skanni“', + 'weekMon': 'E', + 'weekTue': 'T', + 'weekWed': 'K', + 'weekThu': 'N', + 'weekFri': 'R', + 'weekSat': 'L', + 'weekSun': 'P', + 'agentMeeting': 'Häälmemod', + 'agentMeetingDesc': 'Salvestuste kokkuvõtted, mälukeskus', + 'agentEmai': 'EMAI assistent', + 'agentEmaiDesc': 'Vestle ja küsi häälega mida iganes', + 'agentSimultaneous': 'Sünkroontõlge', + 'agentSimultaneousDesc': 'Tõlgib rääkimise ajal', + 'agentFaceToFace': 'Näost näkku', + 'agentFaceToFaceDesc': 'Kahesuunaline vestluse tõlge', + 'agentCallRecording': 'Kõne salvestus', + 'agentCallRecordingDesc': 'Kõned salvestatakse automaatselt', + 'agentFieldRecording': 'Kohapealne salvestus', + 'agentFieldRecordingDesc': 'Seadme või telefoni mikrofon', + 'agentCall': 'Kõnetõlge', + 'agentCallDesc': 'Reaalajas tõlge kõne ajal', + 'agentAudioVideo': 'Meediatõlge', + 'agentAudioVideoDesc': 'Kaamera kadreering / heli ja video tõlge', + 'agentEnglishChat': 'Inglise vestlus', + 'agentEnglishChatDesc': 'Süvenev kõnepraktika', + 'agentEnglishStudy': 'Inglise keele õpe', + 'agentEnglishStudyDesc': 'Sõnavara ja grammatika tunnid', + 'agentKidsStory': 'Lastejutud', + 'agentKidsStoryDesc': 'Unejutud ja küsimused-vastused', + 'moduleRemovedDesc': 'eemaldatud AI lehelt', + 'moduleAddedDesc': 'lisatud AI lehe lõppu', + 'calNoRecords': 'Kirjeid pole', + 'calNoRecordsDay': 'Midagi pole plaanis', + 'calTodos': 'Ülesanded', + 'calExpenses': 'Kulud', + 'calTodoCount': '@count ülesannet', + 'calExpenseCount': '@count kulu', + 'calEntryCount': '@count kirjet', + 'calItemsUnit': 'tk', + 'calCountUnit': 'kirjet', + 'calTotalAmount': 'Kokku', + 'recordPause': 'Peata', + 'recordResume': 'Jätka', + 'recordDeleteConfirm': 'Kas kustutada see salvestus?', + 'scopeDay': 'Päev', + 'scopeWeek': 'Nädal', + 'scopeMonth': 'Kuu', + 'allDay': 'Terve päev', + 'guestModeTitle': 'Külalisrežiim', + 'guestModeDesc': 'Külalised saavad ainult sirvida. Logi sisse, et kasutada häälmärkmeid, tõlget ja salvestamist — sinu andmed salvestatakse sinu kontole.', + 'guestKeepBrowsing': 'Jätka sirvimist', + 'guestGoLogin': 'Logi sisse', + 'guestViewOnlyTag': 'Ainult vaatamiseks', + 'autoConnectReenableHint': 'Automaatne ühendamine on välja lülitatud. Lülita see uuesti sisse menüüs Seaded → Seadmete automaatne ühendamine.', + 'plazaEntryDesc': 'Sirvi ja lisa rohkem agente', + 'agentTextTranslation': 'Tekstitõlge', + 'agentTextTranslationDesc': 'Tõlgi trükitud või kleebitud teksti', + 'agentPictureTranslation': 'Fototõlge', + 'agentPictureTranslationDesc': 'Pildista või vali foto tõlkimiseks', + 'callRequiredTitle': 'Vajalik on kõne', + 'callRequiredDesc': 'See funktsioon töötab ainult kõne ajal', + 'inCallBusyTitle': 'Kõne ajal pole saadaval', + 'inCallBusyDesc': 'Mikrofon ja heliliin on kõne kasutuses. Proovi uuesti pärast kõne lõpetamist.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Tasuta', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/fa_ir.dart b/apps/client/lib/core/translations/language/fa_ir.dart index a63b3d2b..aed4c419 100644 --- a/apps/client/lib/core/translations/language/fa_ir.dart +++ b/apps/client/lib/core/translations/language/fa_ir.dart @@ -1886,4 +1886,208 @@ const Map faIR = { 'unmarkFavorite': 'حذف از علاقه‌مندی‌ها', 'unnamedDevice': 'دستگاه بدون نام', 'userDataParseFailed': 'تحلیل داده‌های کاربر ناموفق بود', + 'catEarphone': 'هدفون هوشمند', + 'catEarphoneDesc': 'هدفون بلوتوث کلاسیک / BLE', + 'catPhoneHolder': 'پایه گوشی هوشمند', + 'catPhoneHolderDesc': 'دستگاه‌های پایه', + 'catCarAroma': 'خوشبوکننده خودرو هوشمند', + 'catCarAromaDesc': 'دستگاه پخش رایحه خودرو', + 'agreeAndContinue': 'موافقت و ادامه', + 'memberServiceAgreement': 'توافق‌نامه خدمات عضویت', + 'memberServiceAgreementTitle': 'توافق‌نامه خدمات عضویت', + 'memberServiceAgreementIntro': 'برای ارائه خدمات عضویت بهتر، لطفاً پیش از اشتراک با دقت مطالعه کنید: ', + 'memberServiceAgreementOutro': '. با کلیک بر روی «موافقت و ادامه»، تأیید می‌کنید که توافق‌نامه فوق را به طور کامل مطالعه کرده و می‌پذیرید.', + 'memberAgreementRejectedTip': 'برای ادامه باید با توافق‌نامه خدمات عضویت موافقت کنید.', + 'translationCallExitTitle': 'خروج از ترجمه تماس', + 'translationCallExitMessage': 'پیش از خروج، انتخاب کنید چه کاری انجام شود', + 'translationCallEnd': 'پایان ترجمه تماس', + 'translationContinueInBackground': 'ادامهٔ ترجمه در پس‌زمینه', + 'backgroundRecordingIndicatorBody': 'ضبط در پس‌زمینه ادامه دارد. برای بازگشت لمس کنید.', + 'backgroundTranslationIndicatorBody': 'ترجمه تماس در پس‌زمینه ادامه دارد. برای بازگشت لمس کنید.', + 'meetingRecordScreenCapturePermissionDenied': 'برای ضبط صدای سیستم، مجوز ضبط صفحه لازم است. لطفاً آن را بدهید و دوباره تلاش کنید.', + 'pleaseGrantBluetoothPermission': 'برای اسکن، لطفاً مجوز بلوتوث را بدهید', + 'startScanFailed': 'شروع اسکن ناموفق بود', + 'pleaseLoginFirst': 'لطفاً ابتدا وارد شوید', + 'deviceUnauthorized': 'دستگاه مجاز نیست، لطفاً دوباره تلاش کنید', + 'boundDevices': 'دستگاه‌های پیوندشده', + 'currentConnection': 'اتصال فعلی', + 'binding': 'در حال پیوند...', + 'permissionDisabled': 'غیرفعال', + 'confirmDisablePermissionTitle': 'خاموش کردن مجوز', + 'confirmDisablePermissionContent': 'مجوز {permission} خاموش شود؟ برای فعال‌سازی مجدد باید به تنظیمات سیستم بروید.', + 'confirmPermanentlyDisallowTitle': 'دیگر پرسیده نشود؟', + 'confirmPermanentlyDisallowContent': 'شما مجوز {permission} را رد کردید. از این پس دیگر پرسیده نشود؟ اگر «اجازه نده» را انتخاب کنید، بعداً می‌توانید آن را از تنظیمات سیستم فعال کنید.', + 'notNow': 'حالا نه', + 'permanentlyDisallow': 'اجازه نده', + 'otaBesNotSupported': 'این هدست هنوز از ارتقای سفت‌افزار داخل برنامه پشتیبانی نمی‌کند. لطفاً با پشتیبانی تماس بگیرید.', + 'tabDevice': 'دستگاه‌ها', + 'tabPlaza': 'پلازا', + 'sloganHome': 'فناوری برای زندگی هوشمندتر', + 'sloganAi': 'هوشی بی‌پایان', + 'sloganDevice': 'سخت‌افزار هوشمند، آمادهٔ آینده', + 'sloganPlaza': 'دنیایی هوشمند که شما را می‌فهمد', + 'aiEditHint': 'برای جابه‌جایی و مرتب‌سازی ماژول‌ها، کارت را لمس طولانی کنید', + 'aiEmptyTitle': 'هنوز ماژولی اضافه نشده است', + 'aiEmptyDesc': 'عامل‌های مورد نیاز خود را از پلازا انتخاب کنید', + 'goToPlaza': 'رفتن به پلازا', + 'plazaOnline': 'در دسترس', + 'plazaPlanned': 'به زودی', + 'plazaSearchHint': 'جستجوی عامل‌ها، مثلاً «ترجمه»، «ضبط»', + 'moduleRemove': 'حذف', + 'moduleAdd': 'افزودن', + 'moduleRemoved': 'حذف شد', + 'moduleAdded': 'اضافه شد', + 'goSee': 'مشاهده', + 'comingSoonTag': 'به زودی', + 'needDeviceTag': 'نیاز به دستگاه', + 'featureInDev': 'این قابلیت در حال توسعه است', + 'featureNotWired': 'هنوز در دسترس نیست', + 'todayLabel': 'امروز', + 'deviceConnected': 'متصل', + 'licenseUnknown': 'مجوز نامشخص', + 'selectDevice': 'یک دستگاه انتخاب کنید', + 'catNoteCard': 'کارت ضبط AI', + 'catNoteCardDesc': 'ضبط‌کنندهٔ کارتی', + 'catParkerPen': 'قلم AI', + 'catParkerPenDesc': 'قلم‌های ضبط صدا', + 'catStylusPen': 'قلم لمسی AI', + 'catStylusPenDesc': 'دستگاه‌های دست‌نویس / قلم لمسی', + 'catStudyMachine': 'تبلت آموزشی AI', + 'catStudyMachineDesc': 'دستگاه‌های آموزشی', + 'besAddTitle': 'افزودن هدست AI', + 'besConnecting': 'در حال اتصال به هدست…', + 'besNotFound': 'هدست پیدا نشد', + 'besNotFoundIosDesc': 'ابتدا هدست را از تنظیمات ← بلوتوث متصل کنید، سپس به اینجا برگردید', + 'besNotFoundAndroidDesc': 'ابتدا هدست را از تنظیمات ← بلوتوث جفت کنید، سپس از اینجا متصل شوید', + 'besReadFailed': 'خواندن ناموفق بود', + 'besConnectFailIos': 'مطمئن شوید هدست در بلوتوث سیستم به‌صورت «متصل» نمایش داده می‌شود، سپس دوباره تلاش کنید', + 'besConnectFailAndroid': 'مطمئن شوید هدست روشن و نزدیک است و به دستگاه دیگری متصل نیست. پس از پیوند، به‌صورت خودکار دوباره متصل می‌شود.', + 'holderAddTitle': 'افزودن پایه گوشی AI', + 'holderConnecting': 'در حال اتصال به دستگاه…', + 'holderSearching': 'در حال جستجوی دستگاه‌ها…', + 'holderNotFound': 'دستگاهی پیدا نشد', + 'holderPairHint': 'مطمئن شوید پایه روشن و در حالت جفت‌سازی است', + 'holderRetryHint': 'مطمئن شوید دستگاه روشن و نزدیک است، سپس دوباره تلاش کنید', + 'autoConnectTitle': 'اتصال خودکار دستگاه‌ها', + 'autoConnectDesc': 'بیدار کردن برنامه برای اتصال مجدد و دریافت ضبط‌ها هنگام روشن شدن یا نزدیک شدن دستگاه', + 'autoConnectConsentTitle': 'فعال‌سازی اتصال خودکار', + 'autoConnectConsentIntro': 'برای اینکه دستگاه شما (هدست AI / پایه گوشی AI) به‌صورت خودکار متصل شود و با فشردن دکمه ضبط آن، ضبط‌ها ذخیره شوند، به رضایت شما نیاز داریم:', + 'autoConnectConsentB1': 'ثبت اسکن بلوتوث در پس‌زمینه تا هنگام شناسایی دستگاه پیوندشده، برنامه بیدار (خودکار اجرا) شود و اتصال مجدد و دریافت ضبط‌ها انجام گیرد', + 'autoConnectConsentB2': 'پس از بیدار شدن، فقط برای اتصال دستگاه، ضبط و بارگذاری استفاده می‌شود — نه چیز دیگری، و هیچ برنامه دیگری اجرا نمی‌شود', + 'autoConnectConsentB3': 'بدون آن هم می‌توانید از برنامه استفاده کنید — فقط هر بار دستگاه را به‌صورت دستی متصل کنید', + 'autoConnectConsentB4': 'هر زمان می‌توانید آن را از تنظیمات ← اتصال خودکار دستگاه‌ها خاموش کنید', + 'autoConnectAgree': 'موافقت و فعال‌سازی', + 'autoConnectLater': 'حالا نه', + 'autoConnectRequired': 'اتصال خودکار خاموش است', + 'autoConnectRequiredDesc': 'برای پیوند این دستگاه، اتصال خودکار را فعال کنید', + 'recordTapToStart': 'برای شروع ضبط، دکمهٔ زیر را لمس کنید', + 'recordPaused': 'متوقف شده', + 'recordMark': 'نشانه', + 'recordDeleteTitle': 'حذف ضبط', + 'accountAndProfile': 'حساب و پروفایل', + 'nicknameUnset': 'نام مستعار تنظیم نشده', + 'nicknameInput': 'نام مستعار را وارد کنید', + 'loginMethod': 'روش ورود', + 'manageMyLogin': 'مدیریت ورود', + 'logoutAction': 'خروج از حساب', + 'warningLabel': 'هشدار:', + 'deleteAccountWarn': 'حساب شما و همه فایل‌ها برای همیشه حذف خواهند شد.', + 'icpFiling': 'ثبت ICP', + 'logExport': 'خروجی گزارش‌ها', + 'logExportDesc': 'مشاهده و خروجی گرفتن از گزارش‌های برنامه', + 'permLoadFailed': 'بارگذاری گروه‌های مجوز ناموفق بود', + 'permInsufficient': 'مجوز رد شد', + 'voiceCloneCreating': 'در حال ساخت صدای شما…', + 'voiceCloneCreate': 'ساخت صدای من', + 'voiceCloneAgree': 'موافقت و خواندن بیانیه با صدای بلند', + 'voiceCloneReadPrompt': 'لطفاً بخوانید:', + 'voiceCloneFirstMonthFree': 'ماه اول رایگان', + 'voiceCloneEnable': 'فعال‌سازی شبیه‌سازی صدا', + 'noMusicPlaying': 'چیزی در حال پخش نیست', + 'qqMusicNoSeek': 'جابه‌جایی در QQ Music پشتیبانی نمی‌شود', + 'bleScanTitle': 'اسکن BLE', + 'bluetoothOn': 'بلوتوث روشن', + 'bleScanning': 'در حال اسکن…', + 'bleConnectedDevices': 'دستگاه‌های متصل', + 'bleUnknownDevice': 'دستگاه ناشناس', + 'bleTapToScan': 'برای جستجوی دستگاه‌های BLE، اسکن را لمس کنید', + 'weekMon': 'دوشنبه', + 'weekTue': 'سه‌شنبه', + 'weekWed': 'چهارشنبه', + 'weekThu': 'پنجشنبه', + 'weekFri': 'جمعه', + 'weekSat': 'شنبه', + 'weekSun': 'یکشنبه', + 'agentMeeting': 'صورت‌جلسه صوتی', + 'agentMeetingDesc': 'خلاصه‌سازی ضبط‌ها، مرکز حافظه', + 'agentEmai': 'دستیار EMAI', + 'agentEmaiDesc': 'با صدا گفتگو کنید و هر چیزی بپرسید', + 'agentSimultaneous': 'ترجمه همزمان', + 'agentSimultaneousDesc': 'ترجمه همزمان با صحبت شما', + 'agentFaceToFace': 'رو در رو', + 'agentFaceToFaceDesc': 'ترجمه گفتگوی دوطرفه', + 'agentCallRecording': 'ضبط تماس', + 'agentCallRecordingDesc': 'تماس‌ها به‌صورت خودکار ذخیره می‌شوند', + 'agentFieldRecording': 'ضبط میدانی', + 'agentFieldRecordingDesc': 'میکروفون دستگاه یا گوشی', + 'agentCall': 'ترجمه تماس', + 'agentCallDesc': 'ترجمه بلادرنگ در حین تماس', + 'agentAudioVideo': 'ترجمه رسانه', + 'agentAudioVideoDesc': 'قاب‌بندی دوربین / ترجمه صوت و ویدیو', + 'agentEnglishChat': 'گفتگوی انگلیسی', + 'agentEnglishChatDesc': 'تمرین مکالمه به‌صورت غوطه‌ور', + 'agentEnglishStudy': 'یادگیری انگلیسی', + 'agentEnglishStudyDesc': 'درس‌های واژگان و دستور زبان', + 'agentKidsStory': 'قصه‌های کودکان', + 'agentKidsStoryDesc': 'قصه‌های شب و پرسش و پاسخ', + 'moduleRemovedDesc': 'از صفحه AI حذف شد', + 'moduleAddedDesc': 'به انتهای صفحه AI اضافه شد', + 'calNoRecords': 'موردی وجود ندارد', + 'calNoRecordsDay': 'برنامه‌ای وجود ندارد', + 'calTodos': 'کارها', + 'calExpenses': 'هزینه‌ها', + 'calTodoCount': '@count کار', + 'calExpenseCount': '@count هزینه', + 'calEntryCount': '@count مورد', + 'calItemsUnit': 'مورد', + 'calCountUnit': 'مورد', + 'calTotalAmount': 'مجموع', + 'recordPause': 'توقف', + 'recordResume': 'ادامه', + 'recordDeleteConfirm': 'این ضبط حذف شود؟', + 'scopeDay': 'روز', + 'scopeWeek': 'هفته', + 'scopeMonth': 'ماه', + 'allDay': 'تمام روز', + 'guestModeTitle': 'حالت مهمان', + 'guestModeDesc': 'مهمان‌ها فقط می‌توانند مرور کنند. برای استفاده از یادداشت صوتی، ترجمه و ضبط وارد شوید — داده‌های شما در حسابتان ذخیره می‌شود.', + 'guestKeepBrowsing': 'ادامه مرور', + 'guestGoLogin': 'ورود', + 'guestViewOnlyTag': 'فقط مشاهده', + 'autoConnectReenableHint': 'اتصال خودکار خاموش است. آن را از تنظیمات ← اتصال خودکار دستگاه‌ها دوباره روشن کنید.', + 'plazaEntryDesc': 'عامل‌های بیشتری را مرور و اضافه کنید', + 'agentTextTranslation': 'ترجمه متن', + 'agentTextTranslationDesc': 'ترجمه متن تایپ‌شده یا چسبانده‌شده', + 'agentPictureTranslation': 'ترجمه عکس', + 'agentPictureTranslationDesc': 'عکس بگیرید یا انتخاب کنید تا ترجمه شود', + 'callRequiredTitle': 'نیاز به تماس', + 'callRequiredDesc': 'این قابلیت فقط در حین تماس کار می‌کند', + 'inCallBusyTitle': 'در حین تماس در دسترس نیست', + 'inCallBusyDesc': 'میکروفون و مسیر صدا در اختیار تماس است. پس از پایان تماس دوباره تلاش کنید.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'رایگان', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/fi_fi.dart b/apps/client/lib/core/translations/language/fi_fi.dart index 7b032e3c..52f99be9 100644 --- a/apps/client/lib/core/translations/language/fi_fi.dart +++ b/apps/client/lib/core/translations/language/fi_fi.dart @@ -1905,4 +1905,208 @@ const Map fiFI = { 'unmarkFavorite': 'Poista suosikeista', 'unnamedDevice': 'Nimetön laite', 'userDataParseFailed': 'Käyttäjätietojen luku epäonnistui', + 'catEarphone': 'AI-nappikuulokkeet', + 'catEarphoneDesc': 'Klassiset Bluetooth- / BLE-kuulokkeet', + 'catPhoneHolder': 'AI-puhelinteline', + 'catPhoneHolderDesc': 'Telinelaitteet', + 'catCarAroma': 'AI-autotuoksu', + 'catCarAromaDesc': 'Auton tuoksudiffuusori', + 'agreeAndContinue': 'Hyväksy ja jatka', + 'memberServiceAgreement': 'Jäsenpalvelusopimus', + 'memberServiceAgreementTitle': 'Jäsenpalvelusopimus', + 'memberServiceAgreementIntro': 'Tarjotaksemme sinulle parempia jäsenpalveluita, lue huolellisesti ennen tilaamista: ', + 'memberServiceAgreementOutro': '. Napsauttamalla ”Hyväksy ja jatka” vahvistat lukeneesi yllä olevan sopimuksen kokonaan ja hyväksyväsi sen.', + 'memberAgreementRejectedTip': 'Sinun on hyväksyttävä jäsenpalvelusopimus jatkaaksesi.', + 'translationCallExitTitle': 'Poistu puhelukäännöksestä', + 'translationCallExitMessage': 'Valitse, mitä tehdään ennen poistumista', + 'translationCallEnd': 'Lopeta puhelukäännös', + 'translationContinueInBackground': 'Jatka kääntämistä taustalla', + 'backgroundRecordingIndicatorBody': 'Tallennus jatkuu taustalla. Palaa napauttamalla.', + 'backgroundTranslationIndicatorBody': 'Puhelukäännös jatkuu taustalla. Palaa napauttamalla.', + 'meetingRecordScreenCapturePermissionDenied': 'Järjestelmän äänen tallentamiseen tarvitaan näytön tallennuslupa. Myönnä lupa ja yritä uudelleen.', + 'pleaseGrantBluetoothPermission': 'Myönnä Bluetooth-lupa hakua varten', + 'startScanFailed': 'Haun käynnistys epäonnistui', + 'pleaseLoginFirst': 'Kirjaudu ensin sisään', + 'deviceUnauthorized': 'Laitetta ei ole valtuutettu, yritä uudelleen', + 'boundDevices': 'Sidotut laitteet', + 'currentConnection': 'Nykyinen yhteys', + 'binding': 'Sidotaan...', + 'permissionDisabled': 'Pois käytöstä', + 'confirmDisablePermissionTitle': 'Poista lupa käytöstä', + 'confirmDisablePermissionContent': 'Poistetaanko {permission}-lupa käytöstä? Sinun on otettava se uudelleen käyttöön järjestelmän asetuksista.', + 'confirmPermanentlyDisallowTitle': 'Lopetetaanko kysyminen?', + 'confirmPermanentlyDisallowContent': 'Epäsit {permission}-luvan. Lopetetaanko kysyminen tästä lähtien? Jos valitset ”Älä salli”, voit silti ottaa sen käyttöön myöhemmin järjestelmän asetuksista.', + 'notNow': 'Ei nyt', + 'permanentlyDisallow': 'Älä salli', + 'otaBesNotSupported': 'Nämä kuulokkeet eivät vielä tue laiteohjelmiston päivitystä sovelluksesta. Ota yhteyttä tukeen.', + 'tabDevice': 'Laitteet', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Teknologiaa älykkäämpään elämään', + 'sloganAi': 'Rajaton älykkyys', + 'sloganDevice': 'Älykäs laitteisto, valmis tulevaisuuteen', + 'sloganPlaza': 'Älykäs maailma, joka ymmärtää sinua', + 'aiEditHint': 'Paina korttia pitkään ja vedä järjestääksesi moduulit', + 'aiEmptyTitle': 'Moduuleja ei ole vielä lisätty', + 'aiEmptyDesc': 'Valitse tarvitsemasi agentit Plazasta', + 'goToPlaza': 'Siirry Plazaan', + 'plazaOnline': 'Saatavilla', + 'plazaPlanned': 'Tulossa pian', + 'plazaSearchHint': 'Hae agentteja, esim. ”käännä”, ”tallenna”', + 'moduleRemove': 'Poista', + 'moduleAdd': 'Lisää', + 'moduleRemoved': 'Poistettu', + 'moduleAdded': 'Lisätty', + 'goSee': 'Katso', + 'comingSoonTag': 'Tulossa pian', + 'needDeviceTag': 'Vaatii laitteen', + 'featureInDev': 'Tämä ominaisuus on kehitteillä', + 'featureNotWired': 'Ei vielä saatavilla', + 'todayLabel': 'Tänään', + 'deviceConnected': 'Yhdistetty', + 'licenseUnknown': 'Lisenssi tuntematon', + 'selectDevice': 'Valitse laite', + 'catNoteCard': 'AI-tallenninkortti', + 'catNoteCardDesc': 'Kortin muotoinen tallennin', + 'catParkerPen': 'AI-kynä', + 'catParkerPenDesc': 'Tallentavat kynät', + 'catStylusPen': 'AI-stylus', + 'catStylusPenDesc': 'Käsinkirjoitus-/stylus-laitteet', + 'catStudyMachine': 'AI-oppimistabletti', + 'catStudyMachineDesc': 'Oppimislaitteet', + 'besAddTitle': 'Lisää AI-kuulokkeet', + 'besConnecting': 'Yhdistetään kuulokkeisiin…', + 'besNotFound': 'Kuulokkeita ei löytynyt', + 'besNotFoundIosDesc': 'Yhdistä kuulokkeet ensin kohdassa Asetukset → Bluetooth ja palaa sitten tänne', + 'besNotFoundAndroidDesc': 'Parita kuulokkeet ensin kohdassa Asetukset → Bluetooth ja yhdistä sitten täällä', + 'besReadFailed': 'Lukeminen epäonnistui', + 'besConnectFailIos': 'Varmista, että kuulokkeet näkyvät yhdistettyinä järjestelmän Bluetooth-asetuksissa, ja yritä sitten uudelleen', + 'besConnectFailAndroid': 'Varmista, että kuulokkeet ovat päällä, lähellä eivätkä yhdistettynä toiseen laitteeseen. Ne yhdistyvät automaattisesti uudelleen parituksen jälkeen.', + 'holderAddTitle': 'Lisää AI-puhelinteline', + 'holderConnecting': 'Yhdistetään laitteeseen…', + 'holderSearching': 'Etsitään laitteita…', + 'holderNotFound': 'Laitteita ei löytynyt', + 'holderPairHint': 'Varmista, että teline on päällä ja paritustilassa', + 'holderRetryHint': 'Varmista, että laite on päällä ja lähellä, ja yritä sitten uudelleen', + 'autoConnectTitle': 'Laitteiden automaattinen yhdistäminen', + 'autoConnectDesc': 'Herättää sovelluksen yhdistämään uudelleen ja vastaanottamaan tallenteita, kun laite käynnistyy tai tulee lähelle', + 'autoConnectConsentTitle': 'Ota automaattinen yhdistäminen käyttöön', + 'autoConnectConsentIntro': 'Jotta laitteesi (AI-kuulokkeet / AI-puhelinteline) voi yhdistää automaattisesti ja tallentaa tallenteet, kun painat sen tallennuspainiketta, tarvitsemme suostumuksesi:', + 'autoConnectConsentB1': 'Rekisteröidään Bluetooth-taustahaku, jotta sovellus herätetään (käynnistetään automaattisesti), kun sidottu laite havaitaan, yhteyden palauttamiseksi ja tallenteiden vastaanottamiseksi', + 'autoConnectConsentB2': 'Herättämisen jälkeen sitä käytetään vain laitteen yhdistämiseen, tallentamiseen ja lataamiseen — ei mihinkään muuhun, eikä muita sovelluksia käynnistetä', + 'autoConnectConsentB3': 'Voit käyttää sovellusta myös ilman sitä — yhdistä laite vain manuaalisesti joka kerta', + 'autoConnectConsentB4': 'Voit poistaa sen käytöstä milloin tahansa kohdassa Asetukset → Laitteiden automaattinen yhdistäminen', + 'autoConnectAgree': 'Hyväksy ja ota käyttöön', + 'autoConnectLater': 'Ei nyt', + 'autoConnectRequired': 'Automaattinen yhdistäminen on pois päältä', + 'autoConnectRequiredDesc': 'Ota automaattinen yhdistäminen käyttöön sitoaksesi tämän laitteen', + 'recordTapToStart': 'Aloita tallennus napauttamalla alla olevaa painiketta', + 'recordPaused': 'Keskeytetty', + 'recordMark': 'Merkitse', + 'recordDeleteTitle': 'Poista tallenne', + 'accountAndProfile': 'Tili ja profiili', + 'nicknameUnset': 'Nimimerkkiä ei ole asetettu', + 'nicknameInput': 'Syötä nimimerkki', + 'loginMethod': 'Kirjautumistapa', + 'manageMyLogin': 'Hallitse kirjautumista', + 'logoutAction': 'Kirjaudu ulos', + 'warningLabel': 'Varoitus:', + 'deleteAccountWarn': 'Tilisi ja kaikki tiedostot poistetaan pysyvästi.', + 'icpFiling': 'ICP-rekisteröinti', + 'logExport': 'Vie lokit', + 'logExportDesc': 'Tarkastele ja vie sovelluksen lokeja', + 'permLoadFailed': 'Luparyhmien lataus epäonnistui', + 'permInsufficient': 'Lupa evätty', + 'voiceCloneCreating': 'Luodaan ääntäsi…', + 'voiceCloneCreate': 'Luo oma ääneni', + 'voiceCloneAgree': 'Hyväksy ja lue lausunto ääneen', + 'voiceCloneReadPrompt': 'Lue ääneen:', + 'voiceCloneFirstMonthFree': 'Ensimmäinen kuukausi ilmaiseksi', + 'voiceCloneEnable': 'Ota äänen kloonaus käyttöön', + 'noMusicPlaying': 'Mitään ei toisteta', + 'qqMusicNoSeek': 'QQ Music ei tue kelausta', + 'bleScanTitle': 'BLE-haku', + 'bluetoothOn': 'Bluetooth päällä', + 'bleScanning': 'Haetaan…', + 'bleConnectedDevices': 'Yhdistetyt laitteet', + 'bleUnknownDevice': 'Tuntematon laite', + 'bleTapToScan': 'Napauta Hae etsiäksesi BLE-laitteita', + 'weekMon': 'Ma', + 'weekTue': 'Ti', + 'weekWed': 'Ke', + 'weekThu': 'To', + 'weekFri': 'Pe', + 'weekSat': 'La', + 'weekSun': 'Su', + 'agentMeeting': 'Äänimuistiot', + 'agentMeetingDesc': 'Tiivistä tallenteet, muistikeskus', + 'agentEmai': 'EMAI-avustaja', + 'agentEmaiDesc': 'Keskustele ja kysy mitä tahansa puhumalla', + 'agentSimultaneous': 'Simultaanitulkkaus', + 'agentSimultaneousDesc': 'Kääntää puhuessasi', + 'agentFaceToFace': 'Kasvokkain', + 'agentFaceToFaceDesc': 'Kaksisuuntainen keskustelun käännös', + 'agentCallRecording': 'Puhelun tallennus', + 'agentCallRecordingDesc': 'Puhelut tallennetaan automaattisesti', + 'agentFieldRecording': 'Kenttätallennus', + 'agentFieldRecordingDesc': 'Laitteen tai puhelimen mikrofoni', + 'agentCall': 'Puhelukäännös', + 'agentCallDesc': 'Reaaliaikainen käännös puhelun aikana', + 'agentAudioVideo': 'Mediakäännös', + 'agentAudioVideoDesc': 'Kameran rajaus / ääni- ja videokäännös', + 'agentEnglishChat': 'Englannin keskustelu', + 'agentEnglishChatDesc': 'Immersiivistä puheharjoittelua', + 'agentEnglishStudy': 'Englannin opiskelu', + 'agentEnglishStudyDesc': 'Sanasto- ja kielioppitunnit', + 'agentKidsStory': 'Lastentarinat', + 'agentKidsStoryDesc': 'Iltasatuja ja kysymyksiä', + 'moduleRemovedDesc': 'poistettu AI-sivulta', + 'moduleAddedDesc': 'lisätty AI-sivun alaosaan', + 'calNoRecords': 'Ei merkintöjä', + 'calNoRecordsDay': 'Ei mitään suunniteltua', + 'calTodos': 'Tehtävät', + 'calExpenses': 'Kulut', + 'calTodoCount': '@count tehtävää', + 'calExpenseCount': '@count kulua', + 'calEntryCount': '@count merkintää', + 'calItemsUnit': 'kpl', + 'calCountUnit': 'merkintää', + 'calTotalAmount': 'Yhteensä', + 'recordPause': 'Keskeytä', + 'recordResume': 'Jatka', + 'recordDeleteConfirm': 'Poistetaanko tämä tallenne?', + 'scopeDay': 'Päivä', + 'scopeWeek': 'Viikko', + 'scopeMonth': 'Kuukausi', + 'allDay': 'Koko päivä', + 'guestModeTitle': 'Vierastila', + 'guestModeDesc': 'Vieraat voivat vain selata. Kirjaudu sisään käyttääksesi äänimuistiinpanoja, käännöstä ja tallennusta — tietosi tallennetaan tilillesi.', + 'guestKeepBrowsing': 'Jatka selaamista', + 'guestGoLogin': 'Kirjaudu sisään', + 'guestViewOnlyTag': 'Vain katselu', + 'autoConnectReenableHint': 'Automaattinen yhdistäminen on pois päältä. Ota se uudelleen käyttöön kohdassa Asetukset → Laitteiden automaattinen yhdistäminen.', + 'plazaEntryDesc': 'Selaa ja lisää agentteja', + 'agentTextTranslation': 'Tekstin käännös', + 'agentTextTranslationDesc': 'Käännä kirjoitettua tai liitettyä tekstiä', + 'agentPictureTranslation': 'Kuvan käännös', + 'agentPictureTranslationDesc': 'Ota tai valitse kuva käännettäväksi', + 'callRequiredTitle': 'Puhelu vaaditaan', + 'callRequiredDesc': 'Tämä ominaisuus toimii vain puhelun aikana', + 'inCallBusyTitle': 'Ei käytettävissä puhelun aikana', + 'inCallBusyDesc': 'Mikrofoni ja äänireitti ovat puhelun käytössä. Yritä uudelleen puhelun päätyttyä.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Ilmainen', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/fr_fr.dart b/apps/client/lib/core/translations/language/fr_fr.dart index 6237ea65..d96af653 100644 --- a/apps/client/lib/core/translations/language/fr_fr.dart +++ b/apps/client/lib/core/translations/language/fr_fr.dart @@ -1898,6 +1898,8 @@ const Map frFR = { 'catNoteCardDesc': 'Enregistreur format carte', 'catPhoneHolder': 'Support téléphone IA', 'catPhoneHolderDesc': 'Appareils de type support', + 'catCarAroma': 'Diffuseur voiture IA', + 'catCarAromaDesc': 'Diffuseur d’arôme pour voiture', 'catParkerPen': 'Stylo IA', 'catParkerPenDesc': 'Stylos enregistreurs', 'catStylusPen': 'Stylet IA', @@ -2155,4 +2157,32 @@ const Map frFR = { 'unmarkFavorite': 'Retirer des favoris', 'unnamedDevice': 'Appareil sans nom', 'userDataParseFailed': "Échec de l'analyse des données utilisateur", + 'translationCallExitTitle': 'Quitter la traduction d\'appel', + 'translationCallExitMessage': 'Choisissez ce que vous souhaitez faire avant de quitter', + 'translationCallEnd': 'Terminer la traduction d\'appel', + 'translationContinueInBackground': 'Continuer la traduction en arrière-plan', + 'backgroundRecordingIndicatorBody': 'L\'enregistrement continue en arrière-plan. Appuyez pour revenir.', + 'backgroundTranslationIndicatorBody': 'La traduction d\'appel continue en arrière-plan. Appuyez pour revenir.', + 'permissionDisabled': 'Désactivé', + 'confirmDisablePermissionTitle': 'Désactiver l\'autorisation', + 'confirmDisablePermissionContent': 'Désactiver l\'autorisation {permission} ? Vous devrez aller dans les paramètres système pour la réactiver.', + 'confirmPermanentlyDisallowTitle': 'Ne plus demander ?', + 'confirmPermanentlyDisallowContent': 'Vous avez refusé l\'autorisation {permission}. Ne plus demander désormais ? Si vous choisissez « Ne pas autoriser », vous pourrez l\'activer plus tard dans les paramètres système.', + 'notNow': 'Pas maintenant', + 'permanentlyDisallow': 'Ne pas autoriser', + 'otaBesNotSupported': 'Ce casque ne prend pas encore en charge la mise à jour du firmware depuis l\'application. Veuillez contacter le support.', + 'smartcarConnected': 'Connecté', + 'smartcarConnectFailed': 'Échec de la connexion', + 'smartcarConnecting': 'Connexion…', + 'smartcarSearching': 'Recherche de diffuseurs auto à proximité…', + 'smartcarNotFound': 'Aucun appareil trouvé', + 'smartcarScanHint': 'Vérifiez que l’appareil est allumé et proche du téléphone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/hi_in.dart b/apps/client/lib/core/translations/language/hi_in.dart index b19dc573..30ee74b8 100644 --- a/apps/client/lib/core/translations/language/hi_in.dart +++ b/apps/client/lib/core/translations/language/hi_in.dart @@ -1904,4 +1904,208 @@ const Map hiIN = { 'unmarkFavorite': 'पसंदीदा से हटाएँ', 'unnamedDevice': 'बिना नाम का डिवाइस', 'userDataParseFailed': 'उपयोगकर्ता डेटा पढ़ने में विफल', + 'catEarphone': 'AI ईयरबड्स', + 'catEarphoneDesc': 'क्लासिक ब्लूटूथ / BLE ईयरबड्स', + 'catPhoneHolder': 'AI फ़ोन स्टैंड', + 'catPhoneHolderDesc': 'स्टैंड डिवाइस', + 'catCarAroma': 'AI कार डिफ्यूज़र', + 'catCarAromaDesc': 'कार सुगंध डिफ्यूज़र', + 'agreeAndContinue': 'सहमत हों और जारी रखें', + 'memberServiceAgreement': 'सदस्यता सेवा अनुबंध', + 'memberServiceAgreementTitle': 'सदस्यता सेवा अनुबंध', + 'memberServiceAgreementIntro': 'आपको बेहतर सदस्यता सेवाएँ देने के लिए, कृपया सदस्यता लेने से पहले ध्यान से पढ़ें: ', + 'memberServiceAgreementOutro': '। "सहमत हों और जारी रखें" पर टैप करके आप पुष्टि करते हैं कि आपने उपरोक्त अनुबंध पूरी तरह पढ़ लिया है और स्वीकार करते हैं।', + 'memberAgreementRejectedTip': 'जारी रखने के लिए आपको सदस्यता सेवा अनुबंध से सहमत होना होगा।', + 'translationCallExitTitle': 'कॉल अनुवाद से बाहर निकलें', + 'translationCallExitMessage': 'बाहर निकलने से पहले चुनें कि क्या करना है', + 'translationCallEnd': 'कॉल अनुवाद समाप्त करें', + 'translationContinueInBackground': 'बैकग्राउंड में अनुवाद जारी रखें', + 'backgroundRecordingIndicatorBody': 'रिकॉर्डिंग बैकग्राउंड में जारी है। वापस जाने के लिए टैप करें।', + 'backgroundTranslationIndicatorBody': 'कॉल अनुवाद बैकग्राउंड में जारी है। वापस जाने के लिए टैप करें।', + 'meetingRecordScreenCapturePermissionDenied': 'सिस्टम ऑडियो कैप्चर करने के लिए स्क्रीन रिकॉर्डिंग अनुमति आवश्यक है। कृपया अनुमति दें और पुनः प्रयास करें।', + 'pleaseGrantBluetoothPermission': 'स्कैन करने के लिए कृपया ब्लूटूथ अनुमति दें', + 'startScanFailed': 'स्कैन शुरू करने में विफल', + 'pleaseLoginFirst': 'कृपया पहले लॉग इन करें', + 'deviceUnauthorized': 'डिवाइस अधिकृत नहीं है, कृपया पुनः प्रयास करें', + 'boundDevices': 'बाउंड डिवाइस', + 'currentConnection': 'वर्तमान कनेक्शन', + 'binding': 'बाइंड हो रहा है...', + 'permissionDisabled': 'बंद', + 'confirmDisablePermissionTitle': 'अनुमति बंद करें', + 'confirmDisablePermissionContent': '{permission} अनुमति बंद करें? इसे फिर से चालू करने के लिए आपको सिस्टम सेटिंग्स में जाना होगा।', + 'confirmPermanentlyDisallowTitle': 'अब न पूछें?', + 'confirmPermanentlyDisallowContent': 'आपने {permission} अनुमति अस्वीकार कर दी। क्या अब से न पूछा जाए? यदि आप "अनुमति न दें" चुनते हैं, तो बाद में सिस्टम सेटिंग्स में इसे चालू कर सकते हैं।', + 'notNow': 'अभी नहीं', + 'permanentlyDisallow': 'अनुमति न दें', + 'otaBesNotSupported': 'यह हेडसेट अभी ऐप में फ़र्मवेयर अपग्रेड का समर्थन नहीं करता। कृपया सहायता से संपर्क करें।', + 'tabDevice': 'डिवाइस', + 'tabPlaza': 'प्लाज़ा', + 'sloganHome': 'स्मार्ट जीवन के लिए तकनीक', + 'sloganAi': 'असीमित बुद्धिमत्ता', + 'sloganDevice': 'स्मार्ट हार्डवेयर, भविष्य के लिए तैयार', + 'sloganPlaza': 'एक स्मार्ट दुनिया जो आपको समझती है', + 'aiEditHint': 'मॉड्यूल खींचकर पुनर्व्यवस्थित करने के लिए कार्ड को देर तक दबाएँ', + 'aiEmptyTitle': 'अभी तक कोई मॉड्यूल नहीं जोड़ा गया', + 'aiEmptyDesc': 'प्लाज़ा में अपने ज़रूरी एजेंट चुनें', + 'goToPlaza': 'प्लाज़ा पर जाएँ', + 'plazaOnline': 'उपलब्ध', + 'plazaPlanned': 'जल्द आ रहा है', + 'plazaSearchHint': 'एजेंट खोजें, जैसे “अनुवाद”, “रिकॉर्ड”', + 'moduleRemove': 'हटाएँ', + 'moduleAdd': 'जोड़ें', + 'moduleRemoved': 'हटाया गया', + 'moduleAdded': 'जोड़ा गया', + 'goSee': 'देखें', + 'comingSoonTag': 'जल्द आ रहा है', + 'needDeviceTag': 'डिवाइस आवश्यक', + 'featureInDev': 'यह सुविधा विकासाधीन है', + 'featureNotWired': 'अभी उपलब्ध नहीं', + 'todayLabel': 'आज', + 'deviceConnected': 'कनेक्टेड', + 'licenseUnknown': 'लाइसेंस अज्ञात', + 'selectDevice': 'एक डिवाइस चुनें', + 'catNoteCard': 'AI रिकॉर्डर कार्ड', + 'catNoteCardDesc': 'कार्ड के आकार का रिकॉर्डर', + 'catParkerPen': 'AI पेन', + 'catParkerPenDesc': 'वॉयस रिकॉर्डर पेन', + 'catStylusPen': 'AI स्टाइलस', + 'catStylusPenDesc': 'हस्तलेखन / स्टाइलस डिवाइस', + 'catStudyMachine': 'AI लर्निंग पैड', + 'catStudyMachineDesc': 'लर्निंग डिवाइस', + 'besAddTitle': 'AI ईयरबड्स जोड़ें', + 'besConnecting': 'ईयरबड्स से कनेक्ट हो रहा है…', + 'besNotFound': 'ईयरबड्स नहीं मिले', + 'besNotFoundIosDesc': 'पहले सेटिंग्स → ब्लूटूथ में ईयरबड्स कनेक्ट करें, फिर यहाँ वापस आएँ', + 'besNotFoundAndroidDesc': 'पहले सेटिंग्स → ब्लूटूथ में ईयरबड्स पेयर करें, फिर यहाँ कनेक्ट करें', + 'besReadFailed': 'पढ़ने में विफल', + 'besConnectFailIos': 'सुनिश्चित करें कि सिस्टम ब्लूटूथ में ईयरबड्स "कनेक्टेड" दिख रहे हैं, फिर पुनः प्रयास करें', + 'besConnectFailAndroid': 'सुनिश्चित करें कि ईयरबड्स चालू हैं, पास में हैं और किसी अन्य डिवाइस से कनेक्ट नहीं हैं। लिंक होते ही वे अपने आप फिर से कनेक्ट हो जाएँगे।', + 'holderAddTitle': 'AI फ़ोन स्टैंड जोड़ें', + 'holderConnecting': 'डिवाइस से कनेक्ट हो रहा है…', + 'holderSearching': 'डिवाइस खोजे जा रहे हैं…', + 'holderNotFound': 'कोई डिवाइस नहीं मिला', + 'holderPairHint': 'सुनिश्चित करें कि स्टैंड चालू है और पेयरिंग मोड में है', + 'holderRetryHint': 'सुनिश्चित करें कि डिवाइस चालू और पास में है, फिर पुनः प्रयास करें', + 'autoConnectTitle': 'डिवाइस ऑटो-कनेक्ट', + 'autoConnectDesc': 'डिवाइस चालू होने या पास आने पर फिर से कनेक्ट होने और रिकॉर्डिंग प्राप्त करने के लिए ऐप को जगाएँ', + 'autoConnectConsentTitle': 'ऑटो-कनेक्ट सक्षम करें', + 'autoConnectConsentIntro': 'आपके डिवाइस (AI ईयरबड्स / AI फ़ोन स्टैंड) को अपने आप कनेक्ट होने और उसका रिकॉर्ड बटन दबाने पर रिकॉर्डिंग सहेजने के लिए, हमें आपकी सहमति चाहिए:', + 'autoConnectConsentB1': 'बैकग्राउंड ब्लूटूथ स्कैन पंजीकृत करें ताकि आपका बाउंड डिवाइस मिलने पर ऐप जागे (ऑटो-स्टार्ट), और फिर से कनेक्ट होकर रिकॉर्डिंग प्राप्त करे', + 'autoConnectConsentB2': 'जागने के बाद इसका उपयोग केवल डिवाइस कनेक्शन, रिकॉर्डिंग और अपलोड के लिए होता है — और कुछ नहीं, न ही कोई अन्य ऐप खोला जाता है', + 'autoConnectConsentB3': 'इसके बिना भी आप ऐप का उपयोग कर सकते हैं — बस हर बार डिवाइस को मैन्युअल रूप से कनेक्ट करें', + 'autoConnectConsentB4': 'आप इसे कभी भी सेटिंग्स → डिवाइस ऑटो-कनेक्ट में बंद कर सकते हैं', + 'autoConnectAgree': 'सहमत हों और सक्षम करें', + 'autoConnectLater': 'अभी नहीं', + 'autoConnectRequired': 'ऑटो-कनेक्ट बंद है', + 'autoConnectRequiredDesc': 'इस डिवाइस को बाइंड करने के लिए ऑटो-कनेक्ट सक्षम करें', + 'recordTapToStart': 'रिकॉर्डिंग शुरू करने के लिए नीचे दिए बटन पर टैप करें', + 'recordPaused': 'रुका हुआ', + 'recordMark': 'मार्क', + 'recordDeleteTitle': 'रिकॉर्डिंग हटाएँ', + 'accountAndProfile': 'खाता और प्रोफ़ाइल', + 'nicknameUnset': 'कोई उपनाम सेट नहीं', + 'nicknameInput': 'उपनाम दर्ज करें', + 'loginMethod': 'लॉगिन विधि', + 'manageMyLogin': 'लॉगिन प्रबंधित करें', + 'logoutAction': 'लॉग आउट', + 'warningLabel': 'चेतावनी:', + 'deleteAccountWarn': 'आपका खाता और सभी फ़ाइलें स्थायी रूप से हटा दी जाएँगी।', + 'icpFiling': 'ICP पंजीकरण', + 'logExport': 'लॉग निर्यात करें', + 'logExportDesc': 'ऐप लॉग देखें और निर्यात करें', + 'permLoadFailed': 'अनुमति समूह लोड करने में विफल', + 'permInsufficient': 'अनुमति अस्वीकृत', + 'voiceCloneCreating': 'आपकी आवाज़ बनाई जा रही है…', + 'voiceCloneCreate': 'मेरी आवाज़ बनाएँ', + 'voiceCloneAgree': 'सहमत हों और कथन को ज़ोर से पढ़ें', + 'voiceCloneReadPrompt': 'कृपया पढ़ें:', + 'voiceCloneFirstMonthFree': 'पहला महीना मुफ़्त', + 'voiceCloneEnable': 'वॉयस क्लोन सक्षम करें', + 'noMusicPlaying': 'कुछ नहीं चल रहा', + 'qqMusicNoSeek': 'QQ Music में सीक करना समर्थित नहीं है', + 'bleScanTitle': 'BLE स्कैन', + 'bluetoothOn': 'ब्लूटूथ चालू', + 'bleScanning': 'स्कैन हो रहा है…', + 'bleConnectedDevices': 'कनेक्टेड डिवाइस', + 'bleUnknownDevice': 'अज्ञात डिवाइस', + 'bleTapToScan': 'BLE डिवाइस खोजने के लिए स्कैन पर टैप करें', + 'weekMon': 'सोम', + 'weekTue': 'मंगल', + 'weekWed': 'बुध', + 'weekThu': 'गुरु', + 'weekFri': 'शुक्र', + 'weekSat': 'शनि', + 'weekSun': 'रवि', + 'agentMeeting': 'वॉयस सारांश', + 'agentMeetingDesc': 'रिकॉर्डिंग का सारांश, मेमोरी हब', + 'agentEmai': 'EMAI असिस्टेंट', + 'agentEmaiDesc': 'आवाज़ से बात करें और कुछ भी पूछें', + 'agentSimultaneous': 'लाइव अनुवाद', + 'agentSimultaneousDesc': 'बोलते समय अनुवाद', + 'agentFaceToFace': 'आमने-सामने', + 'agentFaceToFaceDesc': 'दो-तरफ़ा बातचीत अनुवाद', + 'agentCallRecording': 'कॉल रिकॉर्डिंग', + 'agentCallRecordingDesc': 'कॉल अपने आप सहेजे जाते हैं', + 'agentFieldRecording': 'फ़ील्ड रिकॉर्डिंग', + 'agentFieldRecordingDesc': 'डिवाइस या फ़ोन का माइक्रोफ़ोन', + 'agentCall': 'कॉल अनुवाद', + 'agentCallDesc': 'कॉल के दौरान रीयल-टाइम अनुवाद', + 'agentAudioVideo': 'मीडिया अनुवाद', + 'agentAudioVideoDesc': 'कैमरा फ़्रेमिंग / ऑडियो और वीडियो अनुवाद', + 'agentEnglishChat': 'इंग्लिश चैट', + 'agentEnglishChatDesc': 'इमर्सिव बोलने का अभ्यास', + 'agentEnglishStudy': 'इंग्लिश स्टडी', + 'agentEnglishStudyDesc': 'शब्दावली और व्याकरण पाठ', + 'agentKidsStory': 'बच्चों की कहानियाँ', + 'agentKidsStoryDesc': 'सोने के समय की कहानियाँ और प्रश्नोत्तर', + 'moduleRemovedDesc': 'AI पेज से हटाया गया', + 'moduleAddedDesc': 'AI पेज के नीचे जोड़ा गया', + 'calNoRecords': 'कोई प्रविष्टि नहीं', + 'calNoRecordsDay': 'कुछ भी निर्धारित नहीं', + 'calTodos': 'टू-डू', + 'calExpenses': 'खर्च', + 'calTodoCount': '@count टू-डू', + 'calExpenseCount': '@count खर्च', + 'calEntryCount': '@count प्रविष्टियाँ', + 'calItemsUnit': 'आइटम', + 'calCountUnit': 'प्रविष्टियाँ', + 'calTotalAmount': 'कुल', + 'recordPause': 'रोकें', + 'recordResume': 'जारी रखें', + 'recordDeleteConfirm': 'यह रिकॉर्डिंग हटाएँ?', + 'scopeDay': 'दिन', + 'scopeWeek': 'सप्ताह', + 'scopeMonth': 'माह', + 'allDay': 'पूरे दिन', + 'guestModeTitle': 'अतिथि मोड', + 'guestModeDesc': 'अतिथि केवल ब्राउज़ कर सकते हैं। वॉयस नोट्स, अनुवाद और रिकॉर्डिंग का उपयोग करने के लिए लॉग इन करें — आपका डेटा आपके खाते में सहेजा जाएगा।', + 'guestKeepBrowsing': 'ब्राउज़ करते रहें', + 'guestGoLogin': 'लॉग इन करें', + 'guestViewOnlyTag': 'केवल देखें', + 'autoConnectReenableHint': 'ऑटो-कनेक्ट बंद है। इसे सेटिंग्स → डिवाइस ऑटो-कनेक्ट में फिर से चालू करें।', + 'plazaEntryDesc': 'और एजेंट ब्राउज़ करें और जोड़ें', + 'agentTextTranslation': 'पाठ अनुवाद', + 'agentTextTranslationDesc': 'टाइप या पेस्ट किए गए पाठ का अनुवाद', + 'agentPictureTranslation': 'फ़ोटो अनुवाद', + 'agentPictureTranslationDesc': 'अनुवाद के लिए फ़ोटो लें या चुनें', + 'callRequiredTitle': 'कॉल आवश्यक', + 'callRequiredDesc': 'यह सुविधा केवल कॉल के दौरान काम करती है', + 'inCallBusyTitle': 'कॉल के दौरान अनुपलब्ध', + 'inCallBusyDesc': 'माइक और ऑडियो पाथ कॉल द्वारा उपयोग में हैं। कॉल समाप्त करने के बाद पुनः प्रयास करें।', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'मुफ़्त', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/hr_hr.dart b/apps/client/lib/core/translations/language/hr_hr.dart index 65e53b26..26262c95 100644 --- a/apps/client/lib/core/translations/language/hr_hr.dart +++ b/apps/client/lib/core/translations/language/hr_hr.dart @@ -1920,4 +1920,208 @@ const Map hrHR = { 'unmarkFavorite': 'Ukloni iz favorita', 'unnamedDevice': 'Uređaj bez naziva', 'userDataParseFailed': 'Podatke korisnika nije moguće učitati', + 'catEarphone': 'AI slušalice', + 'catEarphoneDesc': 'Klasične Bluetooth / BLE slušalice', + 'catPhoneHolder': 'AI držač telefona', + 'catPhoneHolderDesc': 'Uređaji tipa držač', + 'catCarAroma': 'AI auto difuzor', + 'catCarAromaDesc': 'Difuzor mirisa za auto', + 'agreeAndContinue': 'Slažem se i nastavi', + 'memberServiceAgreement': 'Ugovor o članskim uslugama', + 'memberServiceAgreementTitle': 'Ugovor o članskim uslugama', + 'memberServiceAgreementIntro': 'Kako bismo vam pružili bolje članske usluge, pažljivo pročitajte prije pretplate: ', + 'memberServiceAgreementOutro': '. Klikom na „Slažem se i nastavi” potvrđujete da ste u cijelosti pročitali i prihvatili gore navedeni ugovor.', + 'memberAgreementRejectedTip': 'Za nastavak morate prihvatiti Ugovor o članskim uslugama.', + 'translationCallExitTitle': 'Izađi iz prijevoda poziva', + 'translationCallExitMessage': 'Odaberite što učiniti prije izlaska', + 'translationCallEnd': 'Završi prijevod poziva', + 'translationContinueInBackground': 'Nastavi prevoditi u pozadini', + 'backgroundRecordingIndicatorBody': 'Snimanje se nastavlja u pozadini. Dodirnite za povratak.', + 'backgroundTranslationIndicatorBody': 'Prijevod poziva nastavlja se u pozadini. Dodirnite za povratak.', + 'meetingRecordScreenCapturePermissionDenied': 'Za snimanje zvuka sustava potrebno je dopuštenje za snimanje zaslona. Odobrite ga i pokušajte ponovno.', + 'pleaseGrantBluetoothPermission': 'Za skeniranje odobrite Bluetooth dopuštenje', + 'startScanFailed': 'Pokretanje skeniranja nije uspjelo', + 'pleaseLoginFirst': 'Prvo se prijavite', + 'deviceUnauthorized': 'Uređaj nije autoriziran, pokušajte ponovno', + 'boundDevices': 'Povezani uređaji', + 'currentConnection': 'Trenutna veza', + 'binding': 'Povezivanje...', + 'permissionDisabled': 'Isključeno', + 'confirmDisablePermissionTitle': 'Isključi dopuštenje', + 'confirmDisablePermissionContent': 'Isključiti dopuštenje {permission}? Za ponovno uključivanje morat ćete otići u postavke sustava.', + 'confirmPermanentlyDisallowTitle': 'Prestati pitati?', + 'confirmPermanentlyDisallowContent': 'Odbili ste dopuštenje {permission}. Prestati pitati od sada? Ako odaberete „Ne dopusti”, i dalje ga možete kasnije omogućiti u postavkama sustava.', + 'notNow': 'Ne sada', + 'permanentlyDisallow': 'Ne dopusti', + 'otaBesNotSupported': 'Ove slušalice još ne podržavaju nadogradnju firmvera iz aplikacije. Obratite se podršci.', + 'tabDevice': 'Uređaji', + 'tabPlaza': 'Trg', + 'sloganHome': 'Tehnologija za pametniji život', + 'sloganAi': 'Inteligencija bez granica', + 'sloganDevice': 'Pametni hardver, spreman za budućnost', + 'sloganPlaza': 'Pametan svijet koji vas razumije', + 'aiEditHint': 'Dugo pritisnite karticu za povlačenje i razmještaj modula', + 'aiEmptyTitle': 'Još nema dodanih modula', + 'aiEmptyDesc': 'Odaberite agente koje trebate na Trgu', + 'goToPlaza': 'Idi na Trg', + 'plazaOnline': 'Dostupno', + 'plazaPlanned': 'Uskoro', + 'plazaSearchHint': 'Pretražite agente, npr. „prijevod”, „snimanje”', + 'moduleRemove': 'Ukloni', + 'moduleAdd': 'Dodaj', + 'moduleRemoved': 'Uklonjeno', + 'moduleAdded': 'Dodano', + 'goSee': 'Pogledaj', + 'comingSoonTag': 'Uskoro', + 'needDeviceTag': 'Potreban uređaj', + 'featureInDev': 'Ova je značajka u razvoju', + 'featureNotWired': 'Još nije dostupno', + 'todayLabel': 'Danas', + 'deviceConnected': 'Povezano', + 'licenseUnknown': 'Licenca nepoznata', + 'selectDevice': 'Odaberite uređaj', + 'catNoteCard': 'AI kartica za snimanje', + 'catNoteCardDesc': 'Snimač u obliku kartice', + 'catParkerPen': 'AI olovka', + 'catParkerPenDesc': 'Olovke za snimanje glasa', + 'catStylusPen': 'AI pisaljka', + 'catStylusPenDesc': 'Uređaji za rukopis / pisaljke', + 'catStudyMachine': 'AI tablet za učenje', + 'catStudyMachineDesc': 'Uređaji za učenje', + 'besAddTitle': 'Dodaj AI slušalice', + 'besConnecting': 'Povezivanje sa slušalicama…', + 'besNotFound': 'Slušalice nisu pronađene', + 'besNotFoundIosDesc': 'Najprije povežite slušalice u Postavke → Bluetooth, zatim se vratite ovdje', + 'besNotFoundAndroidDesc': 'Najprije uparite slušalice u Postavke → Bluetooth, zatim ih ovdje povežite', + 'besReadFailed': 'Čitanje nije uspjelo', + 'besConnectFailIos': 'Provjerite prikazuju li se slušalice kao Povezano u Bluetooth postavkama sustava, zatim pokušajte ponovno', + 'besConnectFailAndroid': 'Provjerite jesu li slušalice uključene, u blizini i da nisu povezane s drugim uređajem. Nakon povezivanja automatski će se ponovno spojiti.', + 'holderAddTitle': 'Dodaj AI stalak za telefon', + 'holderConnecting': 'Povezivanje s uređajem…', + 'holderSearching': 'Pretraživanje uređaja…', + 'holderNotFound': 'Nije pronađen nijedan uređaj', + 'holderPairHint': 'Provjerite je li stalak uključen i u načinu uparivanja', + 'holderRetryHint': 'Provjerite je li uređaj uključen i u blizini, zatim pokušajte ponovno', + 'autoConnectTitle': 'Automatsko povezivanje uređaja', + 'autoConnectDesc': 'Probudi aplikaciju radi ponovnog povezivanja i primanja snimki kad se uređaj uključi ili približi', + 'autoConnectConsentTitle': 'Omogući automatsko povezivanje', + 'autoConnectConsentIntro': 'Kako bi se vaš uređaj (AI slušalice / AI stalak za telefon) automatski povezao i spremao snimke kad pritisnete njegov gumb za snimanje, trebamo vaš pristanak:', + 'autoConnectConsentB1': 'Registrira se pozadinsko Bluetooth skeniranje kako bi se aplikacija probudila (automatski pokrenula) kad se otkrije vaš povezani uređaj, radi ponovnog povezivanja i primanja snimki', + 'autoConnectConsentB2': 'Nakon buđenja koristi se samo za povezivanje uređaja, snimanje i prijenos — ništa drugo, a druge aplikacije se ne pokreću', + 'autoConnectConsentB3': 'Aplikaciju možete koristiti i bez toga — samo svaki put ručno povežite uređaj', + 'autoConnectConsentB4': 'Možete ga isključiti bilo kada u Postavke → Automatsko povezivanje uređaja', + 'autoConnectAgree': 'Slažem se i omogući', + 'autoConnectLater': 'Ne sada', + 'autoConnectRequired': 'Automatsko povezivanje je isključeno', + 'autoConnectRequiredDesc': 'Omogućite automatsko povezivanje kako biste povezali ovaj uređaj', + 'recordTapToStart': 'Dodirnite gumb ispod za početak snimanja', + 'recordPaused': 'Pauzirano', + 'recordMark': 'Označi', + 'recordDeleteTitle': 'Izbriši snimku', + 'accountAndProfile': 'Račun i profil', + 'nicknameUnset': 'Nadimak nije postavljen', + 'nicknameInput': 'Unesite nadimak', + 'loginMethod': 'Način prijave', + 'manageMyLogin': 'Upravljaj prijavom', + 'logoutAction': 'Odjavi se', + 'warningLabel': 'Upozorenje:', + 'deleteAccountWarn': 'Vaš račun i sve datoteke bit će trajno izbrisani.', + 'icpFiling': 'ICP registracija', + 'logExport': 'Izvoz zapisnika', + 'logExportDesc': 'Pregledajte i izvezite zapisnike aplikacije', + 'permLoadFailed': 'Učitavanje grupa dopuštenja nije uspjelo', + 'permInsufficient': 'Dopuštenje odbijeno', + 'voiceCloneCreating': 'Stvaranje vašeg glasa…', + 'voiceCloneCreate': 'Stvori moj glas', + 'voiceCloneAgree': 'Slažem se i pročitat ću izjavu naglas', + 'voiceCloneReadPrompt': 'Pročitajte:', + 'voiceCloneFirstMonthFree': 'Prvi mjesec besplatno', + 'voiceCloneEnable': 'Omogući kloniranje glasa', + 'noMusicPlaying': 'Ništa se ne reproducira', + 'qqMusicNoSeek': 'Premotavanje nije podržano za QQ Music', + 'bleScanTitle': 'BLE skeniranje', + 'bluetoothOn': 'Bluetooth uključen', + 'bleScanning': 'Skeniranje…', + 'bleConnectedDevices': 'Povezani uređaji', + 'bleUnknownDevice': 'Nepoznat uređaj', + 'bleTapToScan': 'Dodirnite Skeniraj za traženje BLE uređaja', + 'weekMon': 'Pon', + 'weekTue': 'Uto', + 'weekWed': 'Sri', + 'weekThu': 'Čet', + 'weekFri': 'Pet', + 'weekSat': 'Sub', + 'weekSun': 'Ned', + 'agentMeeting': 'Glasovni zapisnik', + 'agentMeetingDesc': 'Sažimanje snimki, središte sjećanja', + 'agentEmai': 'EMAI asistent', + 'agentEmaiDesc': 'Razgovarajte i pitajte bilo što glasom', + 'agentSimultaneous': 'Simultani prijevod', + 'agentSimultaneousDesc': 'Prijevod dok govorite', + 'agentFaceToFace': 'Licem u lice', + 'agentFaceToFaceDesc': 'Dvosmjerni prijevod razgovora', + 'agentCallRecording': 'Snimanje poziva', + 'agentCallRecordingDesc': 'Pozivi se automatski spremaju', + 'agentFieldRecording': 'Snimanje na terenu', + 'agentFieldRecordingDesc': 'Mikrofon uređaja ili telefona', + 'agentCall': 'Prijevod poziva', + 'agentCallDesc': 'Prijevod u stvarnom vremenu tijekom poziva', + 'agentAudioVideo': 'Prijevod medija', + 'agentAudioVideoDesc': 'Kadriranje kamerom / prijevod zvuka i videa', + 'agentEnglishChat': 'Razgovor na engleskom', + 'agentEnglishChatDesc': 'Imerzivno vježbanje govora', + 'agentEnglishStudy': 'Učenje engleskog', + 'agentEnglishStudyDesc': 'Lekcije vokabulara i gramatike', + 'agentKidsStory': 'Dječje priče', + 'agentKidsStoryDesc': 'Priče za laku noć te pitanja i odgovori', + 'moduleRemovedDesc': 'uklonjeno s AI stranice', + 'moduleAddedDesc': 'dodano na dno AI stranice', + 'calNoRecords': 'Nema unosa', + 'calNoRecordsDay': 'Ništa nije zakazano', + 'calTodos': 'Zadaci', + 'calExpenses': 'Troškovi', + 'calTodoCount': '@count zadataka', + 'calExpenseCount': '@count troškova', + 'calEntryCount': '@count unosa', + 'calItemsUnit': 'stavki', + 'calCountUnit': 'unosa', + 'calTotalAmount': 'Ukupno', + 'recordPause': 'Pauziraj', + 'recordResume': 'Nastavi', + 'recordDeleteConfirm': 'Izbrisati ovu snimku?', + 'scopeDay': 'Dan', + 'scopeWeek': 'Tjedan', + 'scopeMonth': 'Mjesec', + 'allDay': 'Cijeli dan', + 'guestModeTitle': 'Način gosta', + 'guestModeDesc': 'Gosti mogu samo pregledavati. Prijavite se za korištenje glasovnih bilješki, prijevoda i snimanja — vaši će podaci biti spremljeni na vaš račun.', + 'guestKeepBrowsing': 'Nastavi pregledavati', + 'guestGoLogin': 'Prijavi se', + 'guestViewOnlyTag': 'Samo pregled', + 'autoConnectReenableHint': 'Automatsko povezivanje je isključeno. Ponovno ga uključite u Postavke → Automatsko povezivanje uređaja.', + 'plazaEntryDesc': 'Pregledajte i dodajte više agenata', + 'agentTextTranslation': 'Prijevod teksta', + 'agentTextTranslationDesc': 'Prevedite upisani ili zalijepljeni tekst', + 'agentPictureTranslation': 'Prijevod fotografija', + 'agentPictureTranslationDesc': 'Snimite ili odaberite fotografiju za prijevod', + 'callRequiredTitle': 'Potreban poziv', + 'callRequiredDesc': 'Ova značajka radi samo tijekom poziva', + 'inCallBusyTitle': 'Nedostupno tijekom poziva', + 'inCallBusyDesc': 'Mikrofon i audio put koristi poziv. Pokušajte ponovno nakon prekida poziva.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Besplatno', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/hu_hu.dart b/apps/client/lib/core/translations/language/hu_hu.dart index 4a0a07cc..e7233371 100644 --- a/apps/client/lib/core/translations/language/hu_hu.dart +++ b/apps/client/lib/core/translations/language/hu_hu.dart @@ -1923,4 +1923,208 @@ const Map huHU = { 'unmarkFavorite': 'Eltávolítás a kedvencekből', 'unnamedDevice': 'Névtelen eszköz', 'userDataParseFailed': 'A felhasználói adatok feldolgozása sikertelen', + 'catEarphone': 'AI fülhallgató', + 'catEarphoneDesc': 'Klasszikus Bluetooth / BLE fülhallgató', + 'catPhoneHolder': 'AI telefontartó', + 'catPhoneHolderDesc': 'Tartó eszközök', + 'catCarAroma': 'AI autóillatosító', + 'catCarAromaDesc': 'Autós illatpárologtató', + 'agreeAndContinue': 'Elfogadom és folytatom', + 'memberServiceAgreement': 'Tagsági szolgáltatási szerződés', + 'memberServiceAgreementTitle': 'Tagsági szolgáltatási szerződés', + 'memberServiceAgreementIntro': 'A jobb tagsági szolgáltatás érdekében kérjük, előfizetés előtt figyelmesen olvassa el: ', + 'memberServiceAgreementOutro': '. Az „Elfogadom és folytatom” gombra koppintva megerősíti, hogy a fenti szerződést teljes egészében elolvasta és elfogadja.', + 'memberAgreementRejectedTip': 'A folytatáshoz el kell fogadnia a Tagsági szolgáltatási szerződést.', + 'translationCallExitTitle': 'Kilépés a hívásfordításból', + 'translationCallExitMessage': 'Válassza ki, mi történjen kilépés előtt', + 'translationCallEnd': 'Hívásfordítás befejezése', + 'translationContinueInBackground': 'Fordítás folytatása a háttérben', + 'backgroundRecordingIndicatorBody': 'A felvétel a háttérben folytatódik. Koppintson a visszatéréshez.', + 'backgroundTranslationIndicatorBody': 'A hívásfordítás a háttérben folytatódik. Koppintson a visszatéréshez.', + 'meetingRecordScreenCapturePermissionDenied': 'A rendszerhang rögzítéséhez képernyőfelvételi engedély szükséges. Kérjük, engedélyezze, majd próbálja újra.', + 'pleaseGrantBluetoothPermission': 'A kereséshez adjon Bluetooth engedélyt', + 'startScanFailed': 'A keresés indítása sikertelen', + 'pleaseLoginFirst': 'Kérjük, először jelentkezzen be', + 'deviceUnauthorized': 'Az eszköz nincs engedélyezve, próbálja újra', + 'boundDevices': 'Párosított eszközök', + 'currentConnection': 'Jelenlegi kapcsolat', + 'binding': 'Párosítás...', + 'permissionDisabled': 'Kikapcsolva', + 'confirmDisablePermissionTitle': 'Engedély kikapcsolása', + 'confirmDisablePermissionContent': 'Kikapcsolja a(z) {permission} engedélyt? Az újbóli bekapcsoláshoz a rendszerbeállításokba kell lépnie.', + 'confirmPermanentlyDisallowTitle': 'Ne kérdezzük többé?', + 'confirmPermanentlyDisallowContent': 'Megtagadta a(z) {permission} engedélyt. Ne kérdezzük többé? Ha a „Nem engedélyezem” lehetőséget választja, később a rendszerbeállításokban továbbra is bekapcsolhatja.', + 'notNow': 'Most nem', + 'permanentlyDisallow': 'Nem engedélyezem', + 'otaBesNotSupported': 'Ez a fülhallgató még nem támogatja az alkalmazáson belüli firmware-frissítést. Kérjük, forduljon az ügyfélszolgálathoz.', + 'tabDevice': 'Eszközök', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Technológia az okosabb életért', + 'sloganAi': 'Határtalan intelligencia', + 'sloganDevice': 'Okos hardver, a jövőre készen', + 'sloganPlaza': 'Egy okos világ, amely megért', + 'aiEditHint': 'Tartson lenyomva egy kártyát a modulok húzásához és átrendezéséhez', + 'aiEmptyTitle': 'Még nincs hozzáadott modul', + 'aiEmptyDesc': 'Válassza ki a szükséges ügynököket a Plazában', + 'goToPlaza': 'Ugrás a Plazába', + 'plazaOnline': 'Elérhető', + 'plazaPlanned': 'Hamarosan', + 'plazaSearchHint': 'Ügynökök keresése, pl. „fordítás”, „felvétel”', + 'moduleRemove': 'Eltávolítás', + 'moduleAdd': 'Hozzáadás', + 'moduleRemoved': 'Eltávolítva', + 'moduleAdded': 'Hozzáadva', + 'goSee': 'Megtekintés', + 'comingSoonTag': 'Hamarosan', + 'needDeviceTag': 'Eszköz szükséges', + 'featureInDev': 'Ez a funkció fejlesztés alatt áll', + 'featureNotWired': 'Még nem érhető el', + 'todayLabel': 'Ma', + 'deviceConnected': 'Csatlakoztatva', + 'licenseUnknown': 'Ismeretlen licenc', + 'selectDevice': 'Válasszon eszközt', + 'catNoteCard': 'AI diktafonkártya', + 'catNoteCardDesc': 'Kártya alakú diktafon', + 'catParkerPen': 'AI toll', + 'catParkerPenDesc': 'Diktafon tollak', + 'catStylusPen': 'AI érintőtoll', + 'catStylusPenDesc': 'Kézírás / érintőtoll eszközök', + 'catStudyMachine': 'AI tanulótablet', + 'catStudyMachineDesc': 'Tanulóeszközök', + 'besAddTitle': 'AI fülhallgató hozzáadása', + 'besConnecting': 'Csatlakozás a fülhallgatóhoz…', + 'besNotFound': 'Fülhallgató nem található', + 'besNotFoundIosDesc': 'Először csatlakoztassa a fülhallgatót a Beállítások → Bluetooth menüben, majd térjen vissza ide', + 'besNotFoundAndroidDesc': 'Először párosítsa a fülhallgatót a Beállítások → Bluetooth menüben, majd csatlakozzon itt', + 'besReadFailed': 'Olvasás sikertelen', + 'besConnectFailIos': 'Győződjön meg róla, hogy a fülhallgató Csatlakoztatva állapotban látszik a rendszer Bluetooth-beállításaiban, majd próbálja újra', + 'besConnectFailAndroid': 'Győződjön meg róla, hogy a fülhallgató be van kapcsolva, a közelben van, és nincs másik eszközhöz csatlakoztatva. A kapcsolat létrejötte után automatikusan újracsatlakozik.', + 'holderAddTitle': 'AI telefontartó hozzáadása', + 'holderConnecting': 'Csatlakozás az eszközhöz…', + 'holderSearching': 'Eszközök keresése…', + 'holderNotFound': 'Nem található eszköz', + 'holderPairHint': 'Győződjön meg róla, hogy a tartó be van kapcsolva és párosítási módban van', + 'holderRetryHint': 'Győződjön meg róla, hogy az eszköz be van kapcsolva és a közelben van, majd próbálja újra', + 'autoConnectTitle': 'Eszközök automatikus csatlakoztatása', + 'autoConnectDesc': 'Felébreszti az alkalmazást az újracsatlakozáshoz és a felvételek fogadásához, amikor az eszköz bekapcsol vagy a közelbe kerül', + 'autoConnectConsentTitle': 'Automatikus csatlakozás bekapcsolása', + 'autoConnectConsentIntro': 'Ahhoz, hogy eszköze (AI fülhallgató / AI telefontartó) automatikusan csatlakozzon, és a felvételgomb megnyomásakor mentse a felvételeket, az Ön hozzájárulására van szükségünk:', + 'autoConnectConsentB1': 'Háttérben futó Bluetooth-keresés regisztrálása, hogy az alkalmazás felébredjen (automatikusan elinduljon) a párosított eszköz észlelésekor az újracsatlakozáshoz és a felvételek fogadásához', + 'autoConnectConsentB2': 'Felébresztés után csak az eszköz csatlakoztatására, felvételre és feltöltésre használjuk — semmi másra, és más alkalmazás nem indul el', + 'autoConnectConsentB3': 'Enélkül is használhatja az alkalmazást — csak minden alkalommal kézzel kell csatlakoztatnia az eszközt', + 'autoConnectConsentB4': 'Bármikor kikapcsolhatja a Beállítások → Eszközök automatikus csatlakoztatása menüben', + 'autoConnectAgree': 'Elfogadom és bekapcsolom', + 'autoConnectLater': 'Most nem', + 'autoConnectRequired': 'Az automatikus csatlakozás ki van kapcsolva', + 'autoConnectRequiredDesc': 'Az eszköz párosításához kapcsolja be az automatikus csatlakozást', + 'recordTapToStart': 'A felvétel indításához koppintson az alábbi gombra', + 'recordPaused': 'Szüneteltetve', + 'recordMark': 'Megjelölés', + 'recordDeleteTitle': 'Felvétel törlése', + 'accountAndProfile': 'Fiók és profil', + 'nicknameUnset': 'Nincs beállított becenév', + 'nicknameInput': 'Adjon meg egy becenevet', + 'loginMethod': 'Bejelentkezési mód', + 'manageMyLogin': 'Bejelentkezés kezelése', + 'logoutAction': 'Kijelentkezés', + 'warningLabel': 'Figyelmeztetés:', + 'deleteAccountWarn': 'Fiókja és minden fájlja véglegesen törlődik.', + 'icpFiling': 'ICP-nyilvántartás', + 'logExport': 'Naplók exportálása', + 'logExportDesc': 'Az alkalmazás naplóinak megtekintése és exportálása', + 'permLoadFailed': 'Az engedélycsoportok betöltése sikertelen', + 'permInsufficient': 'Engedély megtagadva', + 'voiceCloneCreating': 'Hangjának létrehozása…', + 'voiceCloneCreate': 'Saját hang létrehozása', + 'voiceCloneAgree': 'Elfogadom és felolvasom a nyilatkozatot', + 'voiceCloneReadPrompt': 'Kérjük, olvassa fel:', + 'voiceCloneFirstMonthFree': 'Az első hónap ingyenes', + 'voiceCloneEnable': 'Hangklónozás bekapcsolása', + 'noMusicPlaying': 'Nincs lejátszás', + 'qqMusicNoSeek': 'A QQ Music nem támogatja a tekerést', + 'bleScanTitle': 'BLE keresés', + 'bluetoothOn': 'Bluetooth bekapcsolva', + 'bleScanning': 'Keresés…', + 'bleConnectedDevices': 'Csatlakoztatott eszközök', + 'bleUnknownDevice': 'Ismeretlen eszköz', + 'bleTapToScan': 'Koppintson a keresésre a BLE eszközök megtalálásához', + 'weekMon': 'H', + 'weekTue': 'K', + 'weekWed': 'Sze', + 'weekThu': 'Cs', + 'weekFri': 'P', + 'weekSat': 'Szo', + 'weekSun': 'V', + 'agentMeeting': 'Hangjegyzőkönyv', + 'agentMeetingDesc': 'Felvételek összefoglalása, emlékközpont', + 'agentEmai': 'EMAI asszisztens', + 'agentEmaiDesc': 'Beszélgessen és kérdezzen bármit hanggal', + 'agentSimultaneous': 'Élő fordítás', + 'agentSimultaneousDesc': 'Fordítás beszéd közben', + 'agentFaceToFace': 'Szemtől szemben', + 'agentFaceToFaceDesc': 'Kétirányú beszélgetésfordítás', + 'agentCallRecording': 'Hívásrögzítés', + 'agentCallRecordingDesc': 'A hívások automatikusan mentődnek', + 'agentFieldRecording': 'Helyszíni felvétel', + 'agentFieldRecordingDesc': 'Eszköz- vagy telefonmikrofon', + 'agentCall': 'Hívásfordítás', + 'agentCallDesc': 'Valós idejű fordítás hívás közben', + 'agentAudioVideo': 'Médiafordítás', + 'agentAudioVideoDesc': 'Kamerakép / hang- és videófordítás', + 'agentEnglishChat': 'Angol csevegés', + 'agentEnglishChatDesc': 'Magával ragadó beszédgyakorlás', + 'agentEnglishStudy': 'Angoltanulás', + 'agentEnglishStudyDesc': 'Szókincs- és nyelvtanleckék', + 'agentKidsStory': 'Gyerekmesék', + 'agentKidsStoryDesc': 'Esti mesék és kérdés-válasz', + 'moduleRemovedDesc': 'eltávolítva az AI oldalról', + 'moduleAddedDesc': 'hozzáadva az AI oldal aljához', + 'calNoRecords': 'Nincs bejegyzés', + 'calNoRecordsDay': 'Nincs betervezve semmi', + 'calTodos': 'Teendők', + 'calExpenses': 'Kiadások', + 'calTodoCount': '@count teendő', + 'calExpenseCount': '@count kiadás', + 'calEntryCount': '@count bejegyzés', + 'calItemsUnit': 'elem', + 'calCountUnit': 'bejegyzés', + 'calTotalAmount': 'Összesen', + 'recordPause': 'Szünet', + 'recordResume': 'Folytatás', + 'recordDeleteConfirm': 'Törli ezt a felvételt?', + 'scopeDay': 'Nap', + 'scopeWeek': 'Hét', + 'scopeMonth': 'Hónap', + 'allDay': 'Egész nap', + 'guestModeTitle': 'Vendég mód', + 'guestModeDesc': 'A vendégek csak böngészhetnek. Jelentkezzen be a hangjegyzetek, a fordítás és a felvétel használatához — adatai a fiókjába kerülnek mentésre.', + 'guestKeepBrowsing': 'Böngészés folytatása', + 'guestGoLogin': 'Bejelentkezés', + 'guestViewOnlyTag': 'Csak megtekintés', + 'autoConnectReenableHint': 'Az automatikus csatlakozás ki van kapcsolva. Kapcsolja vissza a Beállítások → Eszközök automatikus csatlakoztatása menüben.', + 'plazaEntryDesc': 'Böngésszen és adjon hozzá további ügynököket', + 'agentTextTranslation': 'Szövegfordítás', + 'agentTextTranslationDesc': 'Begépelt vagy beillesztett szöveg fordítása', + 'agentPictureTranslation': 'Fotófordítás', + 'agentPictureTranslationDesc': 'Készítsen vagy válasszon fotót a fordításhoz', + 'callRequiredTitle': 'Hívás szükséges', + 'callRequiredDesc': 'Ez a funkció csak hívás közben működik', + 'inCallBusyTitle': 'Hívás közben nem érhető el', + 'inCallBusyDesc': 'A mikrofont és a hangútvonalat a hívás használja. Próbálja újra a hívás befejezése után.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Ingyenes', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/id_id.dart b/apps/client/lib/core/translations/language/id_id.dart index f542c541..7d0a0c85 100644 --- a/apps/client/lib/core/translations/language/id_id.dart +++ b/apps/client/lib/core/translations/language/id_id.dart @@ -1904,4 +1904,208 @@ const Map idID = { 'unmarkFavorite': 'Hapus dari favorit', 'unnamedDevice': 'Perangkat tanpa nama', 'userDataParseFailed': 'Gagal membaca data pengguna', + 'catEarphone': 'Earbud AI', + 'catEarphoneDesc': 'Earbud Bluetooth klasik / BLE', + 'catPhoneHolder': 'Dudukan Ponsel AI', + 'catPhoneHolderDesc': 'Perangkat dudukan', + 'catCarAroma': 'Pengharum Mobil AI', + 'catCarAromaDesc': 'Diffuser aroma mobil', + 'agreeAndContinue': 'Setuju dan Lanjutkan', + 'memberServiceAgreement': 'Perjanjian Layanan Keanggotaan', + 'memberServiceAgreementTitle': 'Perjanjian Layanan Keanggotaan', + 'memberServiceAgreementIntro': 'Untuk memberikan layanan keanggotaan yang lebih baik, harap baca dengan saksama sebelum berlangganan: ', + 'memberServiceAgreementOutro': '. Dengan mengetuk "Setuju dan Lanjutkan", Anda menyatakan telah membaca sepenuhnya dan menerima perjanjian di atas.', + 'memberAgreementRejectedTip': 'Anda harus menyetujui Perjanjian Layanan Keanggotaan untuk melanjutkan.', + 'translationCallExitTitle': 'Keluar dari Terjemahan Panggilan', + 'translationCallExitMessage': 'Pilih tindakan sebelum keluar', + 'translationCallEnd': 'Akhiri terjemahan panggilan', + 'translationContinueInBackground': 'Lanjutkan terjemahan di latar belakang', + 'backgroundRecordingIndicatorBody': 'Perekaman berlanjut di latar belakang. Ketuk untuk kembali.', + 'backgroundTranslationIndicatorBody': 'Terjemahan panggilan berlanjut di latar belakang. Ketuk untuk kembali.', + 'meetingRecordScreenCapturePermissionDenied': 'Izin perekaman layar diperlukan untuk merekam audio sistem. Berikan izin lalu coba lagi.', + 'pleaseGrantBluetoothPermission': 'Berikan izin Bluetooth untuk memindai', + 'startScanFailed': 'Gagal memulai pemindaian', + 'pleaseLoginFirst': 'Silakan masuk terlebih dahulu', + 'deviceUnauthorized': 'Perangkat tidak berwenang, silakan coba lagi', + 'boundDevices': 'Perangkat Terikat', + 'currentConnection': 'Koneksi Saat Ini', + 'binding': 'Mengikat...', + 'permissionDisabled': 'Nonaktif', + 'confirmDisablePermissionTitle': 'Matikan izin', + 'confirmDisablePermissionContent': 'Matikan izin {permission}? Anda perlu membuka pengaturan sistem untuk mengaktifkannya kembali.', + 'confirmPermanentlyDisallowTitle': 'Berhenti bertanya?', + 'confirmPermanentlyDisallowContent': 'Anda menolak izin {permission}. Berhenti bertanya mulai sekarang? Jika memilih "Jangan izinkan", Anda masih bisa mengaktifkannya nanti di pengaturan sistem.', + 'notNow': 'Nanti saja', + 'permanentlyDisallow': 'Jangan izinkan', + 'otaBesNotSupported': 'Headset ini belum mendukung pembaruan firmware dalam aplikasi. Silakan hubungi dukungan.', + 'tabDevice': 'Perangkat', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Teknologi untuk hidup lebih cerdas', + 'sloganAi': 'Kecerdasan tanpa batas', + 'sloganDevice': 'Perangkat keras pintar, siap masa depan', + 'sloganPlaza': 'Dunia cerdas yang memahami Anda', + 'aiEditHint': 'Tekan lama kartu untuk menyeret dan menyusun ulang modul', + 'aiEmptyTitle': 'Belum ada modul yang ditambahkan', + 'aiEmptyDesc': 'Pilih agen yang Anda butuhkan di Plaza', + 'goToPlaza': 'Buka Plaza', + 'plazaOnline': 'Tersedia', + 'plazaPlanned': 'Segera hadir', + 'plazaSearchHint': 'Cari agen, mis. “terjemah”, “rekam”', + 'moduleRemove': 'Hapus', + 'moduleAdd': 'Tambah', + 'moduleRemoved': 'Dihapus', + 'moduleAdded': 'Ditambahkan', + 'goSee': 'Lihat', + 'comingSoonTag': 'Segera hadir', + 'needDeviceTag': 'Perlu perangkat', + 'featureInDev': 'Fitur ini sedang dalam pengembangan', + 'featureNotWired': 'Belum tersedia', + 'todayLabel': 'Hari ini', + 'deviceConnected': 'Terhubung', + 'licenseUnknown': 'Lisensi tidak diketahui', + 'selectDevice': 'Pilih perangkat', + 'catNoteCard': 'Kartu Perekam AI', + 'catNoteCardDesc': 'Perekam berbentuk kartu', + 'catParkerPen': 'Pena AI', + 'catParkerPenDesc': 'Pena perekam suara', + 'catStylusPen': 'Stylus AI', + 'catStylusPenDesc': 'Perangkat tulisan tangan / stylus', + 'catStudyMachine': 'Tablet Belajar AI', + 'catStudyMachineDesc': 'Perangkat belajar', + 'besAddTitle': 'Tambah Earbud AI', + 'besConnecting': 'Menghubungkan ke earbud…', + 'besNotFound': 'Earbud tidak ditemukan', + 'besNotFoundIosDesc': 'Hubungkan earbud di Pengaturan → Bluetooth terlebih dahulu, lalu kembali ke sini', + 'besNotFoundAndroidDesc': 'Sandingkan earbud di Pengaturan → Bluetooth terlebih dahulu, lalu hubungkan di sini', + 'besReadFailed': 'Gagal membaca', + 'besConnectFailIos': 'Pastikan earbud berstatus Terhubung di Bluetooth sistem, lalu coba lagi', + 'besConnectFailAndroid': 'Pastikan earbud menyala, berada di dekat Anda, dan tidak terhubung ke perangkat lain. Earbud akan tersambung kembali secara otomatis setelah terhubung.', + 'holderAddTitle': 'Tambah Penyangga Ponsel AI', + 'holderConnecting': 'Menghubungkan ke perangkat…', + 'holderSearching': 'Mencari perangkat…', + 'holderNotFound': 'Tidak ada perangkat ditemukan', + 'holderPairHint': 'Pastikan penyangga menyala dan dalam mode penyandingan', + 'holderRetryHint': 'Pastikan perangkat menyala dan berada di dekat Anda, lalu coba lagi', + 'autoConnectTitle': 'Sambung otomatis perangkat', + 'autoConnectDesc': 'Bangunkan aplikasi untuk menyambung kembali dan menerima rekaman saat perangkat Anda menyala atau berada di dekat', + 'autoConnectConsentTitle': 'Aktifkan sambung otomatis', + 'autoConnectConsentIntro': 'Agar perangkat Anda (Earbud AI / Penyangga Ponsel AI) dapat tersambung otomatis dan menyimpan rekaman saat Anda menekan tombol rekamnya, kami memerlukan persetujuan Anda:', + 'autoConnectConsentB1': 'Mendaftarkan pemindaian Bluetooth latar belakang agar aplikasi dibangunkan (dijalankan otomatis) saat perangkat terikat Anda terdeteksi, untuk menyambung kembali dan menerima rekaman', + 'autoConnectConsentB2': 'Setelah dibangunkan, hanya digunakan untuk koneksi perangkat, perekaman, dan pengunggahan — tidak untuk hal lain, dan tidak ada aplikasi lain yang dijalankan', + 'autoConnectConsentB3': 'Anda tetap dapat menggunakan aplikasi tanpanya — cukup hubungkan perangkat secara manual setiap kali', + 'autoConnectConsentB4': 'Anda dapat menonaktifkannya kapan saja di Pengaturan → Sambung otomatis perangkat', + 'autoConnectAgree': 'Setuju dan aktifkan', + 'autoConnectLater': 'Nanti saja', + 'autoConnectRequired': 'Sambung otomatis nonaktif', + 'autoConnectRequiredDesc': 'Aktifkan sambung otomatis untuk mengikat perangkat ini', + 'recordTapToStart': 'Ketuk tombol di bawah untuk mulai merekam', + 'recordPaused': 'Dijeda', + 'recordMark': 'Tandai', + 'recordDeleteTitle': 'Hapus rekaman', + 'accountAndProfile': 'Akun & profil', + 'nicknameUnset': 'Nama panggilan belum diatur', + 'nicknameInput': 'Masukkan nama panggilan', + 'loginMethod': 'Metode masuk', + 'manageMyLogin': 'Kelola metode masuk', + 'logoutAction': 'Keluar', + 'warningLabel': 'Peringatan:', + 'deleteAccountWarn': 'Akun Anda dan semua file akan dihapus secara permanen.', + 'icpFiling': 'Pendaftaran ICP', + 'logExport': 'Ekspor log', + 'logExportDesc': 'Lihat dan ekspor log aplikasi', + 'permLoadFailed': 'Gagal memuat grup izin', + 'permInsufficient': 'Izin ditolak', + 'voiceCloneCreating': 'Membuat suara Anda…', + 'voiceCloneCreate': 'Buat suara saya', + 'voiceCloneAgree': 'Setuju dan bacakan pernyataan dengan lantang', + 'voiceCloneReadPrompt': 'Silakan baca:', + 'voiceCloneFirstMonthFree': 'Gratis bulan pertama', + 'voiceCloneEnable': 'Aktifkan kloning suara', + 'noMusicPlaying': 'Tidak ada yang diputar', + 'qqMusicNoSeek': 'Geser posisi tidak didukung untuk QQ Music', + 'bleScanTitle': 'Pemindaian BLE', + 'bluetoothOn': 'Bluetooth aktif', + 'bleScanning': 'Memindai…', + 'bleConnectedDevices': 'Perangkat terhubung', + 'bleUnknownDevice': 'Perangkat tidak dikenal', + 'bleTapToScan': 'Ketuk pindai untuk mencari perangkat BLE', + 'weekMon': 'Sen', + 'weekTue': 'Sel', + 'weekWed': 'Rab', + 'weekThu': 'Kam', + 'weekFri': 'Jum', + 'weekSat': 'Sab', + 'weekSun': 'Min', + 'agentMeeting': 'Notulen Suara', + 'agentMeetingDesc': 'Ringkas rekaman, pusat memori', + 'agentEmai': 'Asisten EMAI', + 'agentEmaiDesc': 'Mengobrol dan bertanya apa saja lewat suara', + 'agentSimultaneous': 'Terjemahan Langsung', + 'agentSimultaneousDesc': 'Terjemahkan sambil bicara', + 'agentFaceToFace': 'Tatap Muka', + 'agentFaceToFaceDesc': 'Terjemahan percakapan dua arah', + 'agentCallRecording': 'Rekaman Panggilan', + 'agentCallRecordingDesc': 'Panggilan tersimpan otomatis', + 'agentFieldRecording': 'Rekaman Lapangan', + 'agentFieldRecordingDesc': 'Mikrofon perangkat atau ponsel', + 'agentCall': 'Terjemahan Panggilan', + 'agentCallDesc': 'Terjemahan waktu nyata selama panggilan', + 'agentAudioVideo': 'Terjemahan Media', + 'agentAudioVideoDesc': 'Bidikan kamera / terjemahan audio & video', + 'agentEnglishChat': 'Obrolan Bahasa Inggris', + 'agentEnglishChatDesc': 'Latihan bicara imersif', + 'agentEnglishStudy': 'Belajar Bahasa Inggris', + 'agentEnglishStudyDesc': 'Pelajaran kosakata dan tata bahasa', + 'agentKidsStory': 'Cerita Anak', + 'agentKidsStoryDesc': 'Dongeng pengantar tidur dan tanya jawab', + 'moduleRemovedDesc': 'dihapus dari halaman AI', + 'moduleAddedDesc': 'ditambahkan ke bagian bawah halaman AI', + 'calNoRecords': 'Tidak ada entri', + 'calNoRecordsDay': 'Tidak ada jadwal', + 'calTodos': 'Tugas', + 'calExpenses': 'Pengeluaran', + 'calTodoCount': '@count tugas', + 'calExpenseCount': '@count pengeluaran', + 'calEntryCount': '@count entri', + 'calItemsUnit': 'item', + 'calCountUnit': 'entri', + 'calTotalAmount': 'Total', + 'recordPause': 'Jeda', + 'recordResume': 'Lanjutkan', + 'recordDeleteConfirm': 'Hapus rekaman ini?', + 'scopeDay': 'Hari', + 'scopeWeek': 'Minggu', + 'scopeMonth': 'Bulan', + 'allDay': 'Sepanjang hari', + 'guestModeTitle': 'Mode tamu', + 'guestModeDesc': 'Tamu hanya dapat menjelajah. Masuk untuk menggunakan catatan suara, terjemahan, dan perekaman — data Anda akan disimpan ke akun Anda.', + 'guestKeepBrowsing': 'Lanjut menjelajah', + 'guestGoLogin': 'Masuk', + 'guestViewOnlyTag': 'Hanya lihat', + 'autoConnectReenableHint': 'Sambung otomatis nonaktif. Aktifkan kembali di Pengaturan → Sambung otomatis perangkat.', + 'plazaEntryDesc': 'Jelajahi dan tambahkan lebih banyak agen', + 'agentTextTranslation': 'Terjemahan Teks', + 'agentTextTranslationDesc': 'Terjemahkan teks yang diketik atau ditempel', + 'agentPictureTranslation': 'Terjemahan Foto', + 'agentPictureTranslationDesc': 'Ambil atau pilih foto untuk diterjemahkan', + 'callRequiredTitle': 'Perlu panggilan', + 'callRequiredDesc': 'Fitur ini hanya berfungsi selama panggilan', + 'inCallBusyTitle': 'Tidak tersedia selama panggilan', + 'inCallBusyDesc': 'Mikrofon dan jalur audio sedang digunakan oleh panggilan. Coba lagi setelah menutup panggilan.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Gratis', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/is_is.dart b/apps/client/lib/core/translations/language/is_is.dart index 4d32ea7d..5676fdeb 100644 --- a/apps/client/lib/core/translations/language/is_is.dart +++ b/apps/client/lib/core/translations/language/is_is.dart @@ -1901,4 +1901,208 @@ const Map isIS = { 'unmarkFavorite': 'Fjarlægja úr eftirlæti', 'unnamedDevice': 'Ónefnt tæki', 'userDataParseFailed': 'Ekki tókst að lesa notandagögn', + 'catEarphone': 'AI eyrnatól', + 'catEarphoneDesc': 'Klassísk Bluetooth / BLE eyrnatól', + 'catPhoneHolder': 'AI símastandur', + 'catPhoneHolderDesc': 'Standtæki', + 'catCarAroma': 'AI bílailmur', + 'catCarAromaDesc': 'Ilmdreifir fyrir bíl', + 'agreeAndContinue': 'Samþykkja og halda áfram', + 'memberServiceAgreement': 'Þjónustusamningur meðlima', + 'memberServiceAgreementTitle': 'Þjónustusamningur meðlima', + 'memberServiceAgreementIntro': 'Til að veita þér betri meðlimaþjónustu, vinsamlegast lestu vandlega áður en þú gerist áskrifandi: ', + 'memberServiceAgreementOutro': '. Með því að smella á „Samþykkja og halda áfram“ staðfestir þú að þú hafir lesið samninginn hér að ofan að fullu og samþykkir hann.', + 'memberAgreementRejectedTip': 'Þú verður að samþykkja þjónustusamning meðlima til að halda áfram.', + 'translationCallExitTitle': 'Hætta símtalsþýðingu', + 'translationCallExitMessage': 'Veldu hvað á að gera áður en þú ferð', + 'translationCallEnd': 'Ljúka símtalsþýðingu', + 'translationContinueInBackground': 'Halda áfram að þýða í bakgrunni', + 'backgroundRecordingIndicatorBody': 'Upptaka heldur áfram í bakgrunni. Ýttu til að fara til baka.', + 'backgroundTranslationIndicatorBody': 'Símtalsþýðing heldur áfram í bakgrunni. Ýttu til að fara til baka.', + 'meetingRecordScreenCapturePermissionDenied': 'Heimild til skjáupptöku er nauðsynleg til að taka upp kerfishljóð. Veittu hana og reyndu aftur.', + 'pleaseGrantBluetoothPermission': 'Veittu Bluetooth-heimild til að leita', + 'startScanFailed': 'Ekki tókst að hefja leit', + 'pleaseLoginFirst': 'Skráðu þig fyrst inn', + 'deviceUnauthorized': 'Tæki ekki heimilað, reyndu aftur', + 'boundDevices': 'Tengd tæki', + 'currentConnection': 'Núverandi tenging', + 'binding': 'Tengi...', + 'permissionDisabled': 'Óvirkt', + 'confirmDisablePermissionTitle': 'Slökkva á heimild', + 'confirmDisablePermissionContent': 'Slökkva á {permission} heimild? Þú þarft að fara í kerfisstillingar til að virkja hana aftur.', + 'confirmPermanentlyDisallowTitle': 'Hætta að spyrja?', + 'confirmPermanentlyDisallowContent': 'Þú hafnaðir {permission} heimild. Hætta að spyrja héðan í frá? Ef þú velur „Ekki leyfa“ geturðu samt virkjað hana síðar í kerfisstillingum.', + 'notNow': 'Ekki núna', + 'permanentlyDisallow': 'Ekki leyfa', + 'otaBesNotSupported': 'Þessi heyrnartól styðja ekki enn fastbúnaðaruppfærslu í forritinu. Hafðu samband við þjónustuver.', + 'tabDevice': 'Tæki', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Tækni fyrir snjallara líf', + 'sloganAi': 'Takmarkalaus greind', + 'sloganDevice': 'Snjallur vélbúnaður, tilbúinn fyrir framtíðina', + 'sloganPlaza': 'Snjall heimur sem skilur þig', + 'aiEditHint': 'Haltu spjaldi inni og dragðu til að endurraða einingum', + 'aiEmptyTitle': 'Engum einingum bætt við enn', + 'aiEmptyDesc': 'Veldu þá aðstoðarmenn sem þú þarft í Plaza', + 'goToPlaza': 'Fara í Plaza', + 'plazaOnline': 'Í boði', + 'plazaPlanned': 'Væntanlegt', + 'plazaSearchHint': 'Leita að aðstoðarmönnum, t.d. „þýða“, „taka upp“', + 'moduleRemove': 'Fjarlægja', + 'moduleAdd': 'Bæta við', + 'moduleRemoved': 'Fjarlægt', + 'moduleAdded': 'Bætt við', + 'goSee': 'Skoða', + 'comingSoonTag': 'Væntanlegt', + 'needDeviceTag': 'Tæki nauðsynlegt', + 'featureInDev': 'Þessi eiginleiki er í þróun', + 'featureNotWired': 'Ekki í boði enn', + 'todayLabel': 'Í dag', + 'deviceConnected': 'Tengt', + 'licenseUnknown': 'Leyfi óþekkt', + 'selectDevice': 'Veldu tæki', + 'catNoteCard': 'AI upptökukort', + 'catNoteCardDesc': 'Upptökutæki í kortaformi', + 'catParkerPen': 'AI penni', + 'catParkerPenDesc': 'Upptökupennar', + 'catStylusPen': 'AI snertipenni', + 'catStylusPenDesc': 'Rithandar-/snertipennatæki', + 'catStudyMachine': 'AI námsspjaldtölva', + 'catStudyMachineDesc': 'Námstæki', + 'besAddTitle': 'Bæta við AI heyrnartólum', + 'besConnecting': 'Tengist heyrnartólum…', + 'besNotFound': 'Heyrnartól fundust ekki', + 'besNotFoundIosDesc': 'Tengdu heyrnartólin fyrst í Stillingar → Bluetooth og komdu svo til baka', + 'besNotFoundAndroidDesc': 'Paraðu heyrnartólin fyrst í Stillingar → Bluetooth og tengdu þau svo hér', + 'besReadFailed': 'Lestur mistókst', + 'besConnectFailIos': 'Gakktu úr skugga um að heyrnartólin séu sýnd sem „Tengd“ í Bluetooth-stillingum kerfisins, reyndu svo aftur', + 'besConnectFailAndroid': 'Gakktu úr skugga um að kveikt sé á heyrnartólunum, þau séu nálægt og ekki tengd öðru tæki. Þau tengjast sjálfkrafa aftur eftir pörun.', + 'holderAddTitle': 'Bæta við AI símastandi', + 'holderConnecting': 'Tengist tæki…', + 'holderSearching': 'Leita að tækjum…', + 'holderNotFound': 'Engin tæki fundust', + 'holderPairHint': 'Gakktu úr skugga um að standurinn sé kveiktur og í pörunarham', + 'holderRetryHint': 'Gakktu úr skugga um að tækið sé kveikt og nálægt, reyndu svo aftur', + 'autoConnectTitle': 'Sjálfvirk tenging tækja', + 'autoConnectDesc': 'Vekur forritið til að endurtengjast og taka við upptökum þegar kveikt er á tækinu eða það kemur nálægt', + 'autoConnectConsentTitle': 'Virkja sjálfvirka tengingu', + 'autoConnectConsentIntro': 'Til að tækið þitt (AI heyrnartól / AI símastandur) geti tengst sjálfkrafa og vistað upptökur þegar þú ýtir á upptökuhnapp þess þurfum við samþykki þitt:', + 'autoConnectConsentB1': 'Skrá Bluetooth-leit í bakgrunni svo forritið sé vakið (ræst sjálfkrafa) þegar tengt tæki finnst, til að endurtengjast og taka við upptökum', + 'autoConnectConsentB2': 'Eftir vakningu er þetta aðeins notað til að tengja tækið, taka upp og hlaða upp — ekkert annað, og engin önnur forrit eru ræst', + 'autoConnectConsentB3': 'Þú getur samt notað forritið án þess — tengdu bara tækið handvirkt í hvert sinn', + 'autoConnectConsentB4': 'Þú getur slökkt á þessu hvenær sem er í Stillingar → Sjálfvirk tenging tækja', + 'autoConnectAgree': 'Samþykkja og virkja', + 'autoConnectLater': 'Ekki núna', + 'autoConnectRequired': 'Slökkt er á sjálfvirkri tengingu', + 'autoConnectRequiredDesc': 'Virkjaðu sjálfvirka tengingu til að tengja þetta tæki', + 'recordTapToStart': 'Ýttu á hnappinn hér að neðan til að hefja upptöku', + 'recordPaused': 'Í bið', + 'recordMark': 'Merkja', + 'recordDeleteTitle': 'Eyða upptöku', + 'accountAndProfile': 'Reikningur og prófíll', + 'nicknameUnset': 'Ekkert gælunafn stillt', + 'nicknameInput': 'Sláðu inn gælunafn', + 'loginMethod': 'Innskráningarleið', + 'manageMyLogin': 'Stjórna innskráningu', + 'logoutAction': 'Skrá út', + 'warningLabel': 'Viðvörun:', + 'deleteAccountWarn': 'Reikningnum þínum og öllum skrám verður eytt varanlega.', + 'icpFiling': 'ICP-skráning', + 'logExport': 'Flytja út skrár', + 'logExportDesc': 'Skoða og flytja út atburðaskrár forritsins', + 'permLoadFailed': 'Ekki tókst að hlaða heimildaflokkum', + 'permInsufficient': 'Heimild hafnað', + 'voiceCloneCreating': 'Bý til röddina þína…', + 'voiceCloneCreate': 'Búa til mína rödd', + 'voiceCloneAgree': 'Samþykkja og lesa yfirlýsinguna upphátt', + 'voiceCloneReadPrompt': 'Lestu upphátt:', + 'voiceCloneFirstMonthFree': 'Fyrsti mánuðurinn ókeypis', + 'voiceCloneEnable': 'Virkja raddklónun', + 'noMusicPlaying': 'Ekkert í spilun', + 'qqMusicNoSeek': 'QQ Music styður ekki að spóla', + 'bleScanTitle': 'BLE-leit', + 'bluetoothOn': 'Kveikt á Bluetooth', + 'bleScanning': 'Leita…', + 'bleConnectedDevices': 'Tengd tæki', + 'bleUnknownDevice': 'Óþekkt tæki', + 'bleTapToScan': 'Ýttu á Leita til að finna BLE-tæki', + 'weekMon': 'Mán', + 'weekTue': 'Þri', + 'weekWed': 'Mið', + 'weekThu': 'Fim', + 'weekFri': 'Fös', + 'weekSat': 'Lau', + 'weekSun': 'Sun', + 'agentMeeting': 'Raddfundargerðir', + 'agentMeetingDesc': 'Draga saman upptökur, minnismiðstöð', + 'agentEmai': 'EMAI aðstoðarmaður', + 'agentEmaiDesc': 'Spjallaðu og spurðu um hvað sem er með röddinni', + 'agentSimultaneous': 'Samtímaþýðing', + 'agentSimultaneousDesc': 'Þýðir á meðan þú talar', + 'agentFaceToFace': 'Augliti til auglitis', + 'agentFaceToFaceDesc': 'Tvíátta samtalsþýðing', + 'agentCallRecording': 'Símtalsupptaka', + 'agentCallRecordingDesc': 'Símtöl vistuð sjálfkrafa', + 'agentFieldRecording': 'Vettvangsupptaka', + 'agentFieldRecordingDesc': 'Hljóðnemi tækis eða síma', + 'agentCall': 'Símtalsþýðing', + 'agentCallDesc': 'Rauntímaþýðing í símtölum', + 'agentAudioVideo': 'Miðlaþýðing', + 'agentAudioVideoDesc': 'Myndavélarrammi / hljóð- og myndþýðing', + 'agentEnglishChat': 'Enskuspjall', + 'agentEnglishChatDesc': 'Yfirgripsmikil talæfing', + 'agentEnglishStudy': 'Enskunám', + 'agentEnglishStudyDesc': 'Orðaforða- og málfræðikennsla', + 'agentKidsStory': 'Barnasögur', + 'agentKidsStoryDesc': 'Kvöldsögur og spurningar og svör', + 'moduleRemovedDesc': 'fjarlægt af AI-síðunni', + 'moduleAddedDesc': 'bætt neðst á AI-síðuna', + 'calNoRecords': 'Engar færslur', + 'calNoRecordsDay': 'Ekkert á dagskrá', + 'calTodos': 'Verkefni', + 'calExpenses': 'Útgjöld', + 'calTodoCount': '@count verkefni', + 'calExpenseCount': '@count útgjöld', + 'calEntryCount': '@count færslur', + 'calItemsUnit': 'atriði', + 'calCountUnit': 'færslur', + 'calTotalAmount': 'Samtals', + 'recordPause': 'Hlé', + 'recordResume': 'Halda áfram', + 'recordDeleteConfirm': 'Eyða þessari upptöku?', + 'scopeDay': 'Dagur', + 'scopeWeek': 'Vika', + 'scopeMonth': 'Mánuður', + 'allDay': 'Allan daginn', + 'guestModeTitle': 'Gestahamur', + 'guestModeDesc': 'Gestir geta aðeins skoðað. Skráðu þig inn til að nota raddminnispunkta, þýðingu og upptöku — gögnin þín verða vistuð á reikninginn þinn.', + 'guestKeepBrowsing': 'Halda áfram að skoða', + 'guestGoLogin': 'Skrá inn', + 'guestViewOnlyTag': 'Aðeins skoðun', + 'autoConnectReenableHint': 'Slökkt er á sjálfvirkri tengingu. Kveiktu aftur á henni í Stillingar → Sjálfvirk tenging tækja.', + 'plazaEntryDesc': 'Skoðaðu og bættu við fleiri aðstoðarmönnum', + 'agentTextTranslation': 'Textaþýðing', + 'agentTextTranslationDesc': 'Þýddu innsleginn eða límdan texta', + 'agentPictureTranslation': 'Myndaþýðing', + 'agentPictureTranslationDesc': 'Taktu eða veldu mynd til að þýða', + 'callRequiredTitle': 'Símtal nauðsynlegt', + 'callRequiredDesc': 'Þessi eiginleiki virkar aðeins í símtali', + 'inCallBusyTitle': 'Ekki í boði í símtali', + 'inCallBusyDesc': 'Hljóðneminn og hljóðleiðin eru í notkun í símtalinu. Reyndu aftur eftir að þú leggur á.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Ókeypis', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/it_it.dart b/apps/client/lib/core/translations/language/it_it.dart index fd21e174..b9a6b4a7 100644 --- a/apps/client/lib/core/translations/language/it_it.dart +++ b/apps/client/lib/core/translations/language/it_it.dart @@ -1942,4 +1942,208 @@ const Map itIT = { 'unmarkFavorite': 'Rimuovi dai preferiti', 'unnamedDevice': 'Dispositivo senza nome', 'userDataParseFailed': "Impossibile leggere i dati dell'utente", + 'catEarphone': 'Auricolari IA', + 'catEarphoneDesc': 'Auricolari Bluetooth classico / BLE', + 'catPhoneHolder': 'Supporto telefono IA', + 'catPhoneHolderDesc': 'Dispositivi di supporto', + 'catCarAroma': 'Diffusore auto IA', + 'catCarAromaDesc': 'Diffusore di aromi per auto', + 'agreeAndContinue': 'Accetta e continua', + 'memberServiceAgreement': 'Contratto di servizio per gli abbonati', + 'memberServiceAgreementTitle': 'Contratto di servizio per gli abbonati', + 'memberServiceAgreementIntro': 'Per offrirti un servizio migliore, leggi attentamente prima di abbonarti: ', + 'memberServiceAgreementOutro': '. Facendo clic su "Accetta e continua" confermi di aver letto integralmente e di accettare il contratto sopra indicato.', + 'memberAgreementRejectedTip': 'Devi accettare il Contratto di servizio per gli abbonati per continuare.', + 'translationCallExitTitle': 'Esci dalla traduzione chiamate', + 'translationCallExitMessage': 'Scegli cosa fare prima di uscire', + 'translationCallEnd': 'Termina traduzione chiamata', + 'translationContinueInBackground': 'Continua a tradurre in background', + 'backgroundRecordingIndicatorBody': 'La registrazione continua in background. Tocca per tornare.', + 'backgroundTranslationIndicatorBody': 'La traduzione della chiamata continua in background. Tocca per tornare.', + 'meetingRecordScreenCapturePermissionDenied': 'Per registrare l\'audio di sistema è necessario il permesso di registrazione dello schermo. Concedilo e riprova.', + 'pleaseGrantBluetoothPermission': 'Concedi il permesso Bluetooth per la scansione', + 'startScanFailed': 'Impossibile avviare la scansione', + 'pleaseLoginFirst': 'Accedi prima di continuare', + 'deviceUnauthorized': 'Dispositivo non autorizzato, riprova', + 'boundDevices': 'Dispositivi associati', + 'currentConnection': 'Connessione attuale', + 'binding': 'Associazione...', + 'permissionDisabled': 'Disattivato', + 'confirmDisablePermissionTitle': 'Disattivare il permesso', + 'confirmDisablePermissionContent': 'Disattivare il permesso {permission}? Dovrai riattivarlo dalle impostazioni di sistema.', + 'confirmPermanentlyDisallowTitle': 'Non chiedere più?', + 'confirmPermanentlyDisallowContent': 'Hai negato il permesso {permission}. Non chiedere più? Se scegli "Non consentire", potrai comunque attivarlo in seguito dalle impostazioni di sistema.', + 'notNow': 'Non ora', + 'permanentlyDisallow': 'Non consentire', + 'otaBesNotSupported': 'Queste cuffie non supportano ancora l\'aggiornamento del firmware dall\'app. Contatta l\'assistenza.', + 'tabDevice': 'Dispositivi', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Tecnologia per una vita più smart', + 'sloganAi': 'Intelligenza senza limiti', + 'sloganDevice': 'Hardware intelligente, pronto per il futuro', + 'sloganPlaza': 'Un mondo smart che ti capisce', + 'aiEditHint': 'Tieni premuta una scheda per trascinare e riordinare i moduli', + 'aiEmptyTitle': 'Nessun modulo aggiunto', + 'aiEmptyDesc': 'Scegli gli agenti che ti servono in Plaza', + 'goToPlaza': 'Vai a Plaza', + 'plazaOnline': 'Disponibile', + 'plazaPlanned': 'Prossimamente', + 'plazaSearchHint': 'Cerca agenti, es. “traduci”, “registra”', + 'moduleRemove': 'Rimuovi', + 'moduleAdd': 'Aggiungi', + 'moduleRemoved': 'Rimosso', + 'moduleAdded': 'Aggiunto', + 'goSee': 'Vedi', + 'comingSoonTag': 'Prossimamente', + 'needDeviceTag': 'Dispositivo richiesto', + 'featureInDev': 'Questa funzione è in fase di sviluppo', + 'featureNotWired': 'Non ancora disponibile', + 'todayLabel': 'Oggi', + 'deviceConnected': 'Connesso', + 'licenseUnknown': 'Licenza sconosciuta', + 'selectDevice': 'Seleziona un dispositivo', + 'catNoteCard': 'Scheda registratore AI', + 'catNoteCardDesc': 'Registratore a forma di scheda', + 'catParkerPen': 'Penna AI', + 'catParkerPenDesc': 'Penne con registratore vocale', + 'catStylusPen': 'Stilo AI', + 'catStylusPenDesc': 'Dispositivi per scrittura a mano / stilo', + 'catStudyMachine': 'Tablet didattico AI', + 'catStudyMachineDesc': 'Dispositivi per l\'apprendimento', + 'besAddTitle': 'Aggiungi auricolari AI', + 'besConnecting': 'Connessione agli auricolari…', + 'besNotFound': 'Auricolari non trovati', + 'besNotFoundIosDesc': 'Connetti prima gli auricolari in Impostazioni → Bluetooth, poi torna qui', + 'besNotFoundAndroidDesc': 'Associa prima gli auricolari in Impostazioni → Bluetooth, poi connettili qui', + 'besReadFailed': 'Lettura non riuscita', + 'besConnectFailIos': 'Assicurati che gli auricolari risultino Connessi nel Bluetooth di sistema, poi riprova', + 'besConnectFailAndroid': 'Assicurati che gli auricolari siano accesi, nelle vicinanze e non connessi a un altro dispositivo. Una volta associati si riconnetteranno automaticamente.', + 'holderAddTitle': 'Aggiungi supporto AI per telefono', + 'holderConnecting': 'Connessione al dispositivo…', + 'holderSearching': 'Ricerca dispositivi…', + 'holderNotFound': 'Nessun dispositivo trovato', + 'holderPairHint': 'Assicurati che il supporto sia acceso e in modalità di associazione', + 'holderRetryHint': 'Assicurati che il dispositivo sia acceso e nelle vicinanze, poi riprova', + 'autoConnectTitle': 'Connessione automatica dispositivi', + 'autoConnectDesc': 'Riattiva l\'app per riconnettersi e ricevere le registrazioni quando il dispositivo si accende o si avvicina', + 'autoConnectConsentTitle': 'Attiva la connessione automatica', + 'autoConnectConsentIntro': 'Per consentire al tuo dispositivo (auricolari AI / supporto AI per telefono) di connettersi automaticamente e salvare le registrazioni quando premi il suo tasto di registrazione, abbiamo bisogno del tuo consenso:', + 'autoConnectConsentB1': 'Registrare una scansione Bluetooth in background così che l\'app venga riattivata (avviata automaticamente) quando viene rilevato il dispositivo associato, per riconnettersi e ricevere le registrazioni', + 'autoConnectConsentB2': 'Una volta riattivata, viene usata solo per la connessione del dispositivo, la registrazione e il caricamento — nient\'altro, e non viene avviata nessun\'altra app', + 'autoConnectConsentB3': 'Puoi comunque usare l\'app senza questa funzione — basta connettere il dispositivo manualmente ogni volta', + 'autoConnectConsentB4': 'Puoi disattivarla in qualsiasi momento in Impostazioni → Connessione automatica dispositivi', + 'autoConnectAgree': 'Accetta e attiva', + 'autoConnectLater': 'Non ora', + 'autoConnectRequired': 'Connessione automatica disattivata', + 'autoConnectRequiredDesc': 'Attiva la connessione automatica per associare questo dispositivo', + 'recordTapToStart': 'Tocca il pulsante in basso per iniziare a registrare', + 'recordPaused': 'In pausa', + 'recordMark': 'Segna', + 'recordDeleteTitle': 'Elimina registrazione', + 'accountAndProfile': 'Account e profilo', + 'nicknameUnset': 'Nessun soprannome impostato', + 'nicknameInput': 'Inserisci un soprannome', + 'loginMethod': 'Metodo di accesso', + 'manageMyLogin': 'Gestisci accesso', + 'logoutAction': 'Esci', + 'warningLabel': 'Attenzione:', + 'deleteAccountWarn': 'Il tuo account e tutti i file verranno eliminati definitivamente.', + 'icpFiling': 'Registrazione ICP', + 'logExport': 'Esporta log', + 'logExportDesc': 'Visualizza ed esporta i log dell\'app', + 'permLoadFailed': 'Impossibile caricare i gruppi di permessi', + 'permInsufficient': 'Permesso negato', + 'voiceCloneCreating': 'Creazione della tua voce…', + 'voiceCloneCreate': 'Crea la mia voce', + 'voiceCloneAgree': 'Accetta e leggi la dichiarazione ad alta voce', + 'voiceCloneReadPrompt': 'Leggi:', + 'voiceCloneFirstMonthFree': 'Primo mese gratis', + 'voiceCloneEnable': 'Attiva la clonazione vocale', + 'noMusicPlaying': 'Nessuna riproduzione in corso', + 'qqMusicNoSeek': 'Lo scorrimento non è supportato per QQ Music', + 'bleScanTitle': 'Scansione BLE', + 'bluetoothOn': 'Bluetooth attivo', + 'bleScanning': 'Scansione…', + 'bleConnectedDevices': 'Dispositivi connessi', + 'bleUnknownDevice': 'Dispositivo sconosciuto', + 'bleTapToScan': 'Tocca Scansiona per cercare dispositivi BLE', + 'weekMon': 'Lun', + 'weekTue': 'Mar', + 'weekWed': 'Mer', + 'weekThu': 'Gio', + 'weekFri': 'Ven', + 'weekSat': 'Sab', + 'weekSun': 'Dom', + 'agentMeeting': 'Verbali vocali', + 'agentMeetingDesc': 'Riassume le registrazioni, hub della memoria', + 'agentEmai': 'Assistente EMAI', + 'agentEmaiDesc': 'Chatta e chiedi qualsiasi cosa con la voce', + 'agentSimultaneous': 'Traduzione simultanea', + 'agentSimultaneousDesc': 'Traduce mentre parli', + 'agentFaceToFace': 'Faccia a faccia', + 'agentFaceToFaceDesc': 'Traduzione bidirezionale delle conversazioni', + 'agentCallRecording': 'Registrazione chiamate', + 'agentCallRecordingDesc': 'Chiamate salvate automaticamente', + 'agentFieldRecording': 'Registrazione live', + 'agentFieldRecordingDesc': 'Microfono del dispositivo o del telefono', + 'agentCall': 'Traduzione chiamate', + 'agentCallDesc': 'Traduzione in tempo reale durante le chiamate', + 'agentAudioVideo': 'Traduzione multimediale', + 'agentAudioVideoDesc': 'Inquadratura fotocamera / traduzione audio e video', + 'agentEnglishChat': 'Conversazione in inglese', + 'agentEnglishChatDesc': 'Pratica orale immersiva', + 'agentEnglishStudy': 'Studio dell\'inglese', + 'agentEnglishStudyDesc': 'Lezioni di vocabolario e grammatica', + 'agentKidsStory': 'Storie per bambini', + 'agentKidsStoryDesc': 'Storie della buonanotte e domande e risposte', + 'moduleRemovedDesc': 'rimosso dalla pagina AI', + 'moduleAddedDesc': 'aggiunto in fondo alla pagina AI', + 'calNoRecords': 'Nessuna voce', + 'calNoRecordsDay': 'Niente in programma', + 'calTodos': 'Da fare', + 'calExpenses': 'Spese', + 'calTodoCount': '@count attività', + 'calExpenseCount': '@count spese', + 'calEntryCount': '@count voci', + 'calItemsUnit': 'elementi', + 'calCountUnit': 'voci', + 'calTotalAmount': 'Totale', + 'recordPause': 'Pausa', + 'recordResume': 'Riprendi', + 'recordDeleteConfirm': 'Eliminare questa registrazione?', + 'scopeDay': 'Giorno', + 'scopeWeek': 'Settimana', + 'scopeMonth': 'Mese', + 'allDay': 'Tutto il giorno', + 'guestModeTitle': 'Modalità ospite', + 'guestModeDesc': 'Gli ospiti possono solo navigare. Accedi per usare note vocali, traduzione e registrazione — i tuoi dati verranno salvati nel tuo account.', + 'guestKeepBrowsing': 'Continua a navigare', + 'guestGoLogin': 'Accedi', + 'guestViewOnlyTag': 'Solo visualizzazione', + 'autoConnectReenableHint': 'La connessione automatica è disattivata. Riattivala in Impostazioni → Connessione automatica dispositivi.', + 'plazaEntryDesc': 'Sfoglia e aggiungi altri agenti', + 'agentTextTranslation': 'Traduzione testo', + 'agentTextTranslationDesc': 'Traduci testo digitato o incollato', + 'agentPictureTranslation': 'Traduzione foto', + 'agentPictureTranslationDesc': 'Scatta o scegli una foto da tradurre', + 'callRequiredTitle': 'Chiamata richiesta', + 'callRequiredDesc': 'Questa funzione è disponibile solo durante una chiamata', + 'inCallBusyTitle': 'Non disponibile durante una chiamata', + 'inCallBusyDesc': 'Il microfono e il percorso audio sono in uso dalla chiamata. Riprova dopo aver riagganciato.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Gratis', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/ja_jp.dart b/apps/client/lib/core/translations/language/ja_jp.dart index 68a8540f..a85b8d2a 100644 --- a/apps/client/lib/core/translations/language/ja_jp.dart +++ b/apps/client/lib/core/translations/language/ja_jp.dart @@ -1683,6 +1683,8 @@ const Map jaJP = { 'catNoteCardDesc': 'カード型レコーダー', 'catPhoneHolder': 'AI スマホスタンド', 'catPhoneHolderDesc': 'スタンド型デバイス', + 'catCarAroma': 'AI カーアロマ', + 'catCarAromaDesc': '車載アロマディフューザー', 'catParkerPen': 'AI ペン', 'catParkerPenDesc': 'ボイスレコーダーペン', 'catStylusPen': 'AI スタイラス', @@ -1937,4 +1939,32 @@ const Map jaJP = { 'unmarkFavorite': 'お気に入りから削除', 'unnamedDevice': '名称未設定のデバイス', 'userDataParseFailed': 'ユーザーデータの解析に失敗しました', + 'translationCallExitTitle': '通話翻訳を終了', + 'translationCallExitMessage': '離れる前の操作を選択してください', + 'translationCallEnd': '通話翻訳を終了する', + 'translationContinueInBackground': 'バックグラウンドで翻訳を続ける', + 'backgroundRecordingIndicatorBody': 'バックグラウンドで録音を続けています。タップして戻る', + 'backgroundTranslationIndicatorBody': 'バックグラウンドで通話翻訳を続けています。タップして戻る', + 'permissionDisabled': '無効', + 'confirmDisablePermissionTitle': '権限をオフにする', + 'confirmDisablePermissionContent': '{permission}の権限をオフにしますか?再度有効にするにはシステム設定から操作する必要があります。', + 'confirmPermanentlyDisallowTitle': '今後確認しない?', + 'confirmPermanentlyDisallowContent': '{permission}の権限が拒否されました。今後は確認しないようにしますか?「許可しない」を選んでも、後からシステム設定で有効にできます。', + 'notNow': '今はしない', + 'permanentlyDisallow': '許可しない', + 'otaBesNotSupported': 'このイヤホンはアプリ内でのファームウェアアップグレードにまだ対応していません。サポートにお問い合わせください。', + 'smartcarConnected': '接続しました', + 'smartcarConnectFailed': '接続に失敗しました', + 'smartcarConnecting': '接続中…', + 'smartcarSearching': '近くの車載アロマを検索中…', + 'smartcarNotFound': 'デバイスが見つかりません', + 'smartcarScanHint': '電源が入っていること、スマホの近くにあることを確認してください', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/ko_kr.dart b/apps/client/lib/core/translations/language/ko_kr.dart index 659dbc0d..5483accd 100644 --- a/apps/client/lib/core/translations/language/ko_kr.dart +++ b/apps/client/lib/core/translations/language/ko_kr.dart @@ -1688,6 +1688,8 @@ const Map koKR = { 'catNoteCardDesc': '카드형 녹음 기기', 'catPhoneHolder': 'AI 휴대폰 거치대', 'catPhoneHolderDesc': '거치대형 기기', + 'catCarAroma': 'AI 차량용 방향제', + 'catCarAromaDesc': '차량용 방향제 기기', 'catParkerPen': 'AI 펜', 'catParkerPenDesc': '녹음 펜 기기', 'catStylusPen': 'AI 스타일러스', @@ -1930,4 +1932,32 @@ const Map koKR = { 'unmarkFavorite': '즐겨찾기 해제', 'unnamedDevice': '이름 없는 기기', 'userDataParseFailed': '사용자 데이터 분석 실패', + 'translationCallExitTitle': '통화 번역 나가기', + 'translationCallExitMessage': '나가기 전에 할 작업을 선택하세요', + 'translationCallEnd': '통화 번역 종료', + 'translationContinueInBackground': '백그라운드에서 번역 계속하기', + 'backgroundRecordingIndicatorBody': '백그라운드에서 녹음이 계속되고 있습니다. 탭하여 돌아가기', + 'backgroundTranslationIndicatorBody': '백그라운드에서 통화 번역이 계속되고 있습니다. 탭하여 돌아가기', + 'permissionDisabled': '비활성화됨', + 'confirmDisablePermissionTitle': '권한 끄기', + 'confirmDisablePermissionContent': '{permission} 권한을 끄시겠습니까? 다시 켜려면 시스템 설정으로 이동해야 합니다.', + 'confirmPermanentlyDisallowTitle': '더 이상 묻지 않을까요?', + 'confirmPermanentlyDisallowContent': '{permission} 권한을 거부하셨습니다. 앞으로 다시 묻지 않을까요? \'허용 안 함\'을 선택해도 나중에 시스템 설정에서 켤 수 있습니다.', + 'notNow': '나중에', + 'permanentlyDisallow': '허용 안 함', + 'otaBesNotSupported': '이 이어폰은 아직 앱 내 펌웨어 업그레이드를 지원하지 않습니다. 고객 지원에 문의해 주세요.', + 'smartcarConnected': '연결됨', + 'smartcarConnectFailed': '연결 실패', + 'smartcarConnecting': '연결 중…', + 'smartcarSearching': '주변 차량용 방향제 검색 중…', + 'smartcarNotFound': '기기를 찾을 수 없습니다', + 'smartcarScanHint': '기기 전원이 켜져 있고 휴대폰 근처에 있는지 확인하세요', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/lt_lt.dart b/apps/client/lib/core/translations/language/lt_lt.dart index 5a57283f..903c5f43 100644 --- a/apps/client/lib/core/translations/language/lt_lt.dart +++ b/apps/client/lib/core/translations/language/lt_lt.dart @@ -1919,4 +1919,208 @@ const Map ltLT = { 'unmarkFavorite': 'Pašalinti iš mėgstamų', 'unnamedDevice': 'Įrenginys be pavadinimo', 'userDataParseFailed': 'Nepavyko nuskaityti naudotojo duomenų', + 'catEarphone': 'AI ausinės', + 'catEarphoneDesc': 'Klasikinės Bluetooth / BLE ausinės', + 'catPhoneHolder': 'AI telefono laikiklis', + 'catPhoneHolderDesc': 'Laikiklio įrenginiai', + 'catCarAroma': 'AI automobilio kvapas', + 'catCarAromaDesc': 'Automobilio aromato difuzorius', + 'agreeAndContinue': 'Sutikti ir tęsti', + 'memberServiceAgreement': 'Narystės paslaugų sutartis', + 'memberServiceAgreementTitle': 'Narystės paslaugų sutartis', + 'memberServiceAgreementIntro': 'Kad galėtume teikti geresnes narystės paslaugas, prieš prenumeruodami atidžiai perskaitykite: ', + 'memberServiceAgreementOutro': '. Spustelėdami „Sutikti ir tęsti“ patvirtinate, kad visiškai perskaitėte ir sutinkate su aukščiau pateikta sutartimi.', + 'memberAgreementRejectedTip': 'Norėdami tęsti, turite sutikti su Narystės paslaugų sutartimi.', + 'translationCallExitTitle': 'Išeiti iš skambučių vertimo', + 'translationCallExitMessage': 'Pasirinkite, ką daryti prieš išeinant', + 'translationCallEnd': 'Baigti skambučio vertimą', + 'translationContinueInBackground': 'Tęsti vertimą fone', + 'backgroundRecordingIndicatorBody': 'Įrašymas tęsiamas fone. Palieskite, kad grįžtumėte.', + 'backgroundTranslationIndicatorBody': 'Skambučio vertimas tęsiamas fone. Palieskite, kad grįžtumėte.', + 'meetingRecordScreenCapturePermissionDenied': 'Sistemos garsui įrašyti reikalingas ekrano įrašymo leidimas. Suteikite jį ir bandykite dar kartą.', + 'pleaseGrantBluetoothPermission': 'Suteikite Bluetooth leidimą, kad būtų galima skenuoti', + 'startScanFailed': 'Nepavyko pradėti skenavimo', + 'pleaseLoginFirst': 'Pirmiausia prisijunkite', + 'deviceUnauthorized': 'Įrenginys neautorizuotas, bandykite dar kartą', + 'boundDevices': 'Susieti įrenginiai', + 'currentConnection': 'Dabartinis ryšys', + 'binding': 'Siejama...', + 'permissionDisabled': 'Išjungta', + 'confirmDisablePermissionTitle': 'Išjungti leidimą', + 'confirmDisablePermissionContent': 'Išjungti {permission} leidimą? Norėdami jį vėl įjungti, turėsite eiti į sistemos nustatymus.', + 'confirmPermanentlyDisallowTitle': 'Daugiau neklausti?', + 'confirmPermanentlyDisallowContent': 'Atmetėte {permission} leidimą. Daugiau neklausti? Jei pasirinksite „Neleisti“, vėliau vis tiek galėsite jį įjungti sistemos nustatymuose.', + 'notNow': 'Ne dabar', + 'permanentlyDisallow': 'Neleisti', + 'otaBesNotSupported': 'Šios ausinės dar nepalaiko programinės aparatinės įrangos atnaujinimo per programą. Susisiekite su palaikymo tarnyba.', + 'tabDevice': 'Įrenginiai', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Technologijos išmanesniam gyvenimui', + 'sloganAi': 'Beribis intelektas', + 'sloganDevice': 'Išmanioji įranga, pasirengusi ateičiai', + 'sloganPlaza': 'Išmanus pasaulis, kuris jus supranta', + 'aiEditHint': 'Ilgai palaikykite kortelę, kad vilkdami pertvarkytumėte modulius', + 'aiEmptyTitle': 'Modulių dar nepridėta', + 'aiEmptyDesc': 'Pasirinkite reikalingus agentus „Plaza“ skiltyje', + 'goToPlaza': 'Eiti į „Plaza“', + 'plazaOnline': 'Prieinama', + 'plazaPlanned': 'Netrukus', + 'plazaSearchHint': 'Ieškoti agentų, pvz., „versti“, „įrašyti“', + 'moduleRemove': 'Pašalinti', + 'moduleAdd': 'Pridėti', + 'moduleRemoved': 'Pašalinta', + 'moduleAdded': 'Pridėta', + 'goSee': 'Peržiūrėti', + 'comingSoonTag': 'Netrukus', + 'needDeviceTag': 'Reikia įrenginio', + 'featureInDev': 'Ši funkcija dar kuriama', + 'featureNotWired': 'Dar neprieinama', + 'todayLabel': 'Šiandien', + 'deviceConnected': 'Prisijungta', + 'licenseUnknown': 'Licencija nežinoma', + 'selectDevice': 'Pasirinkite įrenginį', + 'catNoteCard': 'AI įrašymo kortelė', + 'catNoteCardDesc': 'Kortelės formos įrašytuvas', + 'catParkerPen': 'AI rašiklis', + 'catParkerPenDesc': 'Rašikliai su balso įrašymu', + 'catStylusPen': 'AI jutiklinis rašiklis', + 'catStylusPenDesc': 'Rašymo ranka / jutiklinio rašiklio įrenginiai', + 'catStudyMachine': 'AI mokymosi planšetė', + 'catStudyMachineDesc': 'Mokymosi įrenginiai', + 'besAddTitle': 'Pridėti AI ausines', + 'besConnecting': 'Jungiamasi prie ausinių…', + 'besNotFound': 'Ausinės nerastos', + 'besNotFoundIosDesc': 'Pirmiausia prijunkite ausines per Nustatymai → Bluetooth, tada grįžkite čia', + 'besNotFoundAndroidDesc': 'Pirmiausia susiekite ausines per Nustatymai → Bluetooth, tada prijunkite čia', + 'besReadFailed': 'Nepavyko nuskaityti', + 'besConnectFailIos': 'Įsitikinkite, kad sistemos Bluetooth nustatymuose ausinės rodomos kaip prijungtos, tada bandykite dar kartą', + 'besConnectFailAndroid': 'Įsitikinkite, kad ausinės įjungtos, yra netoliese ir neprijungtos prie kito įrenginio. Susiejus jos prisijungs automatiškai.', + 'holderAddTitle': 'Pridėti AI telefono laikiklį', + 'holderConnecting': 'Jungiamasi prie įrenginio…', + 'holderSearching': 'Ieškoma įrenginių…', + 'holderNotFound': 'Įrenginių nerasta', + 'holderPairHint': 'Įsitikinkite, kad laikiklis įjungtas ir veikia susiejimo režimu', + 'holderRetryHint': 'Įsitikinkite, kad įrenginys įjungtas ir yra netoliese, tada bandykite dar kartą', + 'autoConnectTitle': 'Automatinis įrenginių prijungimas', + 'autoConnectDesc': 'Pažadina programą, kad ji vėl prisijungtų ir gautų įrašus, kai įrenginys įsijungia arba atsiduria netoliese', + 'autoConnectConsentTitle': 'Įjungti automatinį prijungimą', + 'autoConnectConsentIntro': 'Kad jūsų įrenginys (AI ausinės / AI telefono laikiklis) galėtų prisijungti automatiškai ir išsaugoti įrašus paspaudus jo įrašymo mygtuką, mums reikia jūsų sutikimo:', + 'autoConnectConsentB1': 'Užregistruoti Bluetooth skenavimą fone, kad aptikus susietą įrenginį programa būtų pažadinta (paleista automatiškai) ir galėtų vėl prisijungti bei gauti įrašus', + 'autoConnectConsentB2': 'Pažadinta programa naudojama tik įrenginio prijungimui, įrašymui ir įkėlimui — niekam kitam, ir jokios kitos programos nepaleidžiamos', + 'autoConnectConsentB3': 'Programą galite naudoti ir be to — tiesiog kiekvieną kartą prijunkite įrenginį rankiniu būdu', + 'autoConnectConsentB4': 'Bet kada galite tai išjungti: Nustatymai → Automatinis įrenginių prijungimas', + 'autoConnectAgree': 'Sutikti ir įjungti', + 'autoConnectLater': 'Ne dabar', + 'autoConnectRequired': 'Automatinis prijungimas išjungtas', + 'autoConnectRequiredDesc': 'Įjunkite automatinį prijungimą, kad susietumėte šį įrenginį', + 'recordTapToStart': 'Palieskite mygtuką apačioje, kad pradėtumėte įrašyti', + 'recordPaused': 'Pristabdyta', + 'recordMark': 'Žymėti', + 'recordDeleteTitle': 'Ištrinti įrašą', + 'accountAndProfile': 'Paskyra ir profilis', + 'nicknameUnset': 'Slapyvardis nenustatytas', + 'nicknameInput': 'Įveskite slapyvardį', + 'loginMethod': 'Prisijungimo būdas', + 'manageMyLogin': 'Tvarkyti prisijungimą', + 'logoutAction': 'Atsijungti', + 'warningLabel': 'Įspėjimas:', + 'deleteAccountWarn': 'Jūsų paskyra ir visi failai bus visam laikui ištrinti.', + 'icpFiling': 'ICP registracija', + 'logExport': 'Eksportuoti žurnalus', + 'logExportDesc': 'Peržiūrėti ir eksportuoti programos žurnalus', + 'permLoadFailed': 'Nepavyko įkelti leidimų grupių', + 'permInsufficient': 'Leidimas nesuteiktas', + 'voiceCloneCreating': 'Kuriamas jūsų balsas…', + 'voiceCloneCreate': 'Sukurti mano balsą', + 'voiceCloneAgree': 'Sutikti ir garsiai perskaityti pareiškimą', + 'voiceCloneReadPrompt': 'Perskaitykite:', + 'voiceCloneFirstMonthFree': 'Pirmas mėnuo nemokamai', + 'voiceCloneEnable': 'Įjungti balso klonavimą', + 'noMusicPlaying': 'Niekas negrojama', + 'qqMusicNoSeek': '„QQ Music“ nepalaiko persukimo', + 'bleScanTitle': 'BLE skenavimas', + 'bluetoothOn': 'Bluetooth įjungtas', + 'bleScanning': 'Skenuojama…', + 'bleConnectedDevices': 'Prijungti įrenginiai', + 'bleUnknownDevice': 'Nežinomas įrenginys', + 'bleTapToScan': 'Palieskite „Skenuoti“, kad ieškotumėte BLE įrenginių', + 'weekMon': 'Pr', + 'weekTue': 'An', + 'weekWed': 'Tr', + 'weekThu': 'Kt', + 'weekFri': 'Pn', + 'weekSat': 'Št', + 'weekSun': 'Sk', + 'agentMeeting': 'Balso protokolai', + 'agentMeetingDesc': 'Įrašų santraukos, atminties centras', + 'agentEmai': 'EMAI asistentas', + 'agentEmaiDesc': 'Kalbėkitės ir klauskite bet ko balsu', + 'agentSimultaneous': 'Sinchroninis vertimas', + 'agentSimultaneousDesc': 'Verčia jums kalbant', + 'agentFaceToFace': 'Akis į akį', + 'agentFaceToFaceDesc': 'Dvikryptis pokalbių vertimas', + 'agentCallRecording': 'Skambučių įrašymas', + 'agentCallRecordingDesc': 'Skambučiai išsaugomi automatiškai', + 'agentFieldRecording': 'Tiesioginis įrašymas', + 'agentFieldRecordingDesc': 'Įrenginio arba telefono mikrofonas', + 'agentCall': 'Skambučių vertimas', + 'agentCallDesc': 'Vertimas realiuoju laiku skambučių metu', + 'agentAudioVideo': 'Medijos vertimas', + 'agentAudioVideoDesc': 'Kameros kadravimas / garso ir vaizdo vertimas', + 'agentEnglishChat': 'Pokalbiai anglų kalba', + 'agentEnglishChatDesc': 'Įtraukianti kalbėjimo praktika', + 'agentEnglishStudy': 'Anglų kalbos mokymasis', + 'agentEnglishStudyDesc': 'Žodyno ir gramatikos pamokos', + 'agentKidsStory': 'Pasakos vaikams', + 'agentKidsStoryDesc': 'Pasakos prieš miegą ir klausimai-atsakymai', + 'moduleRemovedDesc': 'pašalinta iš AI puslapio', + 'moduleAddedDesc': 'pridėta AI puslapio apačioje', + 'calNoRecords': 'Įrašų nėra', + 'calNoRecordsDay': 'Nieko nesuplanuota', + 'calTodos': 'Darbai', + 'calExpenses': 'Išlaidos', + 'calTodoCount': 'Darbų: @count', + 'calExpenseCount': 'Išlaidų: @count', + 'calEntryCount': 'Įrašų: @count', + 'calItemsUnit': 'vnt.', + 'calCountUnit': 'įrašai', + 'calTotalAmount': 'Iš viso', + 'recordPause': 'Pristabdyti', + 'recordResume': 'Tęsti', + 'recordDeleteConfirm': 'Ištrinti šį įrašą?', + 'scopeDay': 'Diena', + 'scopeWeek': 'Savaitė', + 'scopeMonth': 'Mėnuo', + 'allDay': 'Visą dieną', + 'guestModeTitle': 'Svečio režimas', + 'guestModeDesc': 'Svečiai gali tik naršyti. Prisijunkite, kad naudotumėte balso užrašus, vertimą ir įrašymą — jūsų duomenys bus išsaugoti jūsų paskyroje.', + 'guestKeepBrowsing': 'Toliau naršyti', + 'guestGoLogin': 'Prisijungti', + 'guestViewOnlyTag': 'Tik peržiūra', + 'autoConnectReenableHint': 'Automatinis prijungimas išjungtas. Vėl įjunkite: Nustatymai → Automatinis įrenginių prijungimas.', + 'plazaEntryDesc': 'Naršykite ir pridėkite daugiau agentų', + 'agentTextTranslation': 'Teksto vertimas', + 'agentTextTranslationDesc': 'Verskite įvestą ar įklijuotą tekstą', + 'agentPictureTranslation': 'Nuotraukų vertimas', + 'agentPictureTranslationDesc': 'Nufotografuokite arba pasirinkite nuotrauką vertimui', + 'callRequiredTitle': 'Reikalingas skambutis', + 'callRequiredDesc': 'Ši funkcija veikia tik skambučio metu', + 'inCallBusyTitle': 'Neprieinama skambučio metu', + 'inCallBusyDesc': 'Mikrofoną ir garso kelią naudoja skambutis. Bandykite dar kartą padėję ragelį.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Nemokama', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/lv_lv.dart b/apps/client/lib/core/translations/language/lv_lv.dart index 80815f00..d379f54e 100644 --- a/apps/client/lib/core/translations/language/lv_lv.dart +++ b/apps/client/lib/core/translations/language/lv_lv.dart @@ -1924,4 +1924,208 @@ const Map lvLV = { 'unmarkFavorite': 'Noņemt no izlases', 'unnamedDevice': 'Ierīce bez nosaukuma', 'userDataParseFailed': 'Neizdevās nolasīt lietotāja datus', + 'catEarphone': 'AI austiņas', + 'catEarphoneDesc': 'Klasiskās Bluetooth / BLE austiņas', + 'catPhoneHolder': 'AI tālruņa turētājs', + 'catPhoneHolderDesc': 'Turētāja ierīces', + 'catCarAroma': 'AI auto aromatizētājs', + 'catCarAromaDesc': 'Automašīnas aromāta difuzors', + 'agreeAndContinue': 'Piekrist un turpināt', + 'memberServiceAgreement': 'Dalības pakalpojumu līgums', + 'memberServiceAgreementTitle': 'Dalības pakalpojumu līgums', + 'memberServiceAgreementIntro': 'Lai sniegtu jums labākus dalības pakalpojumus, pirms abonēšanas, lūdzu, rūpīgi izlasiet: ', + 'memberServiceAgreementOutro': '. Noklikšķinot uz “Piekrist un turpināt”, jūs apstiprināt, ka esat pilnībā izlasījis un piekrītat iepriekš minētajam līgumam.', + 'memberAgreementRejectedTip': 'Lai turpinātu, jums jāpiekrīt Dalības pakalpojumu līgumam.', + 'translationCallExitTitle': 'Iziet no zvanu tulkošanas', + 'translationCallExitMessage': 'Izvēlieties, ko darīt pirms iziešanas', + 'translationCallEnd': 'Beigt zvana tulkošanu', + 'translationContinueInBackground': 'Turpināt tulkošanu fonā', + 'backgroundRecordingIndicatorBody': 'Ierakstīšana turpinās fonā. Pieskarieties, lai atgrieztos.', + 'backgroundTranslationIndicatorBody': 'Zvana tulkošana turpinās fonā. Pieskarieties, lai atgrieztos.', + 'meetingRecordScreenCapturePermissionDenied': 'Lai ierakstītu sistēmas audio, nepieciešama ekrāna ierakstīšanas atļauja. Piešķiriet to un mēģiniet vēlreiz.', + 'pleaseGrantBluetoothPermission': 'Piešķiriet Bluetooth atļauju, lai skenētu', + 'startScanFailed': 'Neizdevās sākt skenēšanu', + 'pleaseLoginFirst': 'Vispirms piesakieties', + 'deviceUnauthorized': 'Ierīce nav autorizēta, mēģiniet vēlreiz', + 'boundDevices': 'Saistītās ierīces', + 'currentConnection': 'Pašreizējais savienojums', + 'binding': 'Saista...', + 'permissionDisabled': 'Izslēgta', + 'confirmDisablePermissionTitle': 'Izslēgt atļauju', + 'confirmDisablePermissionContent': 'Izslēgt {permission} atļauju? Lai to atkal ieslēgtu, būs jādodas uz sistēmas iestatījumiem.', + 'confirmPermanentlyDisallowTitle': 'Vairs nejautāt?', + 'confirmPermanentlyDisallowContent': 'Jūs noraidījāt {permission} atļauju. Vairs nejautāt? Ja izvēlēsieties “Neatļaut”, vēlāk to joprojām varēsiet ieslēgt sistēmas iestatījumos.', + 'notNow': 'Ne tagad', + 'permanentlyDisallow': 'Neatļaut', + 'otaBesNotSupported': 'Šīs austiņas vēl neatbalsta programmaparatūras atjaunināšanu lietotnē. Lūdzu, sazinieties ar atbalsta dienestu.', + 'tabDevice': 'Ierīces', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Tehnoloģijas viedākai dzīvei', + 'sloganAi': 'Neierobežots intelekts', + 'sloganDevice': 'Viedā aparatūra, gatava nākotnei', + 'sloganPlaza': 'Vieda pasaule, kas jūs saprot', + 'aiEditHint': 'Turiet karti nospiestu, lai vilktu un pārkārtotu moduļus', + 'aiEmptyTitle': 'Moduļi vēl nav pievienoti', + 'aiEmptyDesc': 'Izvēlieties nepieciešamos aģentus sadaļā Plaza', + 'goToPlaza': 'Doties uz Plaza', + 'plazaOnline': 'Pieejams', + 'plazaPlanned': 'Drīzumā', + 'plazaSearchHint': 'Meklēt aģentus, piem., “tulkot”, “ierakstīt”', + 'moduleRemove': 'Noņemt', + 'moduleAdd': 'Pievienot', + 'moduleRemoved': 'Noņemts', + 'moduleAdded': 'Pievienots', + 'goSee': 'Skatīt', + 'comingSoonTag': 'Drīzumā', + 'needDeviceTag': 'Nepieciešama ierīce', + 'featureInDev': 'Šī funkcija vēl tiek izstrādāta', + 'featureNotWired': 'Vēl nav pieejams', + 'todayLabel': 'Šodien', + 'deviceConnected': 'Savienots', + 'licenseUnknown': 'Licence nav zināma', + 'selectDevice': 'Izvēlieties ierīci', + 'catNoteCard': 'AI ierakstītāja karte', + 'catNoteCardDesc': 'Kartes formas ierakstītājs', + 'catParkerPen': 'AI pildspalva', + 'catParkerPenDesc': 'Pildspalvas ar balss ierakstītāju', + 'catStylusPen': 'AI irbulis', + 'catStylusPenDesc': 'Rokraksta / irbuļa ierīces', + 'catStudyMachine': 'AI mācību planšete', + 'catStudyMachineDesc': 'Mācību ierīces', + 'besAddTitle': 'Pievienot AI austiņas', + 'besConnecting': 'Savienojas ar austiņām…', + 'besNotFound': 'Austiņas nav atrastas', + 'besNotFoundIosDesc': 'Vispirms savienojiet austiņas sadaļā Iestatījumi → Bluetooth, pēc tam atgriezieties šeit', + 'besNotFoundAndroidDesc': 'Vispirms savienojiet austiņas pārī sadaļā Iestatījumi → Bluetooth, pēc tam savienojiet šeit', + 'besReadFailed': 'Nolasīšana neizdevās', + 'besConnectFailIos': 'Pārliecinieties, ka sistēmas Bluetooth iestatījumos austiņas ir redzamas kā savienotas, pēc tam mēģiniet vēlreiz', + 'besConnectFailAndroid': 'Pārliecinieties, ka austiņas ir ieslēgtas, tuvumā un nav savienotas ar citu ierīci. Pēc savienošanas pārī tās atkal savienosies automātiski.', + 'holderAddTitle': 'Pievienot AI tālruņa turētāju', + 'holderConnecting': 'Savienojas ar ierīci…', + 'holderSearching': 'Meklē ierīces…', + 'holderNotFound': 'Ierīces nav atrastas', + 'holderPairHint': 'Pārliecinieties, ka turētājs ir ieslēgts un savienošanas pārī režīmā', + 'holderRetryHint': 'Pārliecinieties, ka ierīce ir ieslēgta un tuvumā, pēc tam mēģiniet vēlreiz', + 'autoConnectTitle': 'Automātiska ierīču savienošana', + 'autoConnectDesc': 'Pamodina lietotni, lai atkal savienotos un saņemtu ierakstus, kad ierīce ieslēdzas vai atrodas tuvumā', + 'autoConnectConsentTitle': 'Ieslēgt automātisko savienošanu', + 'autoConnectConsentIntro': 'Lai jūsu ierīce (AI austiņas / AI tālruņa turētājs) varētu savienoties automātiski un saglabāt ierakstus, kad nospiežat tās ierakstīšanas pogu, mums nepieciešama jūsu piekrišana:', + 'autoConnectConsentB1': 'Reģistrēt Bluetooth skenēšanu fonā, lai lietotne tiktu pamodināta (automātiski palaista), kad tiek atrasta saistītā ierīce, un varētu atkal savienoties un saņemt ierakstus', + 'autoConnectConsentB2': 'Pēc pamodināšanas tā tiek izmantota tikai ierīces savienošanai, ierakstīšanai un augšupielādei — nekam citam, un citas lietotnes netiek palaistas', + 'autoConnectConsentB3': 'Lietotni varat izmantot arī bez tā — vienkārši katru reizi savienojiet ierīci manuāli', + 'autoConnectConsentB4': 'To jebkurā laikā varat izslēgt sadaļā Iestatījumi → Automātiska ierīču savienošana', + 'autoConnectAgree': 'Piekrist un ieslēgt', + 'autoConnectLater': 'Ne tagad', + 'autoConnectRequired': 'Automātiskā savienošana ir izslēgta', + 'autoConnectRequiredDesc': 'Ieslēdziet automātisko savienošanu, lai saistītu šo ierīci', + 'recordTapToStart': 'Pieskarieties pogai zemāk, lai sāktu ierakstīt', + 'recordPaused': 'Pauzēts', + 'recordMark': 'Atzīmēt', + 'recordDeleteTitle': 'Dzēst ierakstu', + 'accountAndProfile': 'Konts un profils', + 'nicknameUnset': 'Segvārds nav iestatīts', + 'nicknameInput': 'Ievadiet segvārdu', + 'loginMethod': 'Pieteikšanās veids', + 'manageMyLogin': 'Pārvaldīt pieteikšanos', + 'logoutAction': 'Izrakstīties', + 'warningLabel': 'Brīdinājums:', + 'deleteAccountWarn': 'Jūsu konts un visi faili tiks neatgriezeniski dzēsti.', + 'icpFiling': 'ICP reģistrācija', + 'logExport': 'Eksportēt žurnālus', + 'logExportDesc': 'Skatīt un eksportēt lietotnes žurnālus', + 'permLoadFailed': 'Neizdevās ielādēt atļauju grupas', + 'permInsufficient': 'Atļauja liegta', + 'voiceCloneCreating': 'Veido jūsu balsi…', + 'voiceCloneCreate': 'Izveidot manu balsi', + 'voiceCloneAgree': 'Piekrist un skaļi nolasīt paziņojumu', + 'voiceCloneReadPrompt': 'Lūdzu, nolasiet:', + 'voiceCloneFirstMonthFree': 'Pirmais mēnesis bez maksas', + 'voiceCloneEnable': 'Ieslēgt balss klonēšanu', + 'noMusicPlaying': 'Nekas netiek atskaņots', + 'qqMusicNoSeek': 'QQ Music neatbalsta pārtīšanu', + 'bleScanTitle': 'BLE skenēšana', + 'bluetoothOn': 'Bluetooth ieslēgts', + 'bleScanning': 'Skenē…', + 'bleConnectedDevices': 'Savienotās ierīces', + 'bleUnknownDevice': 'Nezināma ierīce', + 'bleTapToScan': 'Pieskarieties Skenēt, lai meklētu BLE ierīces', + 'weekMon': 'Pr', + 'weekTue': 'Ot', + 'weekWed': 'Tr', + 'weekThu': 'Ce', + 'weekFri': 'Pk', + 'weekSat': 'Se', + 'weekSun': 'Sv', + 'agentMeeting': 'Balss protokoli', + 'agentMeetingDesc': 'Ierakstu kopsavilkumi, atmiņas centrs', + 'agentEmai': 'EMAI asistents', + 'agentEmaiDesc': 'Sarunājieties un jautājiet jebko ar balsi', + 'agentSimultaneous': 'Sinhronā tulkošana', + 'agentSimultaneousDesc': 'Tulko, kamēr runājat', + 'agentFaceToFace': 'Aci pret aci', + 'agentFaceToFaceDesc': 'Divvirzienu sarunu tulkošana', + 'agentCallRecording': 'Zvanu ierakstīšana', + 'agentCallRecordingDesc': 'Zvani tiek saglabāti automātiski', + 'agentFieldRecording': 'Ierakstīšana uz vietas', + 'agentFieldRecordingDesc': 'Ierīces vai tālruņa mikrofons', + 'agentCall': 'Zvanu tulkošana', + 'agentCallDesc': 'Tulkošana reāllaikā zvanu laikā', + 'agentAudioVideo': 'Mediju tulkošana', + 'agentAudioVideoDesc': 'Kameras kadrēšana / audio un video tulkošana', + 'agentEnglishChat': 'Sarunas angļu valodā', + 'agentEnglishChatDesc': 'Iedziļinoša runāšanas prakse', + 'agentEnglishStudy': 'Angļu valodas mācības', + 'agentEnglishStudyDesc': 'Vārdu krājuma un gramatikas nodarbības', + 'agentKidsStory': 'Bērnu stāsti', + 'agentKidsStoryDesc': 'Vakara pasakas un jautājumi-atbildes', + 'moduleRemovedDesc': 'noņemts no AI lapas', + 'moduleAddedDesc': 'pievienots AI lapas apakšā', + 'calNoRecords': 'Nav ierakstu', + 'calNoRecordsDay': 'Nekas nav ieplānots', + 'calTodos': 'Darāmie darbi', + 'calExpenses': 'Izdevumi', + 'calTodoCount': 'Darbi: @count', + 'calExpenseCount': 'Izdevumi: @count', + 'calEntryCount': 'Ieraksti: @count', + 'calItemsUnit': 'vienības', + 'calCountUnit': 'ieraksti', + 'calTotalAmount': 'Kopā', + 'recordPause': 'Pauze', + 'recordResume': 'Turpināt', + 'recordDeleteConfirm': 'Dzēst šo ierakstu?', + 'scopeDay': 'Diena', + 'scopeWeek': 'Nedēļa', + 'scopeMonth': 'Mēnesis', + 'allDay': 'Visu dienu', + 'guestModeTitle': 'Viesa režīms', + 'guestModeDesc': 'Viesi var tikai pārlūkot. Piesakieties, lai izmantotu balss piezīmes, tulkošanu un ierakstīšanu — jūsu dati tiks saglabāti jūsu kontā.', + 'guestKeepBrowsing': 'Turpināt pārlūkot', + 'guestGoLogin': 'Pieteikties', + 'guestViewOnlyTag': 'Tikai skatīšanās', + 'autoConnectReenableHint': 'Automātiskā savienošana ir izslēgta. Ieslēdziet to atkal sadaļā Iestatījumi → Automātiska ierīču savienošana.', + 'plazaEntryDesc': 'Pārlūkojiet un pievienojiet vairāk aģentu', + 'agentTextTranslation': 'Teksta tulkošana', + 'agentTextTranslationDesc': 'Tulkojiet ievadītu vai ielīmētu tekstu', + 'agentPictureTranslation': 'Foto tulkošana', + 'agentPictureTranslationDesc': 'Uzņemiet vai izvēlieties fotoattēlu tulkošanai', + 'callRequiredTitle': 'Nepieciešams zvans', + 'callRequiredDesc': 'Šī funkcija darbojas tikai zvana laikā', + 'inCallBusyTitle': 'Nav pieejams zvana laikā', + 'inCallBusyDesc': 'Mikrofonu un audio ceļu izmanto zvans. Mēģiniet vēlreiz pēc zvana beigšanas.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Bezmaksas', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/ms_my.dart b/apps/client/lib/core/translations/language/ms_my.dart index a2a4e188..49f0272b 100644 --- a/apps/client/lib/core/translations/language/ms_my.dart +++ b/apps/client/lib/core/translations/language/ms_my.dart @@ -1908,4 +1908,208 @@ const Map msMY = { 'unmarkFavorite': 'Buang dari kegemaran', 'unnamedDevice': 'Peranti tanpa nama', 'userDataParseFailed': 'Gagal membaca data pengguna', + 'catEarphone': 'Fon Telinga AI', + 'catEarphoneDesc': 'Fon telinga Bluetooth klasik / BLE', + 'catPhoneHolder': 'Pemegang Telefon AI', + 'catPhoneHolderDesc': 'Peranti pemegang', + 'catCarAroma': 'Pewangi Kereta AI', + 'catCarAromaDesc': 'Penyebar aroma kereta', + 'agreeAndContinue': 'Setuju dan Teruskan', + 'memberServiceAgreement': 'Perjanjian Perkhidmatan Keahlian', + 'memberServiceAgreementTitle': 'Perjanjian Perkhidmatan Keahlian', + 'memberServiceAgreementIntro': 'Untuk memberikan perkhidmatan keahlian yang lebih baik, sila baca dengan teliti sebelum melanggan: ', + 'memberServiceAgreementOutro': '. Dengan mengetik "Setuju dan Teruskan", anda mengesahkan bahawa anda telah membaca sepenuhnya dan menerima perjanjian di atas.', + 'memberAgreementRejectedTip': 'Anda mesti bersetuju dengan Perjanjian Perkhidmatan Keahlian untuk meneruskan.', + 'translationCallExitTitle': 'Keluar Penterjemahan Panggilan', + 'translationCallExitMessage': 'Pilih tindakan sebelum keluar', + 'translationCallEnd': 'Tamatkan penterjemahan panggilan', + 'translationContinueInBackground': 'Teruskan penterjemahan di latar belakang', + 'backgroundRecordingIndicatorBody': 'Rakaman diteruskan di latar belakang. Ketik untuk kembali.', + 'backgroundTranslationIndicatorBody': 'Penterjemahan panggilan diteruskan di latar belakang. Ketik untuk kembali.', + 'meetingRecordScreenCapturePermissionDenied': 'Kebenaran rakaman skrin diperlukan untuk merakam audio sistem. Sila berikan kebenaran dan cuba lagi.', + 'pleaseGrantBluetoothPermission': 'Sila berikan kebenaran Bluetooth untuk mengimbas', + 'startScanFailed': 'Gagal memulakan imbasan', + 'pleaseLoginFirst': 'Sila log masuk dahulu', + 'deviceUnauthorized': 'Peranti tidak dibenarkan, sila cuba lagi', + 'boundDevices': 'Peranti Terikat', + 'currentConnection': 'Sambungan Semasa', + 'binding': 'Mengikat...', + 'permissionDisabled': 'Dimatikan', + 'confirmDisablePermissionTitle': 'Matikan kebenaran', + 'confirmDisablePermissionContent': 'Matikan kebenaran {permission}? Anda perlu ke tetapan sistem untuk mengaktifkannya semula.', + 'confirmPermanentlyDisallowTitle': 'Berhenti bertanya?', + 'confirmPermanentlyDisallowContent': 'Anda menolak kebenaran {permission}. Berhenti bertanya mulai sekarang? Jika anda memilih "Jangan benarkan", anda masih boleh mengaktifkannya kemudian dalam tetapan sistem.', + 'notNow': 'Bukan sekarang', + 'permanentlyDisallow': 'Jangan benarkan', + 'otaBesNotSupported': 'Set kepala ini belum menyokong naik taraf firmware dalam aplikasi. Sila hubungi sokongan.', + 'tabDevice': 'Peranti', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Teknologi untuk kehidupan lebih bijak', + 'sloganAi': 'Kecerdasan tanpa had', + 'sloganDevice': 'Perkakasan pintar, sedia untuk masa depan', + 'sloganPlaza': 'Dunia pintar yang memahami anda', + 'aiEditHint': 'Tekan lama kad untuk seret dan susun semula modul', + 'aiEmptyTitle': 'Tiada modul ditambah lagi', + 'aiEmptyDesc': 'Pilih ejen yang anda perlukan di Plaza', + 'goToPlaza': 'Pergi ke Plaza', + 'plazaOnline': 'Tersedia', + 'plazaPlanned': 'Akan datang', + 'plazaSearchHint': 'Cari ejen, cth. “terjemah”, “rakam”', + 'moduleRemove': 'Buang', + 'moduleAdd': 'Tambah', + 'moduleRemoved': 'Dibuang', + 'moduleAdded': 'Ditambah', + 'goSee': 'Lihat', + 'comingSoonTag': 'Akan datang', + 'needDeviceTag': 'Perlukan peranti', + 'featureInDev': 'Ciri ini sedang dibangunkan', + 'featureNotWired': 'Belum tersedia', + 'todayLabel': 'Hari ini', + 'deviceConnected': 'Disambungkan', + 'licenseUnknown': 'Lesen tidak diketahui', + 'selectDevice': 'Pilih peranti', + 'catNoteCard': 'Kad Perakam AI', + 'catNoteCardDesc': 'Perakam berbentuk kad', + 'catParkerPen': 'Pen AI', + 'catParkerPenDesc': 'Pen perakam suara', + 'catStylusPen': 'Stilus AI', + 'catStylusPenDesc': 'Peranti tulisan tangan / stilus', + 'catStudyMachine': 'Pad Pembelajaran AI', + 'catStudyMachineDesc': 'Peranti pembelajaran', + 'besAddTitle': 'Tambah Earbud AI', + 'besConnecting': 'Menyambung ke earbud…', + 'besNotFound': 'Earbud tidak ditemui', + 'besNotFoundIosDesc': 'Sambungkan earbud di Tetapan → Bluetooth dahulu, kemudian kembali ke sini', + 'besNotFoundAndroidDesc': 'Pasangkan earbud di Tetapan → Bluetooth dahulu, kemudian sambung di sini', + 'besReadFailed': 'Gagal membaca', + 'besConnectFailIos': 'Pastikan earbud dipaparkan sebagai Disambungkan dalam Bluetooth sistem, kemudian cuba lagi', + 'besConnectFailAndroid': 'Pastikan earbud dihidupkan, berdekatan dan tidak disambungkan ke peranti lain. Earbud akan menyambung semula secara automatik selepas dipautkan.', + 'holderAddTitle': 'Tambah Pemegang Telefon AI', + 'holderConnecting': 'Menyambung ke peranti…', + 'holderSearching': 'Mencari peranti…', + 'holderNotFound': 'Tiada peranti ditemui', + 'holderPairHint': 'Pastikan pemegang dihidupkan dan dalam mod berpasangan', + 'holderRetryHint': 'Pastikan peranti dihidupkan dan berdekatan, kemudian cuba lagi', + 'autoConnectTitle': 'Sambung automatik peranti', + 'autoConnectDesc': 'Bangunkan aplikasi untuk menyambung semula dan menerima rakaman apabila peranti anda dihidupkan atau berdekatan', + 'autoConnectConsentTitle': 'Aktifkan sambung automatik', + 'autoConnectConsentIntro': 'Untuk membolehkan peranti anda (Earbud AI / Pemegang Telefon AI) menyambung secara automatik dan menyimpan rakaman apabila anda menekan butang rakamnya, kami memerlukan persetujuan anda:', + 'autoConnectConsentB1': 'Mendaftarkan imbasan Bluetooth latar belakang supaya aplikasi dibangunkan (dimulakan automatik) apabila peranti terikat anda dikesan, untuk menyambung semula dan menerima rakaman', + 'autoConnectConsentB2': 'Setelah dibangunkan, ia hanya digunakan untuk sambungan peranti, rakaman dan muat naik — tiada yang lain, dan tiada aplikasi lain dilancarkan', + 'autoConnectConsentB3': 'Anda masih boleh menggunakan aplikasi tanpanya — cuma sambungkan peranti secara manual setiap kali', + 'autoConnectConsentB4': 'Anda boleh mematikannya pada bila-bila masa di Tetapan → Sambung automatik peranti', + 'autoConnectAgree': 'Setuju dan aktifkan', + 'autoConnectLater': 'Bukan sekarang', + 'autoConnectRequired': 'Sambung automatik dimatikan', + 'autoConnectRequiredDesc': 'Aktifkan sambung automatik untuk mengikat peranti ini', + 'recordTapToStart': 'Ketik butang di bawah untuk mula merakam', + 'recordPaused': 'Dijeda', + 'recordMark': 'Tanda', + 'recordDeleteTitle': 'Padam rakaman', + 'accountAndProfile': 'Akaun & profil', + 'nicknameUnset': 'Nama panggilan belum ditetapkan', + 'nicknameInput': 'Masukkan nama panggilan', + 'loginMethod': 'Kaedah log masuk', + 'manageMyLogin': 'Urus log masuk', + 'logoutAction': 'Log keluar', + 'warningLabel': 'Amaran:', + 'deleteAccountWarn': 'Akaun anda dan semua fail akan dipadam secara kekal.', + 'icpFiling': 'Pendaftaran ICP', + 'logExport': 'Eksport log', + 'logExportDesc': 'Lihat dan eksport log aplikasi', + 'permLoadFailed': 'Gagal memuatkan kumpulan kebenaran', + 'permInsufficient': 'Kebenaran ditolak', + 'voiceCloneCreating': 'Mencipta suara anda…', + 'voiceCloneCreate': 'Cipta suara saya', + 'voiceCloneAgree': 'Setuju dan baca kenyataan dengan kuat', + 'voiceCloneReadPrompt': 'Sila baca:', + 'voiceCloneFirstMonthFree': 'Bulan pertama percuma', + 'voiceCloneEnable': 'Aktifkan klon suara', + 'noMusicPlaying': 'Tiada yang dimainkan', + 'qqMusicNoSeek': 'Melangkau kedudukan tidak disokong untuk QQ Music', + 'bleScanTitle': 'Imbasan BLE', + 'bluetoothOn': 'Bluetooth dihidupkan', + 'bleScanning': 'Mengimbas…', + 'bleConnectedDevices': 'Peranti disambungkan', + 'bleUnknownDevice': 'Peranti tidak dikenali', + 'bleTapToScan': 'Ketik imbas untuk mencari peranti BLE', + 'weekMon': 'Isn', + 'weekTue': 'Sel', + 'weekWed': 'Rab', + 'weekThu': 'Kha', + 'weekFri': 'Jum', + 'weekSat': 'Sab', + 'weekSun': 'Ahd', + 'agentMeeting': 'Minit Suara', + 'agentMeetingDesc': 'Ringkaskan rakaman, hab memori', + 'agentEmai': 'Pembantu EMAI', + 'agentEmaiDesc': 'Berbual dan tanya apa sahaja melalui suara', + 'agentSimultaneous': 'Penterjemahan Langsung', + 'agentSimultaneousDesc': 'Terjemah semasa anda bercakap', + 'agentFaceToFace': 'Bersemuka', + 'agentFaceToFaceDesc': 'Penterjemahan perbualan dua hala', + 'agentCallRecording': 'Rakaman Panggilan', + 'agentCallRecordingDesc': 'Panggilan disimpan secara automatik', + 'agentFieldRecording': 'Rakaman Lapangan', + 'agentFieldRecordingDesc': 'Mikrofon peranti atau telefon', + 'agentCall': 'Penterjemahan Panggilan', + 'agentCallDesc': 'Terjemahan masa nyata semasa panggilan', + 'agentAudioVideo': 'Penterjemahan Media', + 'agentAudioVideoDesc': 'Bingkai kamera / terjemahan audio & video', + 'agentEnglishChat': 'Sembang Bahasa Inggeris', + 'agentEnglishChatDesc': 'Latihan bertutur secara imersif', + 'agentEnglishStudy': 'Belajar Bahasa Inggeris', + 'agentEnglishStudyDesc': 'Pelajaran kosa kata dan tatabahasa', + 'agentKidsStory': 'Cerita Kanak-kanak', + 'agentKidsStoryDesc': 'Cerita sebelum tidur dan soal jawab', + 'moduleRemovedDesc': 'dibuang daripada halaman AI', + 'moduleAddedDesc': 'ditambah ke bahagian bawah halaman AI', + 'calNoRecords': 'Tiada entri', + 'calNoRecordsDay': 'Tiada jadual', + 'calTodos': 'Tugasan', + 'calExpenses': 'Perbelanjaan', + 'calTodoCount': '@count tugasan', + 'calExpenseCount': '@count perbelanjaan', + 'calEntryCount': '@count entri', + 'calItemsUnit': 'item', + 'calCountUnit': 'entri', + 'calTotalAmount': 'Jumlah', + 'recordPause': 'Jeda', + 'recordResume': 'Sambung semula', + 'recordDeleteConfirm': 'Padam rakaman ini?', + 'scopeDay': 'Hari', + 'scopeWeek': 'Minggu', + 'scopeMonth': 'Bulan', + 'allDay': 'Sepanjang hari', + 'guestModeTitle': 'Mod tetamu', + 'guestModeDesc': 'Tetamu hanya boleh melayari. Log masuk untuk menggunakan nota suara, penterjemahan dan rakaman — data anda akan disimpan ke akaun anda.', + 'guestKeepBrowsing': 'Terus melayari', + 'guestGoLogin': 'Log masuk', + 'guestViewOnlyTag': 'Lihat sahaja', + 'autoConnectReenableHint': 'Sambung automatik dimatikan. Hidupkan semula di Tetapan → Sambung automatik peranti.', + 'plazaEntryDesc': 'Layari dan tambah lebih banyak ejen', + 'agentTextTranslation': 'Penterjemahan Teks', + 'agentTextTranslationDesc': 'Terjemah teks yang ditaip atau ditampal', + 'agentPictureTranslation': 'Penterjemahan Foto', + 'agentPictureTranslationDesc': 'Ambil atau pilih foto untuk diterjemah', + 'callRequiredTitle': 'Panggilan diperlukan', + 'callRequiredDesc': 'Ciri ini hanya berfungsi semasa panggilan', + 'inCallBusyTitle': 'Tidak tersedia semasa panggilan', + 'inCallBusyDesc': 'Mikrofon dan laluan audio sedang digunakan oleh panggilan. Cuba lagi selepas menamatkan panggilan.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Percuma', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/nb_no.dart b/apps/client/lib/core/translations/language/nb_no.dart index bcf6a136..4a4e8821 100644 --- a/apps/client/lib/core/translations/language/nb_no.dart +++ b/apps/client/lib/core/translations/language/nb_no.dart @@ -1902,4 +1902,208 @@ const Map nbNO = { 'unmarkFavorite': 'Fjern fra favoritter', 'unnamedDevice': 'Enhet uten navn', 'userDataParseFailed': 'Kunne ikke lese brukerdata', + 'catEarphone': 'AI-øreplugger', + 'catEarphoneDesc': 'Klassiske Bluetooth- / BLE-øreplugger', + 'catPhoneHolder': 'AI-mobilholder', + 'catPhoneHolderDesc': 'Holderenheter', + 'catCarAroma': 'AI-bilduft', + 'catCarAromaDesc': 'Aromaspreder for bil', + 'agreeAndContinue': 'Godta og fortsett', + 'memberServiceAgreement': 'Medlemstjenesteavtale', + 'memberServiceAgreementTitle': 'Medlemstjenesteavtale', + 'memberServiceAgreementIntro': 'For å gi deg bedre medlemstjenester ber vi deg lese nøye før du abonnerer: ', + 'memberServiceAgreementOutro': '. Ved å trykke på «Godta og fortsett» bekrefter du at du har lest og godtar avtalen ovenfor.', + 'memberAgreementRejectedTip': 'Du må godta medlemstjenesteavtalen for å fortsette.', + 'translationCallExitTitle': 'Forlat samtaleoversettelse', + 'translationCallExitMessage': 'Velg hva som skal skje før du forlater', + 'translationCallEnd': 'Avslutt samtaleoversettelse', + 'translationContinueInBackground': 'Fortsett oversettelsen i bakgrunnen', + 'backgroundRecordingIndicatorBody': 'Opptaket fortsetter i bakgrunnen. Trykk for å gå tilbake.', + 'backgroundTranslationIndicatorBody': 'Samtaleoversettelsen fortsetter i bakgrunnen. Trykk for å gå tilbake.', + 'meetingRecordScreenCapturePermissionDenied': 'Skjermopptakstillatelse kreves for å ta opp systemlyd. Gi tillatelse og prøv igjen.', + 'pleaseGrantBluetoothPermission': 'Gi Bluetooth-tillatelse for å skanne', + 'startScanFailed': 'Kunne ikke starte skanning', + 'pleaseLoginFirst': 'Logg inn først', + 'deviceUnauthorized': 'Enheten er ikke autorisert, prøv igjen', + 'boundDevices': 'Tilknyttede enheter', + 'currentConnection': 'Gjeldende tilkobling', + 'binding': 'Knytter til...', + 'permissionDisabled': 'Deaktivert', + 'confirmDisablePermissionTitle': 'Slå av tillatelse', + 'confirmDisablePermissionContent': 'Slå av {permission}-tillatelse? Du må gå til systeminnstillingene for å aktivere den igjen.', + 'confirmPermanentlyDisallowTitle': 'Slutte å spørre?', + 'confirmPermanentlyDisallowContent': 'Du avslo {permission}-tillatelse. Slutte å spørre fra nå av? Hvis du velger «Ikke tillat», kan du fortsatt aktivere den senere i systeminnstillingene.', + 'notNow': 'Ikke nå', + 'permanentlyDisallow': 'Ikke tillat', + 'otaBesNotSupported': 'Dette headsetet støtter ennå ikke firmware-oppgradering i appen. Kontakt kundestøtte.', + 'tabDevice': 'Enheter', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Teknologi for et smartere liv', + 'sloganAi': 'Grenseløs intelligens', + 'sloganDevice': 'Smart maskinvare, klar for fremtiden', + 'sloganPlaza': 'En smart verden som forstår deg', + 'aiEditHint': 'Hold inne et kort for å dra og omorganisere moduler', + 'aiEmptyTitle': 'Ingen moduler lagt til ennå', + 'aiEmptyDesc': 'Velg agentene du trenger i Plaza', + 'goToPlaza': 'Gå til Plaza', + 'plazaOnline': 'Tilgjengelig', + 'plazaPlanned': 'Kommer snart', + 'plazaSearchHint': 'Søk etter agenter, f.eks. «oversett», «ta opp»', + 'moduleRemove': 'Fjern', + 'moduleAdd': 'Legg til', + 'moduleRemoved': 'Fjernet', + 'moduleAdded': 'Lagt til', + 'goSee': 'Se', + 'comingSoonTag': 'Kommer snart', + 'needDeviceTag': 'Krever enhet', + 'featureInDev': 'Denne funksjonen er under utvikling', + 'featureNotWired': 'Ikke tilgjengelig ennå', + 'todayLabel': 'I dag', + 'deviceConnected': 'Tilkoblet', + 'licenseUnknown': 'Lisens ukjent', + 'selectDevice': 'Velg en enhet', + 'catNoteCard': 'AI-opptakerkort', + 'catNoteCardDesc': 'Kortformet opptaker', + 'catParkerPen': 'AI-penn', + 'catParkerPenDesc': 'Stemmeopptakerpenner', + 'catStylusPen': 'AI-pekepenn', + 'catStylusPenDesc': 'Håndskrift-/pekepennenheter', + 'catStudyMachine': 'AI-læringsnettbrett', + 'catStudyMachineDesc': 'Læringsenheter', + 'besAddTitle': 'Legg til AI-ørepropper', + 'besConnecting': 'Kobler til øreproppene…', + 'besNotFound': 'Fant ikke øreproppene', + 'besNotFoundIosDesc': 'Koble til øreproppene i Innstillinger → Bluetooth først, og kom så tilbake', + 'besNotFoundAndroidDesc': 'Par øreproppene i Innstillinger → Bluetooth først, og koble til her etterpå', + 'besReadFailed': 'Lesing mislyktes', + 'besConnectFailIos': 'Sørg for at øreproppene vises som Tilkoblet i systemets Bluetooth, og prøv igjen', + 'besConnectFailAndroid': 'Sørg for at øreproppene er på, i nærheten og ikke koblet til en annen enhet. De kobler til på nytt automatisk når de er paret.', + 'holderAddTitle': 'Legg til AI-telefonholder', + 'holderConnecting': 'Kobler til enheten…', + 'holderSearching': 'Søker etter enheter…', + 'holderNotFound': 'Ingen enheter funnet', + 'holderPairHint': 'Sørg for at holderen er på og i paringsmodus', + 'holderRetryHint': 'Sørg for at enheten er på og i nærheten, og prøv igjen', + 'autoConnectTitle': 'Koble til enheter automatisk', + 'autoConnectDesc': 'Vekk appen for å koble til på nytt og motta opptak når enheten din slås på eller kommer i nærheten', + 'autoConnectConsentTitle': 'Aktiver automatisk tilkobling', + 'autoConnectConsentIntro': 'For at enheten din (AI-ørepropper / AI-telefonholder) skal kunne koble til automatisk og lagre opptak når du trykker på opptaksknappen, trenger vi ditt samtykke:', + 'autoConnectConsentB1': 'Registrere en Bluetooth-skanning i bakgrunnen slik at appen vekkes (startes automatisk) når den tilknyttede enheten oppdages, for å koble til på nytt og motta opptak', + 'autoConnectConsentB2': 'Når appen er vekket, brukes den kun til enhetstilkobling, opptak og opplasting — ingenting annet, og ingen andre apper startes', + 'autoConnectConsentB3': 'Du kan fortsatt bruke appen uten dette — bare koble til enheten manuelt hver gang', + 'autoConnectConsentB4': 'Du kan slå det av når som helst i Innstillinger → Koble til enheter automatisk', + 'autoConnectAgree': 'Godta og aktiver', + 'autoConnectLater': 'Ikke nå', + 'autoConnectRequired': 'Automatisk tilkobling er av', + 'autoConnectRequiredDesc': 'Aktiver automatisk tilkobling for å knytte til denne enheten', + 'recordTapToStart': 'Trykk på knappen nedenfor for å starte opptaket', + 'recordPaused': 'Satt på pause', + 'recordMark': 'Marker', + 'recordDeleteTitle': 'Slett opptak', + 'accountAndProfile': 'Konto og profil', + 'nicknameUnset': 'Ingen kallenavn angitt', + 'nicknameInput': 'Skriv inn et kallenavn', + 'loginMethod': 'Innloggingsmetode', + 'manageMyLogin': 'Administrer innlogging', + 'logoutAction': 'Logg ut', + 'warningLabel': 'Advarsel:', + 'deleteAccountWarn': 'Kontoen din og alle filer slettes permanent.', + 'icpFiling': 'ICP-registrering', + 'logExport': 'Eksporter logger', + 'logExportDesc': 'Se og eksporter app-logger', + 'permLoadFailed': 'Kunne ikke laste tillatelsesgrupper', + 'permInsufficient': 'Tillatelse avslått', + 'voiceCloneCreating': 'Oppretter stemmen din…', + 'voiceCloneCreate': 'Opprett min stemme', + 'voiceCloneAgree': 'Godta og les erklæringen høyt', + 'voiceCloneReadPrompt': 'Vennligst les:', + 'voiceCloneFirstMonthFree': 'Første måned gratis', + 'voiceCloneEnable': 'Aktiver stemmekloning', + 'noMusicPlaying': 'Ingenting spilles av', + 'qqMusicNoSeek': 'Spoling støttes ikke for QQ Music', + 'bleScanTitle': 'BLE-skanning', + 'bluetoothOn': 'Bluetooth er på', + 'bleScanning': 'Skanner…', + 'bleConnectedDevices': 'Tilkoblede enheter', + 'bleUnknownDevice': 'Ukjent enhet', + 'bleTapToScan': 'Trykk på skann for å søke etter BLE-enheter', + 'weekMon': 'Man', + 'weekTue': 'Tir', + 'weekWed': 'Ons', + 'weekThu': 'Tor', + 'weekFri': 'Fre', + 'weekSat': 'Lør', + 'weekSun': 'Søn', + 'agentMeeting': 'Talereferat', + 'agentMeetingDesc': 'Oppsummer opptak, minnesenter', + 'agentEmai': 'EMAI-assistent', + 'agentEmaiDesc': 'Chat og spør om alt med stemmen', + 'agentSimultaneous': 'Sanntidsoversettelse', + 'agentSimultaneousDesc': 'Oversett mens du snakker', + 'agentFaceToFace': 'Ansikt-til-ansikt', + 'agentFaceToFaceDesc': 'Toveis samtaleoversettelse', + 'agentCallRecording': 'Samtaleopptak', + 'agentCallRecordingDesc': 'Samtaler lagres automatisk', + 'agentFieldRecording': 'Feltopptak', + 'agentFieldRecordingDesc': 'Enhetens eller telefonens mikrofon', + 'agentCall': 'Samtaleoversettelse', + 'agentCallDesc': 'Sanntidsoversettelse under samtaler', + 'agentAudioVideo': 'Medieoversettelse', + 'agentAudioVideoDesc': 'Kamerainnramming / lyd- og videooversettelse', + 'agentEnglishChat': 'Engelsk samtale', + 'agentEnglishChatDesc': 'Oppslukende taletrening', + 'agentEnglishStudy': 'Engelskstudier', + 'agentEnglishStudyDesc': 'Ordforråds- og grammatikkleksjoner', + 'agentKidsStory': 'Barnefortellinger', + 'agentKidsStoryDesc': 'Godnatthistorier og spørsmål og svar', + 'moduleRemovedDesc': 'fjernet fra AI-siden', + 'moduleAddedDesc': 'lagt til nederst på AI-siden', + 'calNoRecords': 'Ingen oppføringer', + 'calNoRecordsDay': 'Ingenting planlagt', + 'calTodos': 'To-do', + 'calExpenses': 'Utgifter', + 'calTodoCount': '@count to-dos', + 'calExpenseCount': '@count utgifter', + 'calEntryCount': '@count oppføringer', + 'calItemsUnit': 'stk.', + 'calCountUnit': 'oppføringer', + 'calTotalAmount': 'Totalt', + 'recordPause': 'Pause', + 'recordResume': 'Fortsett', + 'recordDeleteConfirm': 'Slette dette opptaket?', + 'scopeDay': 'Dag', + 'scopeWeek': 'Uke', + 'scopeMonth': 'Måned', + 'allDay': 'Hele dagen', + 'guestModeTitle': 'Gjestemodus', + 'guestModeDesc': 'Gjester kan bare se seg rundt. Logg inn for å bruke talereferat, oversettelse og opptak — dataene dine lagres på kontoen din.', + 'guestKeepBrowsing': 'Fortsett å se deg rundt', + 'guestGoLogin': 'Logg inn', + 'guestViewOnlyTag': 'Kun visning', + 'autoConnectReenableHint': 'Automatisk tilkobling er av. Slå det på igjen i Innstillinger → Koble til enheter automatisk.', + 'plazaEntryDesc': 'Bla gjennom og legg til flere agenter', + 'agentTextTranslation': 'Tekstoversettelse', + 'agentTextTranslationDesc': 'Oversett skrevet eller limt inn tekst', + 'agentPictureTranslation': 'Bildeoversettelse', + 'agentPictureTranslationDesc': 'Ta eller velg et bilde for å oversette', + 'callRequiredTitle': 'Samtale kreves', + 'callRequiredDesc': 'Denne funksjonen fungerer bare under en samtale', + 'inCallBusyTitle': 'Ikke tilgjengelig under en samtale', + 'inCallBusyDesc': 'Mikrofonen og lydbanen brukes av samtalen. Prøv igjen etter at du har lagt på.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Gratis', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/nl_nl.dart b/apps/client/lib/core/translations/language/nl_nl.dart index 59fa9949..efacfdf4 100644 --- a/apps/client/lib/core/translations/language/nl_nl.dart +++ b/apps/client/lib/core/translations/language/nl_nl.dart @@ -1801,4 +1801,363 @@ const Map nlNL = { 'unmarkFavorite': 'Uit favorieten verwijderen', 'unnamedDevice': 'Naamloos apparaat', 'userDataParseFailed': 'Kan gebruikersgegevens niet verwerken', + 'catEarphone': 'AI-oordopjes', + 'catEarphoneDesc': 'Klassieke Bluetooth- / BLE-oordopjes', + 'catPhoneHolder': 'AI-telefoonhouder', + 'catPhoneHolderDesc': 'Houderapparaten', + 'catCarAroma': 'AI-autoverfrisser', + 'catCarAromaDesc': 'Auto-aromaverspreider', + 'agreeAndContinue': 'Akkoord en doorgaan', + 'memberServiceAgreement': 'Lidmaatschapsserviceovereenkomst', + 'memberServiceAgreementTitle': 'Lidmaatschapsserviceovereenkomst', + 'memberServiceAgreementIntro': 'Om u betere lidmaatschapsservices te bieden, verzoeken wij u dit aandachtig te lezen voordat u zich abonneert: ', + 'memberServiceAgreementOutro': '. Door op "Akkoord en doorgaan" te klikken, bevestigt u dat u de bovenstaande overeenkomst volledig hebt gelezen en accepteert.', + 'memberAgreementRejectedTip': 'U moet akkoord gaan met de Lidmaatschapsserviceovereenkomst om door te gaan.', + 'exploreAi': 'Ontdek de AI-functies van Eaimar', + 'aiFunction': 'AI-functies', + 'allRoundAssistant': 'Alround assistent', + 'allRoundAssistantInfo': 'Helpt bij allerlei vragen en problemen', + 'simultaneousTranslation': 'Realtime vertaling', + 'faceToFaceTranslation': 'Face-to-face vertaling', + 'audioVideoTranslation': 'Multimediavertaling', + 'callTranslation': 'Gespreksvertaling', + 'simultaneousTranslationInfo': 'Directe vertaling in meer dan 80 talen', + 'aiGirlfriend': 'Ouder-kindband', + 'aiGirlfriendInfo': 'Slim gezelschap, altijd om mee te praten', + 'healthConsultant': 'Multifunctionele AI-chat', + 'healthConsultantInfo': 'Meer AI-chatfuncties', + 'conferenceAssistant': 'Zakelijke vergaderassistent', + 'conferenceAssistantInfo': 'Realtime notulen en meertalige vertaling', + 'usageStats': 'Gebruiksstatistieken', + 'usageStatsInfo': 'Bekijk uw gebruiksstatistieken', + 'scene': 'Scenario\'s', + 'aiChat': 'AI-chat', + 'translationStats': 'Vertaalstatistieken', + 'meetingStats': 'Vergaderstatistieken', + 'today': 'Vandaag', + 'thisWeek': 'Deze week', + 'thisMonth': 'Deze maand', + 'history': 'Geschiedenis', + 'currentSessionStats': 'Statistieken huidige sessie', + 'translationCount': 'Aantal vertalingen', + 'sessionDuration': 'Sessieduur', + 'characters': 'Tekens', + 'recordingDuration': 'Opnameduur', + 'totalApiCalls': 'Totaal API-aanroepen', + 'sessionCount': 'Aantal sessies', + 'totalCharacters': 'Totaal aantal tekens', + 'apiCallStats': 'API-aanroepstatistieken', + 'translationApi': 'Vertaal-API', + 'asr': 'ASR', + 'tts': 'TTS', + 'dataVolumeStats': 'Datavolumestatistieken', + 'sourceTextCharacters': 'Tekens brontekst', + 'ttsTextCharacters': 'Tekens TTS-tekst', + 'effectiveAudioDuration': 'Effectieve audioduur', + 'totalSessionDuration': 'Totale sessieduur', + 'costStats': 'Kostenstatistieken', + 'estimatedCost': 'Geschatte kosten', + 'dailyCostThreshold': 'Dagelijkse kostenlimiet', + 'monthlyCostThreshold': 'Maandelijkse kostenlimiet', + 'usageBehaviorStats': 'Gebruiksgedragstatistieken', + 'mostUsedLanguagePair': 'Meest gebruikte talenpaar', + 'mostUsedMode': 'Meest gebruikte modus', + 'asrApiCalls': 'ASR-aanroepen', + 'totalAudioDuration': 'Totale audioduur', + 'audioFileSize': 'Grootte audiobestand', + 'transcriptBytes': 'Transcriptbytes', + 'loadFailed': 'Laden mislukt', + 'statsLoadFailedTryLater': 'Laden van statistieken mislukt. Probeer het later opnieuw.', + 'availablePackages': 'Beschikbare pakketten', + 'remainingQuota': 'Resterend quota', + 'totalQuota': 'Totaal quota', + 'remaining': 'Resterend', + 'featureDescription': 'Functiebeschrijving', + 'paymentSuccess': 'Betaling geslaagd', + 'gotIt': 'Begrepen', + 'paymentFailedTryAgain': 'Betaling mislukt. Probeer het opnieuw.', + 'alipayPay': 'Alipay', + 'paypalPay': 'PayPal', + 'appleIap': 'Apple IAP', + 'googleIap': 'Google IAP', + 'wechatOrderCreateFailed': 'Aanmaken van WeChat-bestelling mislukt', + 'alipayOrderCreateFailed': 'Aanmaken van Alipay-bestelling mislukt', + 'appleOrderCreateFailed': 'Aanmaken van Apple-bestelling mislukt', + 'googleOrderCreateFailed': 'Aanmaken van Google-bestelling mislukt', + 'paypalOrderCreateFailed': 'Aanmaken van PayPal-bestelling mislukt', + 'paymentException': 'Betalingsfout', + 'paymentLaunchFailed': 'Starten van betaling mislukt', + 'paymentExceptionWithError': 'Betalingsfout: @error', + 'paymentProcessingCheckLater': 'Uw bestelling wordt verwerkt. Controleer het later opnieuw.', + 'paymentResultQueryException': 'Opvragen van betalingsresultaat mislukt: @error', + 'orderConfirmedQuotaRefreshed': 'Bestelling bevestigd. Uw quota is bijgewerkt.', + 'paymentCompletedConfirming': 'Betaling voltooid. Bevestigen…', + 'paymentCancelled': 'Betaling geannuleerd', + 'paypalOpenedCompleteInBrowser': 'PayPal is geopend. Voltooi de betaling in uw browser.', + 'paypalOpenFailed': 'Kan de PayPal-betaalpagina niet openen', + 'paymentTestTitle': 'Betalingstest', + 'paymentTestOrderInfo': 'Testbestelgegevens', + 'paymentTestProductId': 'Product-ID', + 'paymentTestProductDescription': 'Productbeschrijving', + 'paymentTestWechatDescription': 'WeChat Pay-betalingstest', + 'paymentTestAlipayDescription': 'Alipay-betalingstest', + 'paymentTestAmount': 'Bedrag', + 'paymentTestSelectAmount': 'Selecteer testbedrag', + 'paying': 'Bezig met betalen...', + 'wechatPayWithAmount': 'WeChat Pay ¥@amount', + 'alipayPayWithAmount': 'Alipay ¥@amount', + 'paymentStatusTitle': 'Betalingsstatus', + 'errorInfoWithMessage': 'Fout: @message', + 'retest': 'Opnieuw testen', + 'paymentTestInstructionsTitle': 'Instructies', + 'paymentTestInstructionsContent': '1. Selecteer een testbedrag (aanbevolen: ¥0,01)\n2. Tik op de knop "WeChat Pay"\n3. De app roept de WeChat Pay SDK aan\n4. Voltooi de betaling in WeChat\n5. Keer terug naar de app om het resultaat te bekijken\n\nLet op: dit is een testomgeving. Er wordt niets in rekening gebracht.', + 'startingWechatPayment': 'WeChat Pay wordt gestart...', + 'startingAlipayPayment': 'Alipay wordt gestart...', + 'wechatPaymentSuccess': 'WeChat Pay-betaling geslaagd!', + 'wechatPaymentFailed': 'WeChat Pay-betaling mislukt', + 'wechatPaymentLaunchFailed': 'Starten van WeChat Pay mislukt', + 'cannotLaunchWechatPayment': 'Kan WeChat Pay niet starten', + 'wechatPaymentException': 'WeChat Pay-fout', + 'wechatPaymentTestCompleted': 'WeChat Pay-test voltooid', + 'alipayPaymentSuccess': 'Alipay-betaling geslaagd!', + 'alipayPaymentFailed': 'Alipay-betaling mislukt', + 'alipayPaymentLaunchFailed': 'Starten van Alipay mislukt', + 'cannotLaunchAlipayPayment': 'Kan Alipay niet starten', + 'alipayPaymentException': 'Alipay-fout', + 'insufficientIntegral': 'Onvoldoende tegoed', + 'insufficientBalanceDesc': 'Onvoldoende saldo. Ga naar de bijbehorende opwaardeerpagina om op te waarderen.', + 'recharge': 'Naar opwaarderen', + 'aiMemberExpiredDesc': 'Uw AI-lidmaatschap is verlopen. Ga naar de lidmaatschapspagina om te verlengen.', + 'musicSearchPlaybackControl': 'Muziekbibliotheek doorzoeken en afspelen bedienen', + 'smartPlaylistAndSimilarRecommendations': 'Slimme afspeellijsten en aanbevelingen van vergelijkbare nummers', + 'routePlanningAndCongestionAvoidance': 'Routeplanning en files vermijden', + 'voiceBroadcastAndWaypoints': 'Gesproken aanwijzingen en tussenpunten instellen', + 'realTimeWeatherForecast': 'Actueel weer en weersverwachting', + 'clothingAdviceAndTravelReminders': 'Kledingadvies en reisherinneringen', + 'poiSearchFoodGasParking': 'POI-zoeken: eten / tanken / parkeren', + 'ratingsHoursAndDirectRoutes': 'Beoordelingen, openingstijden en directe routes', + 'hotNewsAndTopicOverview': 'Actueel nieuws en onderwerpoverzicht', + 'longArticleSummariesAndKeyPoints': 'Samenvattingen en kernpunten van lange artikelen', + 'helpCallAndSMS': 'Hulp bij bellen en sms\'en', + 'templatedMessagesAndScheduleReminders': 'Sjabloonberichten en agendaherinneringen', + 'aiDisclaimer': 'Functies zijn afhankelijk van apparaatmachtigingen, beschikbaarheid van de service en netwerkomstandigheden.', + 'realtimeTranscription': 'Realtime transcriptie', + 'sceneLexicon': 'Scenariowoordenlijst', + 'subtitleDisplay': 'Ondertitels', + 'transHeaderDesc1': 'Realtime simultaanvertaling en tekstvertaling met spraak met lage latentie.', + 'transHeaderDesc2': 'Geschikt voor reizen, zakelijk gebruik, toespraken en onderwijs.', + 'translateZhEn': 'Chinees-Engelse vertaling', + 'lowLatencyVoiceBroadcast': 'Spraakweergave met lage latentie', + 'multiLangTextTranslation': 'Meertalige tekstvertaling', + 'termOptimizationContextPreserve': 'Terminologie-optimalisatie en contextbehoud', + 'lexiconTourBusinessLife': 'Woordenlijsten voor reizen/zakelijk/dagelijks leven', + 'personalVocabularyMemory': 'Persoonlijk woordenschatgeheugen', + 'conversationSubtitleLargeText': 'Gespreksondertitels / grote-tekstmodus', + 'colorHighContrast': 'Hoog kleurcontrast', + 'transDisclaimer': 'De vertaalkwaliteit is afhankelijk van de microfoon, netwerklatentie en omgevingsgeluid.', + 'meetingRecording': 'Vergaderopname', + 'meetingHeaderDesc1': 'Audio-opname, transcriptie, zoeken op trefwoord en automatische samenvatting voor efficiëntere vergaderingen.', + 'meetingAutoRecording': 'Automatisch opnemen en segmenteren', + 'meetingDisclaimer': 'Gebruik in een rustige omgeving; de prestaties zijn afhankelijk van microfoon en netwerk.', + 'crossDeviceSync': 'Synchronisatie tussen apparaten', + 'trans_001_name': 'Vertaling Basis 100', + 'trans_002_name': 'Vertaling Basis 500', + 'trans_003_name': 'Vertaling Basis 1000', + 'trans_001_desc': 'Bevat 100 vertalingen (spraak/tekst).', + 'trans_002_desc': 'Bevat 500 vertalingen (spraak/tekst).', + 'trans_003_desc': 'Bevat 1000 vertalingen (spraak/tekst).', + 'translationCallExitTitle': 'Gespreksvertaling verlaten', + 'translationCallExitMessage': 'Kies wat u wilt doen voordat u vertrekt', + 'translationCallEnd': 'Gespreksvertaling beëindigen', + 'translationContinueInBackground': 'Vertaling op de achtergrond voortzetten', + 'backgroundRecordingIndicatorBody': 'De opname gaat door op de achtergrond. Tik om terug te keren.', + 'backgroundTranslationIndicatorBody': 'De gespreksvertaling gaat door op de achtergrond. Tik om terug te keren.', + 'meetingRecordScreenCapturePermissionDenied': 'Schermopnamemachtiging is vereist om systeemaudio op te nemen. Verleen deze en probeer het opnieuw.', + 'pleaseGrantBluetoothPermission': 'Verleen Bluetooth-machtiging om te scannen', + 'startScanFailed': 'Starten van scan mislukt', + 'pleaseLoginFirst': 'Log eerst in', + 'deviceUnauthorized': 'Apparaat niet geautoriseerd, probeer het opnieuw', + 'boundDevices': 'Gekoppelde apparaten', + 'currentConnection': 'Huidige verbinding', + 'binding': 'Koppelen...', + 'permissionDisabled': 'Uitgeschakeld', + 'confirmDisablePermissionTitle': 'Machtiging uitschakelen', + 'confirmDisablePermissionContent': 'Machtiging {permission} uitschakelen? U moet naar de systeeminstellingen gaan om deze opnieuw in te schakelen.', + 'confirmPermanentlyDisallowTitle': 'Niet meer vragen?', + 'confirmPermanentlyDisallowContent': 'U hebt de machtiging {permission} geweigerd. Voortaan niet meer vragen? Als u "Niet toestaan" kiest, kunt u deze later nog steeds inschakelen in de systeeminstellingen.', + 'notNow': 'Nu niet', + 'permanentlyDisallow': 'Niet toestaan', + 'otaBesNotSupported': 'Deze headset ondersteunt nog geen firmware-upgrade via de app. Neem contact op met de klantenservice.', + '乌拉圭': 'Uruguay', + '黎巴嫩': 'Libanon', + 'tabDevice': 'Apparaten', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Technologie voor een slimmer leven', + 'sloganAi': 'Grenzeloze intelligentie', + 'sloganDevice': 'Slimme hardware, klaar voor de toekomst', + 'sloganPlaza': 'Een slimme wereld die u begrijpt', + 'aiEditHint': 'Houd een kaart ingedrukt om modules te verslepen en te herschikken', + 'aiEmptyTitle': 'Nog geen modules toegevoegd', + 'aiEmptyDesc': 'Kies de agents die u nodig hebt in Plaza', + 'goToPlaza': 'Naar Plaza', + 'plazaOnline': 'Beschikbaar', + 'plazaPlanned': 'Binnenkort beschikbaar', + 'plazaSearchHint': 'Zoek agents, bijv. “vertalen”, “opnemen”', + 'moduleRemove': 'Verwijderen', + 'moduleAdd': 'Toevoegen', + 'moduleRemoved': 'Verwijderd', + 'moduleAdded': 'Toegevoegd', + 'goSee': 'Bekijken', + 'comingSoonTag': 'Binnenkort', + 'needDeviceTag': 'Apparaat vereist', + 'featureInDev': 'Deze functie is in ontwikkeling', + 'featureNotWired': 'Nog niet beschikbaar', + 'todayLabel': 'Vandaag', + 'deviceConnected': 'Verbonden', + 'licenseUnknown': 'Licentie onbekend', + 'selectDevice': 'Selecteer een apparaat', + 'catNoteCard': 'AI-opnamekaart', + 'catNoteCardDesc': 'Recorder in kaartvorm', + 'catParkerPen': 'AI-pen', + 'catParkerPenDesc': 'Pennen met spraakrecorder', + 'catStylusPen': 'AI-stylus', + 'catStylusPenDesc': 'Handschrift-/stylusapparaten', + 'catStudyMachine': 'AI-leertablet', + 'catStudyMachineDesc': 'Leerapparaten', + 'besAddTitle': 'AI-oortjes toevoegen', + 'besConnecting': 'Verbinden met oortjes…', + 'besNotFound': 'Oortjes niet gevonden', + 'besNotFoundIosDesc': 'Verbind de oortjes eerst via Instellingen → Bluetooth en kom daarna terug', + 'besNotFoundAndroidDesc': 'Koppel de oortjes eerst via Instellingen → Bluetooth en verbind ze daarna hier', + 'besReadFailed': 'Lezen mislukt', + 'besConnectFailIos': 'Controleer of de oortjes als Verbonden worden weergegeven in de Bluetooth-instellingen en probeer het opnieuw', + 'besConnectFailAndroid': 'Zorg dat de oortjes aan staan, in de buurt zijn en niet met een ander apparaat verbonden zijn. Zodra ze gekoppeld zijn, verbinden ze automatisch opnieuw.', + 'holderAddTitle': 'AI-telefoonhouder toevoegen', + 'holderConnecting': 'Verbinden met apparaat…', + 'holderSearching': 'Apparaten zoeken…', + 'holderNotFound': 'Geen apparaten gevonden', + 'holderPairHint': 'Zorg dat de houder aan staat en in koppelmodus is', + 'holderRetryHint': 'Zorg dat het apparaat aan staat en in de buurt is, en probeer het opnieuw', + 'autoConnectTitle': 'Apparaten automatisch verbinden', + 'autoConnectDesc': 'De app wekken om opnieuw te verbinden en opnames te ontvangen wanneer uw apparaat wordt ingeschakeld of in de buurt komt', + 'autoConnectConsentTitle': 'Automatisch verbinden inschakelen', + 'autoConnectConsentIntro': 'Om uw apparaat (AI-oortjes / AI-telefoonhouder) automatisch te laten verbinden en opnames op te slaan wanneer u op de opnameknop drukt, hebben we uw toestemming nodig:', + 'autoConnectConsentB1': 'Een Bluetooth-scan op de achtergrond registreren zodat de app wordt gewekt (automatisch gestart) wanneer uw gekoppelde apparaat wordt gedetecteerd, om opnieuw te verbinden en opnames te ontvangen', + 'autoConnectConsentB2': 'Na het wekken wordt dit alleen gebruikt voor apparaatverbinding, opname en uploaden — niets anders, en er worden geen andere apps gestart', + 'autoConnectConsentB3': 'U kunt de app ook zonder gebruiken — verbind het apparaat dan telkens handmatig', + 'autoConnectConsentB4': 'U kunt dit altijd uitschakelen via Instellingen → Apparaten automatisch verbinden', + 'autoConnectAgree': 'Akkoord en inschakelen', + 'autoConnectLater': 'Nu niet', + 'autoConnectRequired': 'Automatisch verbinden staat uit', + 'autoConnectRequiredDesc': 'Schakel automatisch verbinden in om dit apparaat te koppelen', + 'recordTapToStart': 'Tik op de onderstaande knop om de opname te starten', + 'recordPaused': 'Gepauzeerd', + 'recordMark': 'Markeren', + 'recordDeleteTitle': 'Opname verwijderen', + 'accountAndProfile': 'Account en profiel', + 'nicknameUnset': 'Geen bijnaam ingesteld', + 'nicknameInput': 'Voer een bijnaam in', + 'loginMethod': 'Inlogmethode', + 'manageMyLogin': 'Inloggen beheren', + 'logoutAction': 'Uitloggen', + 'warningLabel': 'Waarschuwing:', + 'deleteAccountWarn': 'Uw account en alle bestanden worden permanent verwijderd.', + 'icpFiling': 'ICP-registratie', + 'logExport': 'Logboeken exporteren', + 'logExportDesc': 'App-logboeken bekijken en exporteren', + 'permLoadFailed': 'Laden van machtigingsgroepen mislukt', + 'permInsufficient': 'Machtiging geweigerd', + 'voiceCloneCreating': 'Uw stem wordt aangemaakt…', + 'voiceCloneCreate': 'Mijn stem aanmaken', + 'voiceCloneAgree': 'Akkoord en lees de verklaring hardop voor', + 'voiceCloneReadPrompt': 'Lees voor:', + 'voiceCloneFirstMonthFree': 'Eerste maand gratis', + 'voiceCloneEnable': 'Stemklonen inschakelen', + 'noMusicPlaying': 'Er wordt niets afgespeeld', + 'qqMusicNoSeek': 'Doorspoelen wordt niet ondersteund voor QQ Music', + 'bleScanTitle': 'BLE-scan', + 'bluetoothOn': 'Bluetooth aan', + 'bleScanning': 'Scannen…', + 'bleConnectedDevices': 'Verbonden apparaten', + 'bleUnknownDevice': 'Onbekend apparaat', + 'bleTapToScan': 'Tik op scannen om BLE-apparaten te zoeken', + 'weekMon': 'Ma', + 'weekTue': 'Di', + 'weekWed': 'Wo', + 'weekThu': 'Do', + 'weekFri': 'Vr', + 'weekSat': 'Za', + 'weekSun': 'Zo', + 'agentMeeting': 'Spraaknotulen', + 'agentMeetingDesc': 'Opnames samenvatten, geheugencentrum', + 'agentEmai': 'EMAI-assistent', + 'agentEmaiDesc': 'Chat en vraag alles met uw stem', + 'agentSimultaneous': 'Live vertaling', + 'agentSimultaneousDesc': 'Vertalen terwijl u spreekt', + 'agentFaceToFace': 'Face-to-face', + 'agentFaceToFaceDesc': 'Tweerichtingsgespreksvertaling', + 'agentCallRecording': 'Gespreksopname', + 'agentCallRecordingDesc': 'Gesprekken worden automatisch opgeslagen', + 'agentFieldRecording': 'Opname ter plaatse', + 'agentFieldRecordingDesc': 'Microfoon van apparaat of telefoon', + 'agentCall': 'Gespreksvertaling', + 'agentCallDesc': 'Realtime vertaling tijdens gesprekken', + 'agentAudioVideo': 'Mediavertaling', + 'agentAudioVideoDesc': 'Camerabeeld / audio- en videovertaling', + 'agentEnglishChat': 'Engelse conversatie', + 'agentEnglishChatDesc': 'Meeslepende spreekoefening', + 'agentEnglishStudy': 'Engels leren', + 'agentEnglishStudyDesc': 'Woordenschat- en grammaticalessen', + 'agentKidsStory': 'Kinderverhalen', + 'agentKidsStoryDesc': 'Verhaaltjes voor het slapengaan en vragen', + 'moduleRemovedDesc': 'verwijderd van de AI-pagina', + 'moduleAddedDesc': 'onderaan de AI-pagina toegevoegd', + 'calNoRecords': 'Geen items', + 'calNoRecordsDay': 'Niets gepland', + 'calTodos': 'Taken', + 'calExpenses': 'Uitgaven', + 'calTodoCount': '@count taken', + 'calExpenseCount': '@count uitgaven', + 'calEntryCount': '@count items', + 'calItemsUnit': 'items', + 'calCountUnit': 'items', + 'calTotalAmount': 'Totaal', + 'recordPause': 'Pauzeren', + 'recordResume': 'Hervatten', + 'recordDeleteConfirm': 'Deze opname verwijderen?', + 'scopeDay': 'Dag', + 'scopeWeek': 'Week', + 'scopeMonth': 'Maand', + 'allDay': 'Hele dag', + 'guestModeTitle': 'Gastmodus', + 'guestModeDesc': 'Gasten kunnen alleen bekijken. Log in om spraaknotities, vertaling en opname te gebruiken — uw gegevens worden dan in uw account opgeslagen.', + 'guestKeepBrowsing': 'Verder kijken', + 'guestGoLogin': 'Inloggen', + 'guestViewOnlyTag': 'Alleen bekijken', + 'autoConnectReenableHint': 'Automatisch verbinden staat uit. Schakel het weer in via Instellingen → Apparaten automatisch verbinden.', + 'plazaEntryDesc': 'Blader door en voeg meer agents toe', + 'agentTextTranslation': 'Tekstvertaling', + 'agentTextTranslationDesc': 'Getypte of geplakte tekst vertalen', + 'agentPictureTranslation': 'Fotovertaling', + 'agentPictureTranslationDesc': 'Maak of kies een foto om te vertalen', + 'callRequiredTitle': 'Gesprek vereist', + 'callRequiredDesc': 'Deze functie werkt alleen tijdens een gesprek', + 'inCallBusyTitle': 'Niet beschikbaar tijdens een gesprek', + 'inCallBusyDesc': 'De microfoon en het audiopad worden gebruikt door het gesprek. Probeer het opnieuw na het ophangen.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Gratis', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/pl_pl.dart b/apps/client/lib/core/translations/language/pl_pl.dart index 8fd44905..db72b09b 100644 --- a/apps/client/lib/core/translations/language/pl_pl.dart +++ b/apps/client/lib/core/translations/language/pl_pl.dart @@ -1930,4 +1930,208 @@ const Map plPL = { 'unmarkFavorite': 'Usuń z ulubionych', 'unnamedDevice': 'Urządzenie bez nazwy', 'userDataParseFailed': 'Nie udało się odczytać danych użytkownika', + 'catEarphone': 'Słuchawki AI', + 'catEarphoneDesc': 'Słuchawki Bluetooth Classic / BLE', + 'catPhoneHolder': 'Uchwyt na telefon AI', + 'catPhoneHolderDesc': 'Urządzenia typu uchwyt', + 'catCarAroma': 'Zapach samochodowy AI', + 'catCarAromaDesc': 'Dyfuzor zapachu do auta', + 'agreeAndContinue': 'Zgadzam się i kontynuuję', + 'memberServiceAgreement': 'Umowa o usługi członkowskie', + 'memberServiceAgreementTitle': 'Umowa o usługi członkowskie', + 'memberServiceAgreementIntro': 'Aby zapewnić Ci lepsze usługi członkowskie, przed subskrypcją uważnie przeczytaj: ', + 'memberServiceAgreementOutro': '. Klikając „Zgadzam się i kontynuuję”, potwierdzasz, że w pełni zapoznałeś(-aś) się z powyższą umową i ją akceptujesz.', + 'memberAgreementRejectedTip': 'Aby kontynuować, musisz zaakceptować Umowę o usługi członkowskie.', + 'translationCallExitTitle': 'Wyjdź z tłumaczenia rozmowy', + 'translationCallExitMessage': 'Wybierz, co zrobić przed wyjściem', + 'translationCallEnd': 'Zakończ tłumaczenie rozmowy', + 'translationContinueInBackground': 'Kontynuuj tłumaczenie w tle', + 'backgroundRecordingIndicatorBody': 'Nagrywanie trwa w tle. Dotknij, aby wrócić.', + 'backgroundTranslationIndicatorBody': 'Tłumaczenie rozmowy trwa w tle. Dotknij, aby wrócić.', + 'meetingRecordScreenCapturePermissionDenied': 'Do przechwytywania dźwięku systemowego wymagane jest uprawnienie do nagrywania ekranu. Przyznaj je i spróbuj ponownie.', + 'pleaseGrantBluetoothPermission': 'Aby skanować, przyznaj uprawnienie Bluetooth', + 'startScanFailed': 'Nie udało się rozpocząć skanowania', + 'pleaseLoginFirst': 'Najpierw się zaloguj', + 'deviceUnauthorized': 'Urządzenie nieautoryzowane, spróbuj ponownie', + 'boundDevices': 'Powiązane urządzenia', + 'currentConnection': 'Bieżące połączenie', + 'binding': 'Wiązanie…', + 'permissionDisabled': 'Wyłączone', + 'confirmDisablePermissionTitle': 'Wyłącz uprawnienie', + 'confirmDisablePermissionContent': 'Wyłączyć uprawnienie {permission}? Aby je ponownie włączyć, trzeba będzie przejść do ustawień systemu.', + 'confirmPermanentlyDisallowTitle': 'Przestać pytać?', + 'confirmPermanentlyDisallowContent': 'Odmówiono uprawnienia {permission}. Przestać pytać od teraz? Jeśli wybierzesz „Nie zezwalaj”, nadal możesz je później włączyć w ustawieniach systemu.', + 'notNow': 'Nie teraz', + 'permanentlyDisallow': 'Nie zezwalaj', + 'otaBesNotSupported': 'Te słuchawki nie obsługują jeszcze aktualizacji oprogramowania z poziomu aplikacji. Skontaktuj się z pomocą techniczną.', + 'tabDevice': 'Urządzenia', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Technologia dla mądrzejszego życia', + 'sloganAi': 'Inteligencja bez granic', + 'sloganDevice': 'Inteligentny sprzęt gotowy na przyszłość', + 'sloganPlaza': 'Inteligentny świat, który Cię rozumie', + 'aiEditHint': 'Przytrzymaj kartę, aby przeciągnąć i zmienić układ modułów', + 'aiEmptyTitle': 'Nie dodano jeszcze modułów', + 'aiEmptyDesc': 'Wybierz potrzebnych agentów w Plaza', + 'goToPlaza': 'Przejdź do Plaza', + 'plazaOnline': 'Dostępne', + 'plazaPlanned': 'Wkrótce', + 'plazaSearchHint': 'Szukaj agentów, np. „tłumacz”, „nagraj”', + 'moduleRemove': 'Usuń', + 'moduleAdd': 'Dodaj', + 'moduleRemoved': 'Usunięto', + 'moduleAdded': 'Dodano', + 'goSee': 'Zobacz', + 'comingSoonTag': 'Wkrótce', + 'needDeviceTag': 'Wymaga urządzenia', + 'featureInDev': 'Ta funkcja jest w przygotowaniu', + 'featureNotWired': 'Jeszcze niedostępne', + 'todayLabel': 'Dziś', + 'deviceConnected': 'Połączono', + 'licenseUnknown': 'Licencja nieznana', + 'selectDevice': 'Wybierz urządzenie', + 'catNoteCard': 'Karta dyktafonu AI', + 'catNoteCardDesc': 'Dyktafon w kształcie karty', + 'catParkerPen': 'Długopis AI', + 'catParkerPenDesc': 'Długopisy z dyktafonem', + 'catStylusPen': 'Rysik AI', + 'catStylusPenDesc': 'Urządzenia do pisma odręcznego / rysiki', + 'catStudyMachine': 'Tablet edukacyjny AI', + 'catStudyMachineDesc': 'Urządzenia edukacyjne', + 'besAddTitle': 'Dodaj słuchawki AI', + 'besConnecting': 'Łączenie ze słuchawkami…', + 'besNotFound': 'Nie znaleziono słuchawek', + 'besNotFoundIosDesc': 'Najpierw połącz słuchawki w Ustawienia → Bluetooth, a potem wróć tutaj', + 'besNotFoundAndroidDesc': 'Najpierw sparuj słuchawki w Ustawienia → Bluetooth, a potem połącz je tutaj', + 'besReadFailed': 'Odczyt nie powiódł się', + 'besConnectFailIos': 'Upewnij się, że słuchawki są widoczne jako Połączone w systemowym Bluetooth, a następnie spróbuj ponownie', + 'besConnectFailAndroid': 'Upewnij się, że słuchawki są włączone, w pobliżu i niepołączone z innym urządzeniem. Po powiązaniu będą łączyć się automatycznie.', + 'holderAddTitle': 'Dodaj podstawkę AI na telefon', + 'holderConnecting': 'Łączenie z urządzeniem…', + 'holderSearching': 'Wyszukiwanie urządzeń…', + 'holderNotFound': 'Nie znaleziono urządzeń', + 'holderPairHint': 'Upewnij się, że podstawka jest włączona i w trybie parowania', + 'holderRetryHint': 'Upewnij się, że urządzenie jest włączone i w pobliżu, a następnie spróbuj ponownie', + 'autoConnectTitle': 'Automatyczne łączenie urządzeń', + 'autoConnectDesc': 'Budzi aplikację, aby ponownie połączyć się i odebrać nagrania, gdy urządzenie zostanie włączone lub znajdzie się w pobliżu', + 'autoConnectConsentTitle': 'Włącz automatyczne łączenie', + 'autoConnectConsentIntro': 'Aby Twoje urządzenie (słuchawki AI / podstawka AI na telefon) mogło łączyć się automatycznie i zapisywać nagrania po naciśnięciu przycisku nagrywania, potrzebujemy Twojej zgody:', + 'autoConnectConsentB1': 'Zarejestrowanie skanowania Bluetooth w tle, aby aplikacja była budzona (uruchamiana automatycznie) po wykryciu powiązanego urządzenia w celu ponownego połączenia i odbioru nagrań', + 'autoConnectConsentB2': 'Po wybudzeniu jest używana wyłącznie do łączenia z urządzeniem, nagrywania i przesyłania — nic więcej, żadne inne aplikacje nie są uruchamiane', + 'autoConnectConsentB3': 'Nadal możesz korzystać z aplikacji bez tego — wystarczy za każdym razem połączyć urządzenie ręcznie', + 'autoConnectConsentB4': 'Możesz to wyłączyć w dowolnym momencie w Ustawienia → Automatyczne łączenie urządzeń', + 'autoConnectAgree': 'Zgadzam się i włączam', + 'autoConnectLater': 'Nie teraz', + 'autoConnectRequired': 'Automatyczne łączenie jest wyłączone', + 'autoConnectRequiredDesc': 'Włącz automatyczne łączenie, aby powiązać to urządzenie', + 'recordTapToStart': 'Dotknij przycisku poniżej, aby rozpocząć nagrywanie', + 'recordPaused': 'Wstrzymano', + 'recordMark': 'Znacznik', + 'recordDeleteTitle': 'Usuń nagranie', + 'accountAndProfile': 'Konto i profil', + 'nicknameUnset': 'Nie ustawiono pseudonimu', + 'nicknameInput': 'Wpisz pseudonim', + 'loginMethod': 'Metoda logowania', + 'manageMyLogin': 'Zarządzaj logowaniem', + 'logoutAction': 'Wyloguj się', + 'warningLabel': 'Ostrzeżenie:', + 'deleteAccountWarn': 'Twoje konto i wszystkie pliki zostaną trwale usunięte.', + 'icpFiling': 'Rejestracja ICP', + 'logExport': 'Eksport dzienników', + 'logExportDesc': 'Przeglądaj i eksportuj dzienniki aplikacji', + 'permLoadFailed': 'Nie udało się wczytać grup uprawnień', + 'permInsufficient': 'Brak uprawnień', + 'voiceCloneCreating': 'Tworzenie Twojego głosu…', + 'voiceCloneCreate': 'Utwórz mój głos', + 'voiceCloneAgree': 'Zgadzam się i odczytam oświadczenie na głos', + 'voiceCloneReadPrompt': 'Przeczytaj:', + 'voiceCloneFirstMonthFree': 'Pierwszy miesiąc za darmo', + 'voiceCloneEnable': 'Włącz klonowanie głosu', + 'noMusicPlaying': 'Nic nie jest odtwarzane', + 'qqMusicNoSeek': 'QQ Music nie obsługuje przewijania', + 'bleScanTitle': 'Skanowanie BLE', + 'bluetoothOn': 'Bluetooth włączony', + 'bleScanning': 'Skanowanie…', + 'bleConnectedDevices': 'Połączone urządzenia', + 'bleUnknownDevice': 'Nieznane urządzenie', + 'bleTapToScan': 'Dotknij Skanuj, aby wyszukać urządzenia BLE', + 'weekMon': 'Pn', + 'weekTue': 'Wt', + 'weekWed': 'Śr', + 'weekThu': 'Cz', + 'weekFri': 'Pt', + 'weekSat': 'So', + 'weekSun': 'Nd', + 'agentMeeting': 'Notatki głosowe', + 'agentMeetingDesc': 'Podsumowania nagrań, centrum pamięci', + 'agentEmai': 'Asystent EMAI', + 'agentEmaiDesc': 'Rozmawiaj i pytaj o wszystko głosem', + 'agentSimultaneous': 'Tłumaczenie na żywo', + 'agentSimultaneousDesc': 'Tłumaczenie w trakcie mówienia', + 'agentFaceToFace': 'Twarzą w twarz', + 'agentFaceToFaceDesc': 'Dwukierunkowe tłumaczenie rozmowy', + 'agentCallRecording': 'Nagrywanie rozmów', + 'agentCallRecordingDesc': 'Rozmowy zapisywane automatycznie', + 'agentFieldRecording': 'Nagrywanie w terenie', + 'agentFieldRecordingDesc': 'Mikrofon urządzenia lub telefonu', + 'agentCall': 'Tłumaczenie rozmów', + 'agentCallDesc': 'Tłumaczenie w czasie rzeczywistym podczas rozmów', + 'agentAudioVideo': 'Tłumaczenie mediów', + 'agentAudioVideoDesc': 'Kadr aparatu / tłumaczenie audio i wideo', + 'agentEnglishChat': 'Rozmowa po angielsku', + 'agentEnglishChatDesc': 'Immersyjna nauka mówienia', + 'agentEnglishStudy': 'Nauka angielskiego', + 'agentEnglishStudyDesc': 'Lekcje słownictwa i gramatyki', + 'agentKidsStory': 'Bajki dla dzieci', + 'agentKidsStoryDesc': 'Bajki na dobranoc i pytania z odpowiedziami', + 'moduleRemovedDesc': 'usunięto ze strony AI', + 'moduleAddedDesc': 'dodano na dole strony AI', + 'calNoRecords': 'Brak wpisów', + 'calNoRecordsDay': 'Brak zaplanowanych zdarzeń', + 'calTodos': 'Zadania', + 'calExpenses': 'Wydatki', + 'calTodoCount': 'Zadania: @count', + 'calExpenseCount': 'Wydatki: @count', + 'calEntryCount': 'Wpisy: @count', + 'calItemsUnit': 'pozycji', + 'calCountUnit': 'wpisów', + 'calTotalAmount': 'Razem', + 'recordPause': 'Wstrzymaj', + 'recordResume': 'Wznów', + 'recordDeleteConfirm': 'Usunąć to nagranie?', + 'scopeDay': 'Dzień', + 'scopeWeek': 'Tydzień', + 'scopeMonth': 'Miesiąc', + 'allDay': 'Cały dzień', + 'guestModeTitle': 'Tryb gościa', + 'guestModeDesc': 'Goście mogą tylko przeglądać. Zaloguj się, aby korzystać z notatek głosowych, tłumaczenia i nagrywania — Twoje dane zostaną zapisane na Twoim koncie.', + 'guestKeepBrowsing': 'Przeglądaj dalej', + 'guestGoLogin': 'Zaloguj się', + 'guestViewOnlyTag': 'Tylko podgląd', + 'autoConnectReenableHint': 'Automatyczne łączenie jest wyłączone. Włącz je ponownie w Ustawienia → Automatyczne łączenie urządzeń.', + 'plazaEntryDesc': 'Przeglądaj i dodawaj kolejnych agentów', + 'agentTextTranslation': 'Tłumaczenie tekstu', + 'agentTextTranslationDesc': 'Tłumacz wpisany lub wklejony tekst', + 'agentPictureTranslation': 'Tłumaczenie zdjęć', + 'agentPictureTranslationDesc': 'Zrób lub wybierz zdjęcie do tłumaczenia', + 'callRequiredTitle': 'Wymagana rozmowa', + 'callRequiredDesc': 'Ta funkcja działa tylko podczas rozmowy', + 'inCallBusyTitle': 'Niedostępne podczas rozmowy', + 'inCallBusyDesc': 'Mikrofon i tor audio są używane przez rozmowę. Spróbuj ponownie po rozłączeniu.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Bezpłatne', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/pt_pt.dart b/apps/client/lib/core/translations/language/pt_pt.dart index 70e92cf0..4d835731 100644 --- a/apps/client/lib/core/translations/language/pt_pt.dart +++ b/apps/client/lib/core/translations/language/pt_pt.dart @@ -1885,6 +1885,8 @@ const Map ptPT = { 'catNoteCardDesc': 'Gravador em formato de cartão', 'catPhoneHolder': 'Suporte de telemóvel IA', 'catPhoneHolderDesc': 'Dispositivos de suporte', + 'catCarAroma': 'Difusor de carro IA', + 'catCarAromaDesc': 'Difusor de aroma para carro', 'catParkerPen': 'Caneta IA', 'catParkerPenDesc': 'Canetas gravadoras', 'catStylusPen': 'Stylus IA', @@ -2142,4 +2144,32 @@ const Map ptPT = { 'unmarkFavorite': 'Remover dos favoritos', 'unnamedDevice': 'Dispositivo sem nome', 'userDataParseFailed': 'Falha ao processar os dados do utilizador', + 'translationCallExitTitle': 'Sair da Tradução de Chamadas', + 'translationCallExitMessage': 'Escolha o que fazer antes de sair', + 'translationCallEnd': 'Terminar tradução de chamada', + 'translationContinueInBackground': 'Continuar a traduzir em segundo plano', + 'backgroundRecordingIndicatorBody': 'A gravação continua em segundo plano. Toque para voltar.', + 'backgroundTranslationIndicatorBody': 'A tradução de chamada continua em segundo plano. Toque para voltar.', + 'permissionDisabled': 'Desativado', + 'confirmDisablePermissionTitle': 'Desativar permissão', + 'confirmDisablePermissionContent': 'Desativar a permissão de {permission}? Terá de ir às definições do sistema para a reativar.', + 'confirmPermanentlyDisallowTitle': 'Parar de perguntar?', + 'confirmPermanentlyDisallowContent': 'Recusou a permissão de {permission}. Deixar de perguntar a partir de agora? Se escolher «Não permitir», poderá ativá-la mais tarde nas definições do sistema.', + 'notNow': 'Agora não', + 'permanentlyDisallow': 'Não permitir', + 'otaBesNotSupported': 'Estes auscultadores ainda não suportam a atualização de firmware na app. Contacte o suporte.', + 'smartcarConnected': 'Ligado', + 'smartcarConnectFailed': 'Falha na ligação', + 'smartcarConnecting': 'A ligar…', + 'smartcarSearching': 'A procurar difusores de carro próximos…', + 'smartcarNotFound': 'Nenhum dispositivo encontrado', + 'smartcarScanHint': 'Certifique-se de que o dispositivo está ligado e perto do telemóvel', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/ro_ro.dart b/apps/client/lib/core/translations/language/ro_ro.dart index 16ba2826..a7b8222f 100644 --- a/apps/client/lib/core/translations/language/ro_ro.dart +++ b/apps/client/lib/core/translations/language/ro_ro.dart @@ -1932,4 +1932,208 @@ const Map roRO = { 'unmarkFavorite': 'Elimină de la favorite', 'unnamedDevice': 'Dispozitiv fără nume', 'userDataParseFailed': 'Datele utilizatorului nu au putut fi citite', + 'catEarphone': 'Căști AI', + 'catEarphoneDesc': 'Căști Bluetooth clasic / BLE', + 'catPhoneHolder': 'Suport telefon AI', + 'catPhoneHolderDesc': 'Dispozitive de tip suport', + 'catCarAroma': 'Difuzor auto AI', + 'catCarAromaDesc': 'Difuzor de arome auto', + 'agreeAndContinue': 'Sunt de acord și continuă', + 'memberServiceAgreement': 'Acordul privind serviciile de membru', + 'memberServiceAgreementTitle': 'Acordul privind serviciile de membru', + 'memberServiceAgreementIntro': 'Pentru a vă oferi servicii de membru mai bune, vă rugăm să citiți cu atenție înainte de a vă abona: ', + 'memberServiceAgreementOutro': '. Făcând clic pe „Sunt de acord și continuă”, confirmați că ați citit integral și acceptați acordul de mai sus.', + 'memberAgreementRejectedTip': 'Trebuie să acceptați Acordul privind serviciile de membru pentru a continua.', + 'translationCallExitTitle': 'Ieșire din traducerea apelului', + 'translationCallExitMessage': 'Alege ce să faci înainte de a ieși', + 'translationCallEnd': 'Încheie traducerea apelului', + 'translationContinueInBackground': 'Continuă traducerea în fundal', + 'backgroundRecordingIndicatorBody': 'Înregistrarea continuă în fundal. Atinge pentru a reveni.', + 'backgroundTranslationIndicatorBody': 'Traducerea apelului continuă în fundal. Atinge pentru a reveni.', + 'meetingRecordScreenCapturePermissionDenied': 'Este necesară permisiunea de înregistrare a ecranului pentru a capta sunetul sistemului. Acordați-o și reîncercați.', + 'pleaseGrantBluetoothPermission': 'Acordați permisiunea Bluetooth pentru a scana', + 'startScanFailed': 'Pornirea scanării a eșuat', + 'pleaseLoginFirst': 'Autentificați-vă mai întâi', + 'deviceUnauthorized': 'Dispozitiv neautorizat, reîncercați', + 'boundDevices': 'Dispozitive asociate', + 'currentConnection': 'Conexiune curentă', + 'binding': 'Se asociază...', + 'permissionDisabled': 'Dezactivat', + 'confirmDisablePermissionTitle': 'Dezactivează permisiunea', + 'confirmDisablePermissionContent': 'Dezactivezi permisiunea {permission}? Va trebui să mergi în setările sistemului pentru a o reactiva.', + 'confirmPermanentlyDisallowTitle': 'Nu mai întreba?', + 'confirmPermanentlyDisallowContent': 'Ai refuzat permisiunea {permission}. Nu mai întrebăm de acum înainte? Dacă alegi „Nu permite”, o poți activa ulterior din setările sistemului.', + 'notNow': 'Nu acum', + 'permanentlyDisallow': 'Nu permite', + 'otaBesNotSupported': 'Aceste căști nu acceptă încă actualizarea firmware-ului din aplicație. Contactați asistența.', + 'tabDevice': 'Dispozitive', + 'tabPlaza': 'Piața', + 'sloganHome': 'Tehnologie pentru o viață mai inteligentă', + 'sloganAi': 'Inteligență fără limite', + 'sloganDevice': 'Hardware inteligent, pregătit pentru viitor', + 'sloganPlaza': 'O lume inteligentă care te înțelege', + 'aiEditHint': 'Apasă lung pe un card pentru a trage și rearanja modulele', + 'aiEmptyTitle': 'Niciun modul adăugat încă', + 'aiEmptyDesc': 'Alege agenții de care ai nevoie din Piață', + 'goToPlaza': 'Mergi la Piață', + 'plazaOnline': 'Disponibil', + 'plazaPlanned': 'În curând', + 'plazaSearchHint': 'Caută agenți, de ex. „traducere”, „înregistrare”', + 'moduleRemove': 'Elimină', + 'moduleAdd': 'Adaugă', + 'moduleRemoved': 'Eliminat', + 'moduleAdded': 'Adăugat', + 'goSee': 'Vezi', + 'comingSoonTag': 'În curând', + 'needDeviceTag': 'Necesită dispozitiv', + 'featureInDev': 'Această funcție este în dezvoltare', + 'featureNotWired': 'Momentan indisponibil', + 'todayLabel': 'Astăzi', + 'deviceConnected': 'Conectat', + 'licenseUnknown': 'Licență necunoscută', + 'selectDevice': 'Selectează un dispozitiv', + 'catNoteCard': 'Card de înregistrare AI', + 'catNoteCardDesc': 'Reportofon în formă de card', + 'catParkerPen': 'Stilou AI', + 'catParkerPenDesc': 'Stilouri cu reportofon', + 'catStylusPen': 'Stylus AI', + 'catStylusPenDesc': 'Dispozitive de scris de mână / stylus', + 'catStudyMachine': 'Tabletă de învățare AI', + 'catStudyMachineDesc': 'Dispozitive de învățare', + 'besAddTitle': 'Adaugă căști AI', + 'besConnecting': 'Se conectează la căști…', + 'besNotFound': 'Căștile nu au fost găsite', + 'besNotFoundIosDesc': 'Conectează mai întâi căștile din Setări → Bluetooth, apoi revino aici', + 'besNotFoundAndroidDesc': 'Asociază mai întâi căștile din Setări → Bluetooth, apoi conectează-le aici', + 'besReadFailed': 'Citirea a eșuat', + 'besConnectFailIos': 'Asigură-te că în Bluetooth-ul sistemului căștile apar ca Conectate, apoi reîncearcă', + 'besConnectFailAndroid': 'Asigură-te că căștile sunt pornite, în apropiere și neconectate la alt dispozitiv. Odată asociate, se vor reconecta automat.', + 'holderAddTitle': 'Adaugă suport de telefon AI', + 'holderConnecting': 'Se conectează la dispozitiv…', + 'holderSearching': 'Se caută dispozitive…', + 'holderNotFound': 'Niciun dispozitiv găsit', + 'holderPairHint': 'Asigură-te că suportul este pornit și în modul de asociere', + 'holderRetryHint': 'Asigură-te că dispozitivul este pornit și în apropiere, apoi reîncearcă', + 'autoConnectTitle': 'Conectare automată a dispozitivelor', + 'autoConnectDesc': 'Trezește aplicația pentru a se reconecta și a primi înregistrări când dispozitivul pornește sau se apropie', + 'autoConnectConsentTitle': 'Activează conectarea automată', + 'autoConnectConsentIntro': 'Pentru ca dispozitivul tău (căști AI / suport de telefon AI) să se conecteze automat și să salveze înregistrările când apeși butonul său de înregistrare, avem nevoie de consimțământul tău:', + 'autoConnectConsentB1': 'Înregistrarea unei scanări Bluetooth în fundal, astfel încât aplicația să fie trezită (pornită automat) când dispozitivul asociat este detectat, pentru a se reconecta și a primi înregistrări', + 'autoConnectConsentB2': 'Odată trezită, este folosită doar pentru conectarea dispozitivului, înregistrare și încărcare — nimic altceva, și nu sunt lansate alte aplicații', + 'autoConnectConsentB3': 'Poți folosi aplicația și fără aceasta — doar conectează dispozitivul manual de fiecare dată', + 'autoConnectConsentB4': 'O poți dezactiva oricând din Setări → Conectare automată a dispozitivelor', + 'autoConnectAgree': 'Sunt de acord și activează', + 'autoConnectLater': 'Nu acum', + 'autoConnectRequired': 'Conectarea automată este dezactivată', + 'autoConnectRequiredDesc': 'Activează conectarea automată pentru a asocia acest dispozitiv', + 'recordTapToStart': 'Atinge butonul de mai jos pentru a începe înregistrarea', + 'recordPaused': 'În pauză', + 'recordMark': 'Marchează', + 'recordDeleteTitle': 'Șterge înregistrarea', + 'accountAndProfile': 'Cont și profil', + 'nicknameUnset': 'Niciun pseudonim setat', + 'nicknameInput': 'Introdu un pseudonim', + 'loginMethod': 'Metodă de autentificare', + 'manageMyLogin': 'Gestionează autentificarea', + 'logoutAction': 'Deconectare', + 'warningLabel': 'Avertisment:', + 'deleteAccountWarn': 'Contul tău și toate fișierele vor fi șterse definitiv.', + 'icpFiling': 'Înregistrare ICP', + 'logExport': 'Export jurnale', + 'logExportDesc': 'Vezi și exportă jurnalele aplicației', + 'permLoadFailed': 'Încărcarea grupurilor de permisiuni a eșuat', + 'permInsufficient': 'Permisiune refuzată', + 'voiceCloneCreating': 'Se creează vocea ta…', + 'voiceCloneCreate': 'Creează vocea mea', + 'voiceCloneAgree': 'Sunt de acord și voi citi declarația cu voce tare', + 'voiceCloneReadPrompt': 'Te rugăm să citești:', + 'voiceCloneFirstMonthFree': 'Prima lună gratuită', + 'voiceCloneEnable': 'Activează clonarea vocii', + 'noMusicPlaying': 'Nu se redă nimic', + 'qqMusicNoSeek': 'Derularea nu este acceptată pentru QQ Music', + 'bleScanTitle': 'Scanare BLE', + 'bluetoothOn': 'Bluetooth pornit', + 'bleScanning': 'Se scanează…', + 'bleConnectedDevices': 'Dispozitive conectate', + 'bleUnknownDevice': 'Dispozitiv necunoscut', + 'bleTapToScan': 'Atinge Scanează pentru a căuta dispozitive BLE', + 'weekMon': 'Lun', + 'weekTue': 'Mar', + 'weekWed': 'Mie', + 'weekThu': 'Joi', + 'weekFri': 'Vin', + 'weekSat': 'Sâm', + 'weekSun': 'Dum', + 'agentMeeting': 'Note vocale de ședință', + 'agentMeetingDesc': 'Rezumă înregistrările, centru de amintiri', + 'agentEmai': 'Asistent EMAI', + 'agentEmaiDesc': 'Conversează și întreabă orice prin voce', + 'agentSimultaneous': 'Traducere simultană', + 'agentSimultaneousDesc': 'Traduce pe măsură ce vorbești', + 'agentFaceToFace': 'Față în față', + 'agentFaceToFaceDesc': 'Traducere bidirecțională a conversației', + 'agentCallRecording': 'Înregistrare apel', + 'agentCallRecordingDesc': 'Apelurile sunt salvate automat', + 'agentFieldRecording': 'Înregistrare pe teren', + 'agentFieldRecordingDesc': 'Microfonul dispozitivului sau al telefonului', + 'agentCall': 'Traducere apeluri', + 'agentCallDesc': 'Traducere în timp real în timpul apelurilor', + 'agentAudioVideo': 'Traducere media', + 'agentAudioVideoDesc': 'Încadrare cu camera / traducere audio și video', + 'agentEnglishChat': 'Conversație în engleză', + 'agentEnglishChatDesc': 'Exersare imersivă a vorbirii', + 'agentEnglishStudy': 'Studiul englezei', + 'agentEnglishStudyDesc': 'Lecții de vocabular și gramatică', + 'agentKidsStory': 'Povești pentru copii', + 'agentKidsStoryDesc': 'Povești de seară și întrebări și răspunsuri', + 'moduleRemovedDesc': 'eliminat din pagina AI', + 'moduleAddedDesc': 'adăugat la finalul paginii AI', + 'calNoRecords': 'Nicio intrare', + 'calNoRecordsDay': 'Nimic programat', + 'calTodos': 'De făcut', + 'calExpenses': 'Cheltuieli', + 'calTodoCount': '@count sarcini', + 'calExpenseCount': '@count cheltuieli', + 'calEntryCount': '@count intrări', + 'calItemsUnit': 'elemente', + 'calCountUnit': 'intrări', + 'calTotalAmount': 'Total', + 'recordPause': 'Pauză', + 'recordResume': 'Reia', + 'recordDeleteConfirm': 'Ștergi această înregistrare?', + 'scopeDay': 'Zi', + 'scopeWeek': 'Săptămână', + 'scopeMonth': 'Lună', + 'allDay': 'Toată ziua', + 'guestModeTitle': 'Mod vizitator', + 'guestModeDesc': 'Vizitatorii pot doar naviga. Autentifică-te pentru a folosi notele vocale, traducerea și înregistrarea — datele tale vor fi salvate în contul tău.', + 'guestKeepBrowsing': 'Continuă navigarea', + 'guestGoLogin': 'Autentificare', + 'guestViewOnlyTag': 'Doar vizualizare', + 'autoConnectReenableHint': 'Conectarea automată este dezactivată. Reactiveaz-o din Setări → Conectare automată a dispozitivelor.', + 'plazaEntryDesc': 'Răsfoiește și adaugă mai mulți agenți', + 'agentTextTranslation': 'Traducere text', + 'agentTextTranslationDesc': 'Traduce text tastat sau lipit', + 'agentPictureTranslation': 'Traducere foto', + 'agentPictureTranslationDesc': 'Fotografiază sau alege o poză pentru traducere', + 'callRequiredTitle': 'Necesită un apel', + 'callRequiredDesc': 'Această funcție funcționează doar în timpul unui apel', + 'inCallBusyTitle': 'Indisponibil în timpul apelului', + 'inCallBusyDesc': 'Microfonul și calea audio sunt folosite de apel. Reîncearcă după ce închizi.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Gratuit', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/ru_ru.dart b/apps/client/lib/core/translations/language/ru_ru.dart index 02c1d994..b0994fdb 100644 --- a/apps/client/lib/core/translations/language/ru_ru.dart +++ b/apps/client/lib/core/translations/language/ru_ru.dart @@ -1863,6 +1863,8 @@ const Map ruRU = { 'catNoteCardDesc': 'Диктофон в форме карты', 'catPhoneHolder': 'ИИ-держатель телефона', 'catPhoneHolderDesc': 'Устройства-держатели', + 'catCarAroma': 'ИИ-ароматизатор для авто', + 'catCarAromaDesc': 'Автомобильный ароматизатор', 'catParkerPen': 'ИИ-ручка', 'catParkerPenDesc': 'Ручки-диктофоны', 'catStylusPen': 'ИИ-стилус', @@ -2117,4 +2119,32 @@ const Map ruRU = { 'unmarkFavorite': 'Убрать из избранного', 'unnamedDevice': 'Устройство без имени', 'userDataParseFailed': 'Не удалось обработать данные пользователя', + 'translationCallExitTitle': 'Выйти из перевода звонка', + 'translationCallExitMessage': 'Выберите, что сделать перед выходом', + 'translationCallEnd': 'Завершить перевод звонка', + 'translationContinueInBackground': 'Продолжить перевод в фоне', + 'backgroundRecordingIndicatorBody': 'Запись продолжается в фоновом режиме. Нажмите, чтобы вернуться.', + 'backgroundTranslationIndicatorBody': 'Перевод звонка продолжается в фоновом режиме. Нажмите, чтобы вернуться.', + 'permissionDisabled': 'Отключено', + 'confirmDisablePermissionTitle': 'Отключить разрешение', + 'confirmDisablePermissionContent': 'Отключить разрешение «{permission}»? Чтобы включить его снова, нужно будет перейти в настройки системы.', + 'confirmPermanentlyDisallowTitle': 'Больше не спрашивать?', + 'confirmPermanentlyDisallowContent': 'Вы отклонили разрешение «{permission}». Больше не спрашивать? Если выбрать «Не разрешать», его можно будет включить позже в настройках системы.', + 'notNow': 'Не сейчас', + 'permanentlyDisallow': 'Не разрешать', + 'otaBesNotSupported': 'Эта гарнитура пока не поддерживает обновление прошивки из приложения. Обратитесь в службу поддержки.', + 'smartcarConnected': 'Подключено', + 'smartcarConnectFailed': 'Ошибка подключения', + 'smartcarConnecting': 'Подключение…', + 'smartcarSearching': 'Поиск автомобильных ароматизаторов поблизости…', + 'smartcarNotFound': 'Устройство не найдено', + 'smartcarScanHint': 'Убедитесь, что устройство включено и находится рядом с телефоном', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/sk_sk.dart b/apps/client/lib/core/translations/language/sk_sk.dart index 9e783cb1..6efa4718 100644 --- a/apps/client/lib/core/translations/language/sk_sk.dart +++ b/apps/client/lib/core/translations/language/sk_sk.dart @@ -1913,4 +1913,208 @@ const Map skSK = { 'unmarkFavorite': 'Odstrániť z obľúbených', 'unnamedDevice': 'Nepomenované zariadenie', 'userDataParseFailed': 'Údaje používateľa sa nepodarilo načítať', + 'catEarphone': 'AI slúchadlá', + 'catEarphoneDesc': 'Klasické Bluetooth / BLE slúchadlá', + 'catPhoneHolder': 'AI držiak telefónu', + 'catPhoneHolderDesc': 'Zariadenia typu držiak', + 'catCarAroma': 'AI vôňa do auta', + 'catCarAromaDesc': 'Difuzér vône do auta', + 'agreeAndContinue': 'Súhlasím a pokračovať', + 'memberServiceAgreement': 'Zmluva o členských službách', + 'memberServiceAgreementTitle': 'Zmluva o členských službách', + 'memberServiceAgreementIntro': 'Aby sme vám mohli poskytovať lepšie členské služby, pred predplatením si pozorne prečítajte: ', + 'memberServiceAgreementOutro': '. Ťuknutím na „Súhlasím a pokračovať“ potvrdzujete, že ste si vyššie uvedenú zmluvu celú prečítali a prijímate ju.', + 'memberAgreementRejectedTip': 'Na pokračovanie musíte súhlasiť so Zmluvou o členských službách.', + 'translationCallExitTitle': 'Opustiť preklad hovoru', + 'translationCallExitMessage': 'Vyberte, čo urobiť pred odchodom', + 'translationCallEnd': 'Ukončiť preklad hovoru', + 'translationContinueInBackground': 'Pokračovať v preklade na pozadí', + 'backgroundRecordingIndicatorBody': 'Nahrávanie pokračuje na pozadí. Ťuknutím sa vrátite.', + 'backgroundTranslationIndicatorBody': 'Preklad hovoru pokračuje na pozadí. Ťuknutím sa vrátite.', + 'meetingRecordScreenCapturePermissionDenied': 'Na nahrávanie systémového zvuku je potrebné povolenie na nahrávanie obrazovky. Udeľte ho a skúste to znova.', + 'pleaseGrantBluetoothPermission': 'Na skenovanie udeľte povolenie Bluetooth', + 'startScanFailed': 'Spustenie skenovania zlyhalo', + 'pleaseLoginFirst': 'Najprv sa prihláste', + 'deviceUnauthorized': 'Zariadenie nie je autorizované, skúste to znova', + 'boundDevices': 'Prepojené zariadenia', + 'currentConnection': 'Aktuálne pripojenie', + 'binding': 'Prepája sa…', + 'permissionDisabled': 'Vypnuté', + 'confirmDisablePermissionTitle': 'Vypnúť povolenie', + 'confirmDisablePermissionContent': 'Vypnúť povolenie {permission}? Na opätovné zapnutie bude potrebné prejsť do nastavení systému.', + 'confirmPermanentlyDisallowTitle': 'Prestať sa pýtať?', + 'confirmPermanentlyDisallowContent': 'Zamietli ste povolenie {permission}. Prestať sa odteraz pýtať? Ak zvolíte „Nepovoliť“, môžete ho neskôr zapnúť v nastaveniach systému.', + 'notNow': 'Teraz nie', + 'permanentlyDisallow': 'Nepovoliť', + 'otaBesNotSupported': 'Tieto slúchadlá zatiaľ nepodporujú aktualizáciu firmvéru v aplikácii. Kontaktujte podporu.', + 'tabDevice': 'Zariadenia', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Technológie pre inteligentnejší život', + 'sloganAi': 'Inteligencia bez hraníc', + 'sloganDevice': 'Inteligentný hardvér pripravený na budúcnosť', + 'sloganPlaza': 'Inteligentný svet, ktorý vám rozumie', + 'aiEditHint': 'Dlhým stlačením karty presuniete a preusporiadate moduly', + 'aiEmptyTitle': 'Zatiaľ žiadne moduly', + 'aiEmptyDesc': 'Vyberte si potrebných agentov v Plaza', + 'goToPlaza': 'Prejsť do Plaza', + 'plazaOnline': 'K dispozícii', + 'plazaPlanned': 'Už čoskoro', + 'plazaSearchHint': 'Hľadať agentov, napr. „preklad“, „nahrávanie“', + 'moduleRemove': 'Odstrániť', + 'moduleAdd': 'Pridať', + 'moduleRemoved': 'Odstránené', + 'moduleAdded': 'Pridané', + 'goSee': 'Zobraziť', + 'comingSoonTag': 'Už čoskoro', + 'needDeviceTag': 'Vyžaduje zariadenie', + 'featureInDev': 'Táto funkcia sa pripravuje', + 'featureNotWired': 'Zatiaľ nie je k dispozícii', + 'todayLabel': 'Dnes', + 'deviceConnected': 'Pripojené', + 'licenseUnknown': 'Licencia neznáma', + 'selectDevice': 'Vyberte zariadenie', + 'catNoteCard': 'AI záznamová karta', + 'catNoteCardDesc': 'Záznamník v tvare karty', + 'catParkerPen': 'AI pero', + 'catParkerPenDesc': 'Perá s hlasovým záznamníkom', + 'catStylusPen': 'AI stylus', + 'catStylusPenDesc': 'Zariadenia na ručné písanie / stylusy', + 'catStudyMachine': 'AI výukový tablet', + 'catStudyMachineDesc': 'Výukové zariadenia', + 'besAddTitle': 'Pridať AI slúchadlá', + 'besConnecting': 'Pripája sa k slúchadlám…', + 'besNotFound': 'Slúchadlá sa nenašli', + 'besNotFoundIosDesc': 'Najprv pripojte slúchadlá v Nastavenia → Bluetooth a potom sa vráťte', + 'besNotFoundAndroidDesc': 'Najprv spárujte slúchadlá v Nastavenia → Bluetooth a potom ich tu pripojte', + 'besReadFailed': 'Čítanie zlyhalo', + 'besConnectFailIos': 'Uistite sa, že sa slúchadlá v systémovom Bluetooth zobrazujú ako Pripojené, a skúste to znova', + 'besConnectFailAndroid': 'Uistite sa, že sú slúchadlá zapnuté, nablízku a nie sú pripojené k inému zariadeniu. Po prepojení sa budú pripájať automaticky.', + 'holderAddTitle': 'Pridať AI stojan na telefón', + 'holderConnecting': 'Pripája sa k zariadeniu…', + 'holderSearching': 'Hľadajú sa zariadenia…', + 'holderNotFound': 'Nenašli sa žiadne zariadenia', + 'holderPairHint': 'Uistite sa, že je stojan zapnutý a v režime párovania', + 'holderRetryHint': 'Uistite sa, že je zariadenie zapnuté a nablízku, a skúste to znova', + 'autoConnectTitle': 'Automatické pripojenie zariadení', + 'autoConnectDesc': 'Prebudí aplikáciu, aby sa znova pripojila a prijala nahrávky, keď sa vaše zariadenie zapne alebo priblíži', + 'autoConnectConsentTitle': 'Zapnúť automatické pripojenie', + 'autoConnectConsentIntro': 'Aby sa vaše zariadenie (AI slúchadlá / AI stojan na telefón) mohlo pripájať automaticky a ukladať nahrávky po stlačení tlačidla nahrávania, potrebujeme váš súhlas:', + 'autoConnectConsentB1': 'Zaregistrovať skenovanie Bluetooth na pozadí, aby sa aplikácia pri zistení prepojeného zariadenia prebudila (automaticky spustila), znova pripojila a prijala nahrávky', + 'autoConnectConsentB2': 'Po prebudení sa používa iba na pripojenie zariadenia, nahrávanie a odosielanie — nič iné, žiadne ďalšie aplikácie sa nespúšťajú', + 'autoConnectConsentB3': 'Aplikáciu môžete používať aj bez toho — stačí zariadenie zakaždým pripojiť ručne', + 'autoConnectConsentB4': 'Kedykoľvek to môžete vypnúť v Nastavenia → Automatické pripojenie zariadení', + 'autoConnectAgree': 'Súhlasím a zapnúť', + 'autoConnectLater': 'Teraz nie', + 'autoConnectRequired': 'Automatické pripojenie je vypnuté', + 'autoConnectRequiredDesc': 'Na prepojenie tohto zariadenia zapnite automatické pripojenie', + 'recordTapToStart': 'Ťuknutím na tlačidlo nižšie spustíte nahrávanie', + 'recordPaused': 'Pozastavené', + 'recordMark': 'Značka', + 'recordDeleteTitle': 'Odstrániť nahrávku', + 'accountAndProfile': 'Účet a profil', + 'nicknameUnset': 'Prezývka nie je nastavená', + 'nicknameInput': 'Zadajte prezývku', + 'loginMethod': 'Spôsob prihlásenia', + 'manageMyLogin': 'Spravovať prihlásenie', + 'logoutAction': 'Odhlásiť sa', + 'warningLabel': 'Upozornenie:', + 'deleteAccountWarn': 'Váš účet a všetky súbory budú natrvalo odstránené.', + 'icpFiling': 'Registrácia ICP', + 'logExport': 'Export protokolov', + 'logExportDesc': 'Zobraziť a exportovať protokoly aplikácie', + 'permLoadFailed': 'Načítanie skupín povolení zlyhalo', + 'permInsufficient': 'Povolenie zamietnuté', + 'voiceCloneCreating': 'Vytvára sa váš hlas…', + 'voiceCloneCreate': 'Vytvoriť môj hlas', + 'voiceCloneAgree': 'Súhlasím a prečítam vyhlásenie nahlas', + 'voiceCloneReadPrompt': 'Prečítajte:', + 'voiceCloneFirstMonthFree': 'Prvý mesiac zadarmo', + 'voiceCloneEnable': 'Zapnúť klonovanie hlasu', + 'noMusicPlaying': 'Nič sa neprehráva', + 'qqMusicNoSeek': 'QQ Music nepodporuje pretáčanie', + 'bleScanTitle': 'Skenovanie BLE', + 'bluetoothOn': 'Bluetooth zapnutý', + 'bleScanning': 'Skenuje sa…', + 'bleConnectedDevices': 'Pripojené zariadenia', + 'bleUnknownDevice': 'Neznáme zariadenie', + 'bleTapToScan': 'Ťuknutím na Skenovať vyhľadáte BLE zariadenia', + 'weekMon': 'Po', + 'weekTue': 'Ut', + 'weekWed': 'St', + 'weekThu': 'Št', + 'weekFri': 'Pi', + 'weekSat': 'So', + 'weekSun': 'Ne', + 'agentMeeting': 'Hlasové zápisnice', + 'agentMeetingDesc': 'Zhrnutie nahrávok, centrum pamäte', + 'agentEmai': 'Asistent EMAI', + 'agentEmaiDesc': 'Rozprávajte sa a pýtajte sa hlasom na čokoľvek', + 'agentSimultaneous': 'Živý preklad', + 'agentSimultaneousDesc': 'Preklad počas reči', + 'agentFaceToFace': 'Tvárou v tvár', + 'agentFaceToFaceDesc': 'Obojsmerný preklad konverzácie', + 'agentCallRecording': 'Nahrávanie hovorov', + 'agentCallRecordingDesc': 'Hovory sa ukladajú automaticky', + 'agentFieldRecording': 'Terénne nahrávanie', + 'agentFieldRecordingDesc': 'Mikrofón zariadenia alebo telefónu', + 'agentCall': 'Preklad hovoru', + 'agentCallDesc': 'Preklad v reálnom čase počas hovorov', + 'agentAudioVideo': 'Preklad médií', + 'agentAudioVideoDesc': 'Záber kamery / preklad audia a videa', + 'agentEnglishChat': 'Konverzácia v angličtine', + 'agentEnglishChatDesc': 'Imerzívne precvičovanie rozprávania', + 'agentEnglishStudy': 'Štúdium angličtiny', + 'agentEnglishStudyDesc': 'Lekcie slovnej zásoby a gramatiky', + 'agentKidsStory': 'Detské rozprávky', + 'agentKidsStoryDesc': 'Rozprávky na dobrú noc a otázky s odpoveďami', + 'moduleRemovedDesc': 'odstránené zo stránky AI', + 'moduleAddedDesc': 'pridané na koniec stránky AI', + 'calNoRecords': 'Žiadne záznamy', + 'calNoRecordsDay': 'Nič naplánované', + 'calTodos': 'Úlohy', + 'calExpenses': 'Výdavky', + 'calTodoCount': 'Úlohy: @count', + 'calExpenseCount': 'Výdavky: @count', + 'calEntryCount': 'Záznamy: @count', + 'calItemsUnit': 'položiek', + 'calCountUnit': 'záznamov', + 'calTotalAmount': 'Spolu', + 'recordPause': 'Pozastaviť', + 'recordResume': 'Pokračovať', + 'recordDeleteConfirm': 'Odstrániť túto nahrávku?', + 'scopeDay': 'Deň', + 'scopeWeek': 'Týždeň', + 'scopeMonth': 'Mesiac', + 'allDay': 'Celý deň', + 'guestModeTitle': 'Režim hosťa', + 'guestModeDesc': 'Hostia môžu iba prezerať. Prihláste sa a používajte hlasové poznámky, preklad a nahrávanie — vaše údaje sa uložia k vášmu účtu.', + 'guestKeepBrowsing': 'Pokračovať v prezeraní', + 'guestGoLogin': 'Prihlásiť sa', + 'guestViewOnlyTag': 'Iba prezeranie', + 'autoConnectReenableHint': 'Automatické pripojenie je vypnuté. Znova ho zapnite v Nastavenia → Automatické pripojenie zariadení.', + 'plazaEntryDesc': 'Prezerajte a pridávajte ďalších agentov', + 'agentTextTranslation': 'Preklad textu', + 'agentTextTranslationDesc': 'Preklad napísaného alebo vloženého textu', + 'agentPictureTranslation': 'Preklad fotiek', + 'agentPictureTranslationDesc': 'Odfoťte alebo vyberte fotku na preklad', + 'callRequiredTitle': 'Vyžaduje sa hovor', + 'callRequiredDesc': 'Táto funkcia funguje iba počas hovoru', + 'inCallBusyTitle': 'Počas hovoru nedostupné', + 'inCallBusyDesc': 'Mikrofón a zvukovú cestu používa hovor. Skúste to znova po zavesení.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Zadarmo', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/sl_si.dart b/apps/client/lib/core/translations/language/sl_si.dart index 61f616d3..f411afd9 100644 --- a/apps/client/lib/core/translations/language/sl_si.dart +++ b/apps/client/lib/core/translations/language/sl_si.dart @@ -1916,4 +1916,208 @@ const Map slSI = { 'unmarkFavorite': 'Odstrani iz priljubljenih', 'unnamedDevice': 'Neimenovana naprava', 'userDataParseFailed': 'Uporabniških podatkov ni bilo mogoče prebrati', + 'catEarphone': 'AI slušalke', + 'catEarphoneDesc': 'Klasične Bluetooth / BLE slušalke', + 'catPhoneHolder': 'AI držalo za telefon', + 'catPhoneHolderDesc': 'Naprave tipa držalo', + 'catCarAroma': 'AI avtomobilski difuzor', + 'catCarAromaDesc': 'Difuzor vonja za avto', + 'agreeAndContinue': 'Strinjam se in nadaljuj', + 'memberServiceAgreement': 'Pogodba o članskih storitvah', + 'memberServiceAgreementTitle': 'Pogodba o članskih storitvah', + 'memberServiceAgreementIntro': 'Da bi vam zagotovili boljše članske storitve, pred naročnino pozorno preberite: ', + 'memberServiceAgreementOutro': '. S klikom na „Strinjam se in nadaljuj“ potrjujete, da ste v celoti prebrali in sprejeli zgornjo pogodbo.', + 'memberAgreementRejectedTip': 'Za nadaljevanje morate sprejeti Pogodbo o članskih storitvah.', + 'translationCallExitTitle': 'Izhod iz prevajanja klica', + 'translationCallExitMessage': 'Izberite dejanje pred izhodom', + 'translationCallEnd': 'Končaj prevajanje klica', + 'translationContinueInBackground': 'Nadaljuj prevajanje v ozadju', + 'backgroundRecordingIndicatorBody': 'Snemanje se nadaljuje v ozadju. Tapnite za vrnitev.', + 'backgroundTranslationIndicatorBody': 'Prevajanje klica se nadaljuje v ozadju. Tapnite za vrnitev.', + 'meetingRecordScreenCapturePermissionDenied': 'Za snemanje sistemskega zvoka je potrebno dovoljenje za snemanje zaslona. Odobrite ga in poskusite znova.', + 'pleaseGrantBluetoothPermission': 'Za iskanje dovolite dostop do Bluetootha', + 'startScanFailed': 'Zagon iskanja ni uspel', + 'pleaseLoginFirst': 'Najprej se prijavite', + 'deviceUnauthorized': 'Naprava ni pooblaščena, poskusite znova', + 'boundDevices': 'Povezane naprave', + 'currentConnection': 'Trenutna povezava', + 'binding': 'Povezovanje...', + 'permissionDisabled': 'Izklopljeno', + 'confirmDisablePermissionTitle': 'Izklopi dovoljenje', + 'confirmDisablePermissionContent': 'Želite izklopiti dovoljenje {permission}? Za ponovno omogočanje boste morali v sistemske nastavitve.', + 'confirmPermanentlyDisallowTitle': 'Ne sprašuj več?', + 'confirmPermanentlyDisallowContent': 'Zavrnili ste dovoljenje {permission}. Naj vas ne sprašujemo več? Če izberete „Ne dovoli“, ga lahko pozneje še vedno omogočite v sistemskih nastavitvah.', + 'notNow': 'Ne zdaj', + 'permanentlyDisallow': 'Ne dovoli', + 'otaBesNotSupported': 'Te slušalke še ne podpirajo nadgradnje vdelane programske opreme v aplikaciji. Obrnite se na podporo.', + 'tabDevice': 'Naprave', + 'tabPlaza': 'Trg', + 'sloganHome': 'Tehnologija za pametnejše življenje', + 'sloganAi': 'Inteligenca brez meja', + 'sloganDevice': 'Pametna strojna oprema, pripravljena na prihodnost', + 'sloganPlaza': 'Pameten svet, ki vas razume', + 'aiEditHint': 'Dolgo pritisnite kartico, da povlečete in prerazporedite module', + 'aiEmptyTitle': 'Ni še dodanih modulov', + 'aiEmptyDesc': 'Na Trgu izberite agente, ki jih potrebujete', + 'goToPlaza': 'Pojdi na Trg', + 'plazaOnline': 'Na voljo', + 'plazaPlanned': 'Kmalu', + 'plazaSearchHint': 'Iščite agente, npr. „prevod“, „snemanje“', + 'moduleRemove': 'Odstrani', + 'moduleAdd': 'Dodaj', + 'moduleRemoved': 'Odstranjeno', + 'moduleAdded': 'Dodano', + 'goSee': 'Poglej', + 'comingSoonTag': 'Kmalu', + 'needDeviceTag': 'Potrebna naprava', + 'featureInDev': 'Ta funkcija je v razvoju', + 'featureNotWired': 'Še ni na voljo', + 'todayLabel': 'Danes', + 'deviceConnected': 'Povezano', + 'licenseUnknown': 'Licenca neznana', + 'selectDevice': 'Izberite napravo', + 'catNoteCard': 'AI snemalna kartica', + 'catNoteCardDesc': 'Snemalnik v obliki kartice', + 'catParkerPen': 'AI pisalo', + 'catParkerPenDesc': 'Pisala za snemanje glasu', + 'catStylusPen': 'AI stilus', + 'catStylusPenDesc': 'Naprave za rokopis / stilusi', + 'catStudyMachine': 'AI učna tablica', + 'catStudyMachineDesc': 'Naprave za učenje', + 'besAddTitle': 'Dodaj AI slušalke', + 'besConnecting': 'Povezovanje s slušalkami…', + 'besNotFound': 'Slušalke niso najdene', + 'besNotFoundIosDesc': 'Najprej povežite slušalke v Nastavitve → Bluetooth, nato se vrnite sem', + 'besNotFoundAndroidDesc': 'Najprej seznanite slušalke v Nastavitve → Bluetooth, nato jih povežite tukaj', + 'besReadFailed': 'Branje ni uspelo', + 'besConnectFailIos': 'Prepričajte se, da so slušalke v sistemskem Bluetoothu prikazane kot Povezane, nato poskusite znova', + 'besConnectFailAndroid': 'Prepričajte se, da so slušalke vklopljene, v bližini in niso povezane z drugo napravo. Ko bodo povezane, se bodo samodejno znova povezale.', + 'holderAddTitle': 'Dodaj AI stojalo za telefon', + 'holderConnecting': 'Povezovanje z napravo…', + 'holderSearching': 'Iskanje naprav…', + 'holderNotFound': 'Ni najdenih naprav', + 'holderPairHint': 'Prepričajte se, da je stojalo vklopljeno in v načinu seznanjanja', + 'holderRetryHint': 'Prepričajte se, da je naprava vklopljena in v bližini, nato poskusite znova', + 'autoConnectTitle': 'Samodejno povezovanje naprav', + 'autoConnectDesc': 'Prebudi aplikacijo za ponovno povezavo in prejem posnetkov, ko se naprava vklopi ali približa', + 'autoConnectConsentTitle': 'Omogoči samodejno povezovanje', + 'autoConnectConsentIntro': 'Da se vaša naprava (AI slušalke / AI stojalo za telefon) samodejno poveže in shrani posnetke, ko pritisnete njen gumb za snemanje, potrebujemo vaše soglasje:', + 'autoConnectConsentB1': 'Registracija Bluetooth iskanja v ozadju, da se aplikacija prebudi (samodejno zažene), ko je zaznana vaša povezana naprava, za ponovno povezavo in prejem posnetkov', + 'autoConnectConsentB2': 'Po prebuditvi se uporablja samo za povezavo naprave, snemanje in nalaganje — nič drugega, druge aplikacije se ne zaženejo', + 'autoConnectConsentB3': 'Aplikacijo lahko uporabljate tudi brez tega — napravo le vsakič povežite ročno', + 'autoConnectConsentB4': 'Kadarkoli ga lahko izklopite v Nastavitve → Samodejno povezovanje naprav', + 'autoConnectAgree': 'Strinjam se in omogoči', + 'autoConnectLater': 'Ne zdaj', + 'autoConnectRequired': 'Samodejno povezovanje je izklopljeno', + 'autoConnectRequiredDesc': 'Za povezavo te naprave omogočite samodejno povezovanje', + 'recordTapToStart': 'Tapnite spodnji gumb za začetek snemanja', + 'recordPaused': 'Začasno ustavljeno', + 'recordMark': 'Označi', + 'recordDeleteTitle': 'Izbriši posnetek', + 'accountAndProfile': 'Račun in profil', + 'nicknameUnset': 'Vzdevek ni nastavljen', + 'nicknameInput': 'Vnesite vzdevek', + 'loginMethod': 'Način prijave', + 'manageMyLogin': 'Upravljaj prijavo', + 'logoutAction': 'Odjava', + 'warningLabel': 'Opozorilo:', + 'deleteAccountWarn': 'Vaš račun in vse datoteke bodo trajno izbrisani.', + 'icpFiling': 'ICP registracija', + 'logExport': 'Izvoz dnevnikov', + 'logExportDesc': 'Oglejte si in izvozite dnevnike aplikacije', + 'permLoadFailed': 'Nalaganje skupin dovoljenj ni uspelo', + 'permInsufficient': 'Dovoljenje zavrnjeno', + 'voiceCloneCreating': 'Ustvarjanje vašega glasu…', + 'voiceCloneCreate': 'Ustvari moj glas', + 'voiceCloneAgree': 'Strinjam se in bom izjavo prebral naglas', + 'voiceCloneReadPrompt': 'Preberite:', + 'voiceCloneFirstMonthFree': 'Prvi mesec brezplačno', + 'voiceCloneEnable': 'Omogoči kloniranje glasu', + 'noMusicPlaying': 'Nič se ne predvaja', + 'qqMusicNoSeek': 'Previjanje ni podprto za QQ Music', + 'bleScanTitle': 'BLE iskanje', + 'bluetoothOn': 'Bluetooth vklopljen', + 'bleScanning': 'Iskanje…', + 'bleConnectedDevices': 'Povezane naprave', + 'bleUnknownDevice': 'Neznana naprava', + 'bleTapToScan': 'Tapnite Išči za iskanje naprav BLE', + 'weekMon': 'Pon', + 'weekTue': 'Tor', + 'weekWed': 'Sre', + 'weekThu': 'Čet', + 'weekFri': 'Pet', + 'weekSat': 'Sob', + 'weekSun': 'Ned', + 'agentMeeting': 'Glasovni zapisnik', + 'agentMeetingDesc': 'Povzemanje posnetkov, središče spominov', + 'agentEmai': 'Pomočnik EMAI', + 'agentEmaiDesc': 'Klepetajte in vprašajte karkoli z glasom', + 'agentSimultaneous': 'Simultano prevajanje', + 'agentSimultaneousDesc': 'Prevajanje med govorjenjem', + 'agentFaceToFace': 'Iz oči v oči', + 'agentFaceToFaceDesc': 'Dvosmerno prevajanje pogovora', + 'agentCallRecording': 'Snemanje klicev', + 'agentCallRecordingDesc': 'Klici se samodejno shranijo', + 'agentFieldRecording': 'Terensko snemanje', + 'agentFieldRecordingDesc': 'Mikrofon naprave ali telefona', + 'agentCall': 'Prevajanje klicev', + 'agentCallDesc': 'Prevajanje v realnem času med klici', + 'agentAudioVideo': 'Prevajanje medijev', + 'agentAudioVideoDesc': 'Kadriranje s kamero / prevajanje avdia in videa', + 'agentEnglishChat': 'Klepet v angleščini', + 'agentEnglishChatDesc': 'Poglobljena vadba govora', + 'agentEnglishStudy': 'Učenje angleščine', + 'agentEnglishStudyDesc': 'Lekcije besedišča in slovnice', + 'agentKidsStory': 'Otroške zgodbe', + 'agentKidsStoryDesc': 'Zgodbe za lahko noč ter vprašanja in odgovori', + 'moduleRemovedDesc': 'odstranjeno s strani AI', + 'moduleAddedDesc': 'dodano na dno strani AI', + 'calNoRecords': 'Ni vnosov', + 'calNoRecordsDay': 'Nič načrtovanega', + 'calTodos': 'Opravila', + 'calExpenses': 'Stroški', + 'calTodoCount': '@count opravil', + 'calExpenseCount': '@count stroškov', + 'calEntryCount': '@count vnosov', + 'calItemsUnit': 'elementov', + 'calCountUnit': 'vnosov', + 'calTotalAmount': 'Skupaj', + 'recordPause': 'Premor', + 'recordResume': 'Nadaljuj', + 'recordDeleteConfirm': 'Želite izbrisati ta posnetek?', + 'scopeDay': 'Dan', + 'scopeWeek': 'Teden', + 'scopeMonth': 'Mesec', + 'allDay': 'Ves dan', + 'guestModeTitle': 'Način gosta', + 'guestModeDesc': 'Gostje lahko samo brskajo. Prijavite se za uporabo glasovnih zapiskov, prevajanja in snemanja — vaši podatki bodo shranjeni v vašem računu.', + 'guestKeepBrowsing': 'Nadaljuj brskanje', + 'guestGoLogin': 'Prijava', + 'guestViewOnlyTag': 'Samo ogled', + 'autoConnectReenableHint': 'Samodejno povezovanje je izklopljeno. Znova ga vklopite v Nastavitve → Samodejno povezovanje naprav.', + 'plazaEntryDesc': 'Prebrskajte in dodajte več agentov', + 'agentTextTranslation': 'Prevajanje besedila', + 'agentTextTranslationDesc': 'Prevedite vneseno ali prilepljeno besedilo', + 'agentPictureTranslation': 'Prevajanje fotografij', + 'agentPictureTranslationDesc': 'Posnemite ali izberite fotografijo za prevod', + 'callRequiredTitle': 'Potreben je klic', + 'callRequiredDesc': 'Ta funkcija deluje samo med klicem', + 'inCallBusyTitle': 'Ni na voljo med klicem', + 'inCallBusyDesc': 'Mikrofon in zvočno pot uporablja klic. Poskusite znova, ko odložite.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Brezplačno', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/sr_rs.dart b/apps/client/lib/core/translations/language/sr_rs.dart index cbb78188..a8afcee5 100644 --- a/apps/client/lib/core/translations/language/sr_rs.dart +++ b/apps/client/lib/core/translations/language/sr_rs.dart @@ -1912,4 +1912,208 @@ const Map srRS = { 'unmarkFavorite': 'Уклони из омиљених', 'unnamedDevice': 'Уређај без назива', 'userDataParseFailed': 'Подаци корисника нису могли да се учитају', + 'catEarphone': 'AI slušalice', + 'catEarphoneDesc': 'Klasične Bluetooth / BLE slušalice', + 'catPhoneHolder': 'AI držač telefona', + 'catPhoneHolderDesc': 'Uređaji tipa držač', + 'catCarAroma': 'AI auto difuzor', + 'catCarAromaDesc': 'Difuzor mirisa za auto', + 'agreeAndContinue': 'Prihvati i nastavi', + 'memberServiceAgreement': 'Ugovor o članskim uslugama', + 'memberServiceAgreementTitle': 'Ugovor o članskim uslugama', + 'memberServiceAgreementIntro': 'Da bismo vam pružili bolje članske usluge, pažljivo pročitajte pre pretplate: ', + 'memberServiceAgreementOutro': '. Klikom na „Prihvati i nastavi“ potvrđujete da ste u potpunosti pročitali i prihvatili gore navedeni ugovor.', + 'memberAgreementRejectedTip': 'Morate prihvatiti Ugovor o članskim uslugama da biste nastavili.', + 'translationCallExitTitle': 'Izlaz iz prevoda poziva', + 'translationCallExitMessage': 'Izaberite šta želite da uradite pre izlaska', + 'translationCallEnd': 'Završi prevod poziva', + 'translationContinueInBackground': 'Nastavi prevod u pozadini', + 'backgroundRecordingIndicatorBody': 'Snimanje se nastavlja u pozadini. Dodirnite da se vratite.', + 'backgroundTranslationIndicatorBody': 'Prevod poziva se nastavlja u pozadini. Dodirnite da se vratite.', + 'meetingRecordScreenCapturePermissionDenied': 'Za snimanje sistemskog zvuka potrebna je dozvola za snimanje ekrana. Odobrite je i pokušajte ponovo.', + 'pleaseGrantBluetoothPermission': 'Dozvolite pristup Bluetooth-u za pretraživanje', + 'startScanFailed': 'Pokretanje pretrage nije uspelo', + 'pleaseLoginFirst': 'Prvo se prijavite', + 'deviceUnauthorized': 'Uređaj nije autorizovan, pokušajte ponovo', + 'boundDevices': 'Vezani uređaji', + 'currentConnection': 'Trenutna veza', + 'binding': 'Vezivanje...', + 'permissionDisabled': 'Isključeno', + 'confirmDisablePermissionTitle': 'Isključi dozvolu', + 'confirmDisablePermissionContent': 'Isključiti dozvolu {permission}? Moraćete da je ponovo uključite u sistemskim podešavanjima.', + 'confirmPermanentlyDisallowTitle': 'Ne pitati više?', + 'confirmPermanentlyDisallowContent': 'Odbili ste dozvolu {permission}. Da više ne pitamo? Ako izaberete „Ne dozvoli“, i dalje je možete kasnije uključiti u sistemskim podešavanjima.', + 'notNow': 'Ne sada', + 'permanentlyDisallow': 'Ne dozvoli', + 'otaBesNotSupported': 'Ove slušalice još ne podržavaju ažuriranje firmvera iz aplikacije. Obratite se podršci.', + 'tabDevice': 'Uređaji', + 'tabPlaza': 'Trg', + 'sloganHome': 'Tehnologija za pametniji život', + 'sloganAi': 'Inteligencija bez granica', + 'sloganDevice': 'Pametan hardver, spreman za budućnost', + 'sloganPlaza': 'Pametan svet koji te razume', + 'aiEditHint': 'Dugo pritisnite karticu da prevučete i preuredite module', + 'aiEmptyTitle': 'Još nema dodatih modula', + 'aiEmptyDesc': 'Izaberite potrebne agente na Trgu', + 'goToPlaza': 'Idi na Trg', + 'plazaOnline': 'Dostupno', + 'plazaPlanned': 'Uskoro', + 'plazaSearchHint': 'Pretraži agente, npr. „prevod“, „snimanje“', + 'moduleRemove': 'Ukloni', + 'moduleAdd': 'Dodaj', + 'moduleRemoved': 'Uklonjeno', + 'moduleAdded': 'Dodato', + 'goSee': 'Pogledaj', + 'comingSoonTag': 'Uskoro', + 'needDeviceTag': 'Potreban uređaj', + 'featureInDev': 'Ova funkcija je u razvoju', + 'featureNotWired': 'Još nije dostupno', + 'todayLabel': 'Danas', + 'deviceConnected': 'Povezano', + 'licenseUnknown': 'Licenca nepoznata', + 'selectDevice': 'Izaberite uređaj', + 'catNoteCard': 'AI kartica za snimanje', + 'catNoteCardDesc': 'Diktafon u obliku kartice', + 'catParkerPen': 'AI olovka', + 'catParkerPenDesc': 'Olovke sa diktafonom', + 'catStylusPen': 'AI stilus', + 'catStylusPenDesc': 'Uređaji za rukopis / stilus', + 'catStudyMachine': 'AI tablet za učenje', + 'catStudyMachineDesc': 'Uređaji za učenje', + 'besAddTitle': 'Dodaj AI slušalice', + 'besConnecting': 'Povezivanje sa slušalicama…', + 'besNotFound': 'Slušalice nisu pronađene', + 'besNotFoundIosDesc': 'Prvo povežite slušalice u Podešavanja → Bluetooth, pa se vratite ovde', + 'besNotFoundAndroidDesc': 'Prvo uparite slušalice u Podešavanja → Bluetooth, pa ih povežite ovde', + 'besReadFailed': 'Čitanje nije uspelo', + 'besConnectFailIos': 'Proverite da su slušalice prikazane kao „Povezano“ u sistemskom Bluetooth-u, pa pokušajte ponovo', + 'besConnectFailAndroid': 'Proverite da su slušalice uključene, u blizini i da nisu povezane sa drugim uređajem. Nakon povezivanja povezivaće se automatski.', + 'holderAddTitle': 'Dodaj AI držač telefona', + 'holderConnecting': 'Povezivanje sa uređajem…', + 'holderSearching': 'Traženje uređaja…', + 'holderNotFound': 'Nije pronađen nijedan uređaj', + 'holderPairHint': 'Proverite da je držač uključen i u režimu uparivanja', + 'holderRetryHint': 'Proverite da je uređaj uključen i u blizini, pa pokušajte ponovo', + 'autoConnectTitle': 'Automatsko povezivanje uređaja', + 'autoConnectDesc': 'Budi aplikaciju radi ponovnog povezivanja i prijema snimaka kada se uređaj uključi ili nađe u blizini', + 'autoConnectConsentTitle': 'Uključi automatsko povezivanje', + 'autoConnectConsentIntro': 'Da bi se vaš uređaj (AI slušalice / AI držač telefona) automatski povezivao i čuvao snimke kada pritisnete dugme za snimanje, potrebna nam je vaša saglasnost:', + 'autoConnectConsentB1': 'Registrovanje pozadinske Bluetooth pretrage kako bi se aplikacija probudila (automatski pokrenula) kada se otkrije vaš vezani uređaj, radi ponovnog povezivanja i prijema snimaka', + 'autoConnectConsentB2': 'Nakon buđenja koristi se samo za povezivanje uređaja, snimanje i otpremanje — ništa drugo, i ne pokreću se druge aplikacije', + 'autoConnectConsentB3': 'Aplikaciju možete koristiti i bez toga — samo svaki put ručno povežite uređaj', + 'autoConnectConsentB4': 'Možete je isključiti bilo kada u Podešavanja → Automatsko povezivanje uređaja', + 'autoConnectAgree': 'Prihvati i uključi', + 'autoConnectLater': 'Ne sada', + 'autoConnectRequired': 'Automatsko povezivanje je isključeno', + 'autoConnectRequiredDesc': 'Uključite automatsko povezivanje da biste vezali ovaj uređaj', + 'recordTapToStart': 'Dodirnite dugme ispod da započnete snimanje', + 'recordPaused': 'Pauzirano', + 'recordMark': 'Oznaka', + 'recordDeleteTitle': 'Obriši snimak', + 'accountAndProfile': 'Nalog i profil', + 'nicknameUnset': 'Nadimak nije postavljen', + 'nicknameInput': 'Unesite nadimak', + 'loginMethod': 'Način prijave', + 'manageMyLogin': 'Upravljaj prijavom', + 'logoutAction': 'Odjavi se', + 'warningLabel': 'Upozorenje:', + 'deleteAccountWarn': 'Vaš nalog i sve datoteke biće trajno obrisani.', + 'icpFiling': 'ICP registracija', + 'logExport': 'Izvoz dnevnika', + 'logExportDesc': 'Pregled i izvoz dnevnika aplikacije', + 'permLoadFailed': 'Učitavanje grupa dozvola nije uspelo', + 'permInsufficient': 'Dozvola odbijena', + 'voiceCloneCreating': 'Kreiranje vašeg glasa…', + 'voiceCloneCreate': 'Kreiraj moj glas', + 'voiceCloneAgree': 'Prihvati i pročitaj izjavu naglas', + 'voiceCloneReadPrompt': 'Pročitajte:', + 'voiceCloneFirstMonthFree': 'Prvi mesec besplatno', + 'voiceCloneEnable': 'Uključi kloniranje glasa', + 'noMusicPlaying': 'Ništa se ne reprodukuje', + 'qqMusicNoSeek': 'Premotavanje nije podržano za QQ Music', + 'bleScanTitle': 'BLE pretraga', + 'bluetoothOn': 'Bluetooth je uključen', + 'bleScanning': 'Pretraživanje…', + 'bleConnectedDevices': 'Povezani uređaji', + 'bleUnknownDevice': 'Nepoznat uređaj', + 'bleTapToScan': 'Dodirnite „Pretraži“ da potražite BLE uređaje', + 'weekMon': 'Pon', + 'weekTue': 'Uto', + 'weekWed': 'Sre', + 'weekThu': 'Čet', + 'weekFri': 'Pet', + 'weekSat': 'Sub', + 'weekSun': 'Ned', + 'agentMeeting': 'Glasovne beleške', + 'agentMeetingDesc': 'Rezimei snimaka, centar memorije', + 'agentEmai': 'EMAI asistent', + 'agentEmaiDesc': 'Razgovarajte i pitajte bilo šta glasom', + 'agentSimultaneous': 'Prevod uživo', + 'agentSimultaneousDesc': 'Prevod dok govorite', + 'agentFaceToFace': 'Licem u lice', + 'agentFaceToFaceDesc': 'Dvosmerni prevod razgovora', + 'agentCallRecording': 'Snimanje poziva', + 'agentCallRecordingDesc': 'Pozivi se čuvaju automatski', + 'agentFieldRecording': 'Snimanje na terenu', + 'agentFieldRecordingDesc': 'Mikrofon uređaja ili telefona', + 'agentCall': 'Prevod poziva', + 'agentCallDesc': 'Prevod u realnom vremenu tokom poziva', + 'agentAudioVideo': 'Prevod medija', + 'agentAudioVideoDesc': 'Kadriranje kamerom / prevod audio i video sadržaja', + 'agentEnglishChat': 'Razgovor na engleskom', + 'agentEnglishChatDesc': 'Imerzivno vežbanje govora', + 'agentEnglishStudy': 'Učenje engleskog', + 'agentEnglishStudyDesc': 'Lekcije iz vokabulara i gramatike', + 'agentKidsStory': 'Priče za decu', + 'agentKidsStoryDesc': 'Priče za laku noć i pitanja i odgovori', + 'moduleRemovedDesc': 'uklonjeno sa AI stranice', + 'moduleAddedDesc': 'dodato na dno AI stranice', + 'calNoRecords': 'Nema unosa', + 'calNoRecordsDay': 'Ništa nije zakazano', + 'calTodos': 'Zadaci', + 'calExpenses': 'Troškovi', + 'calTodoCount': '@count zadataka', + 'calExpenseCount': '@count troškova', + 'calEntryCount': '@count unosa', + 'calItemsUnit': 'stavki', + 'calCountUnit': 'unosa', + 'calTotalAmount': 'Ukupno', + 'recordPause': 'Pauziraj', + 'recordResume': 'Nastavi', + 'recordDeleteConfirm': 'Obrisati ovaj snimak?', + 'scopeDay': 'Dan', + 'scopeWeek': 'Nedelja', + 'scopeMonth': 'Mesec', + 'allDay': 'Ceo dan', + 'guestModeTitle': 'Režim gosta', + 'guestModeDesc': 'Gosti mogu samo da pregledaju. Prijavite se da biste koristili glasovne beleške, prevod i snimanje — vaši podaci će se čuvati na vašem nalogu.', + 'guestKeepBrowsing': 'Nastavi pregled', + 'guestGoLogin': 'Prijavi se', + 'guestViewOnlyTag': 'Samo pregled', + 'autoConnectReenableHint': 'Automatsko povezivanje je isključeno. Ponovo ga uključite u Podešavanja → Automatsko povezivanje uređaja.', + 'plazaEntryDesc': 'Pregledajte i dodajte još agenata', + 'agentTextTranslation': 'Prevod teksta', + 'agentTextTranslationDesc': 'Prevod ukucanog ili nalepljenog teksta', + 'agentPictureTranslation': 'Prevod fotografija', + 'agentPictureTranslationDesc': 'Slikajte ili izaberite fotografiju za prevod', + 'callRequiredTitle': 'Potreban je poziv', + 'callRequiredDesc': 'Ova funkcija radi samo tokom poziva', + 'inCallBusyTitle': 'Nedostupno tokom poziva', + 'inCallBusyDesc': 'Mikrofon i audio putanja su zauzeti pozivom. Pokušajte ponovo nakon završetka poziva.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Besplatno', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/sv_se.dart b/apps/client/lib/core/translations/language/sv_se.dart index 238904bd..f888067e 100644 --- a/apps/client/lib/core/translations/language/sv_se.dart +++ b/apps/client/lib/core/translations/language/sv_se.dart @@ -1908,4 +1908,208 @@ const Map svSE = { 'unmarkFavorite': 'Ta bort från favoriter', 'unnamedDevice': 'Namnlös enhet', 'userDataParseFailed': 'Det gick inte att läsa användardata', + 'catEarphone': 'AI-öronsnäckor', + 'catEarphoneDesc': 'Klassiska Bluetooth- / BLE-öronsnäckor', + 'catPhoneHolder': 'AI-mobilhållare', + 'catPhoneHolderDesc': 'Hållarenheter', + 'catCarAroma': 'AI-bildoft', + 'catCarAromaDesc': 'Aromdiffusor för bil', + 'agreeAndContinue': 'Godkänn och fortsätt', + 'memberServiceAgreement': 'Medlemstjänstavtal', + 'memberServiceAgreementTitle': 'Medlemstjänstavtal', + 'memberServiceAgreementIntro': 'För att ge dig bättre medlemstjänster, läs noga innan du prenumererar: ', + 'memberServiceAgreementOutro': '. Genom att trycka på ”Godkänn och fortsätt” bekräftar du att du har läst och godkänner avtalet ovan.', + 'memberAgreementRejectedTip': 'Du måste godkänna medlemstjänstavtalet för att fortsätta.', + 'translationCallExitTitle': 'Lämna samtalsöversättning', + 'translationCallExitMessage': 'Välj vad som ska hända innan du lämnar', + 'translationCallEnd': 'Avsluta samtalsöversättning', + 'translationContinueInBackground': 'Fortsätt översätta i bakgrunden', + 'backgroundRecordingIndicatorBody': 'Inspelningen fortsätter i bakgrunden. Tryck för att gå tillbaka.', + 'backgroundTranslationIndicatorBody': 'Samtalsöversättningen fortsätter i bakgrunden. Tryck för att gå tillbaka.', + 'meetingRecordScreenCapturePermissionDenied': 'Behörighet för skärminspelning krävs för att spela in systemljud. Ge behörighet och försök igen.', + 'pleaseGrantBluetoothPermission': 'Ge Bluetooth-behörighet för att skanna', + 'startScanFailed': 'Det gick inte att starta skanningen', + 'pleaseLoginFirst': 'Logga in först', + 'deviceUnauthorized': 'Enheten är inte auktoriserad, försök igen', + 'boundDevices': 'Kopplade enheter', + 'currentConnection': 'Aktuell anslutning', + 'binding': 'Kopplar...', + 'permissionDisabled': 'Inaktiverad', + 'confirmDisablePermissionTitle': 'Stäng av behörighet', + 'confirmDisablePermissionContent': 'Stänga av behörigheten {permission}? Du måste gå till systeminställningarna för att aktivera den igen.', + 'confirmPermanentlyDisallowTitle': 'Sluta fråga?', + 'confirmPermanentlyDisallowContent': 'Du nekade behörigheten {permission}. Sluta fråga från och med nu? Om du väljer ”Tillåt inte” kan du fortfarande aktivera den senare i systeminställningarna.', + 'notNow': 'Inte nu', + 'permanentlyDisallow': 'Tillåt inte', + 'otaBesNotSupported': 'Det här headsetet stöder ännu inte firmware-uppgradering i appen. Kontakta supporten.', + 'tabDevice': 'Enheter', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Teknik för ett smartare liv', + 'sloganAi': 'Gränslös intelligens', + 'sloganDevice': 'Smart hårdvara, redo för framtiden', + 'sloganPlaza': 'En smart värld som förstår dig', + 'aiEditHint': 'Håll in ett kort för att dra och ordna om moduler', + 'aiEmptyTitle': 'Inga moduler tillagda ännu', + 'aiEmptyDesc': 'Välj de agenter du behöver i Plaza', + 'goToPlaza': 'Gå till Plaza', + 'plazaOnline': 'Tillgänglig', + 'plazaPlanned': 'Kommer snart', + 'plazaSearchHint': 'Sök efter agenter, t.ex. ”översätt”, ”spela in”', + 'moduleRemove': 'Ta bort', + 'moduleAdd': 'Lägg till', + 'moduleRemoved': 'Borttagen', + 'moduleAdded': 'Tillagd', + 'goSee': 'Visa', + 'comingSoonTag': 'Kommer snart', + 'needDeviceTag': 'Kräver enhet', + 'featureInDev': 'Den här funktionen är under utveckling', + 'featureNotWired': 'Inte tillgänglig ännu', + 'todayLabel': 'Idag', + 'deviceConnected': 'Ansluten', + 'licenseUnknown': 'Licens okänd', + 'selectDevice': 'Välj en enhet', + 'catNoteCard': 'AI-inspelarkort', + 'catNoteCardDesc': 'Kortformad inspelare', + 'catParkerPen': 'AI-penna', + 'catParkerPenDesc': 'Röstinspelningspennor', + 'catStylusPen': 'AI-stylus', + 'catStylusPenDesc': 'Handskrifts-/stylusenheter', + 'catStudyMachine': 'AI-lärplatta', + 'catStudyMachineDesc': 'Lärenheter', + 'besAddTitle': 'Lägg till AI-hörlurar', + 'besConnecting': 'Ansluter till hörlurarna…', + 'besNotFound': 'Hörlurarna hittades inte', + 'besNotFoundIosDesc': 'Anslut hörlurarna i Inställningar → Bluetooth först, och kom sedan tillbaka', + 'besNotFoundAndroidDesc': 'Parkoppla hörlurarna i Inställningar → Bluetooth först, och anslut sedan här', + 'besReadFailed': 'Läsning misslyckades', + 'besConnectFailIos': 'Se till att hörlurarna visas som Ansluten i systemets Bluetooth, och försök igen', + 'besConnectFailAndroid': 'Se till att hörlurarna är på, i närheten och inte anslutna till en annan enhet. De återansluter automatiskt när de är parkopplade.', + 'holderAddTitle': 'Lägg till AI-telefonhållare', + 'holderConnecting': 'Ansluter till enheten…', + 'holderSearching': 'Söker efter enheter…', + 'holderNotFound': 'Inga enheter hittades', + 'holderPairHint': 'Se till att hållaren är på och i parkopplingsläge', + 'holderRetryHint': 'Se till att enheten är på och i närheten, och försök igen', + 'autoConnectTitle': 'Anslut enheter automatiskt', + 'autoConnectDesc': 'Väck appen för att återansluta och ta emot inspelningar när din enhet slås på eller kommer i närheten', + 'autoConnectConsentTitle': 'Aktivera automatisk anslutning', + 'autoConnectConsentIntro': 'För att din enhet (AI-hörlurar / AI-telefonhållare) ska kunna ansluta automatiskt och spara inspelningar när du trycker på dess inspelningsknapp behöver vi ditt samtycke:', + 'autoConnectConsentB1': 'Registrera en Bluetooth-skanning i bakgrunden så att appen väcks (startas automatiskt) när din kopplade enhet upptäcks, för att återansluta och ta emot inspelningar', + 'autoConnectConsentB2': 'När appen väckts används den bara för enhetsanslutning, inspelning och uppladdning — inget annat, och inga andra appar startas', + 'autoConnectConsentB3': 'Du kan fortfarande använda appen utan det — anslut bara enheten manuellt varje gång', + 'autoConnectConsentB4': 'Du kan stänga av det när som helst i Inställningar → Anslut enheter automatiskt', + 'autoConnectAgree': 'Godkänn och aktivera', + 'autoConnectLater': 'Inte nu', + 'autoConnectRequired': 'Automatisk anslutning är av', + 'autoConnectRequiredDesc': 'Aktivera automatisk anslutning för att koppla den här enheten', + 'recordTapToStart': 'Tryck på knappen nedan för att starta inspelningen', + 'recordPaused': 'Pausad', + 'recordMark': 'Markera', + 'recordDeleteTitle': 'Ta bort inspelning', + 'accountAndProfile': 'Konto och profil', + 'nicknameUnset': 'Inget smeknamn angivet', + 'nicknameInput': 'Ange ett smeknamn', + 'loginMethod': 'Inloggningsmetod', + 'manageMyLogin': 'Hantera inloggning', + 'logoutAction': 'Logga ut', + 'warningLabel': 'Varning:', + 'deleteAccountWarn': 'Ditt konto och alla filer raderas permanent.', + 'icpFiling': 'ICP-registrering', + 'logExport': 'Exportera loggar', + 'logExportDesc': 'Visa och exportera appens loggar', + 'permLoadFailed': 'Det gick inte att läsa in behörighetsgrupper', + 'permInsufficient': 'Behörighet nekad', + 'voiceCloneCreating': 'Skapar din röst…', + 'voiceCloneCreate': 'Skapa min röst', + 'voiceCloneAgree': 'Godkänn och läs upp uttalandet högt', + 'voiceCloneReadPrompt': 'Läs upp:', + 'voiceCloneFirstMonthFree': 'Första månaden gratis', + 'voiceCloneEnable': 'Aktivera röstkloning', + 'noMusicPlaying': 'Inget spelas', + 'qqMusicNoSeek': 'Spolning stöds inte för QQ Music', + 'bleScanTitle': 'BLE-skanning', + 'bluetoothOn': 'Bluetooth är på', + 'bleScanning': 'Skannar…', + 'bleConnectedDevices': 'Anslutna enheter', + 'bleUnknownDevice': 'Okänd enhet', + 'bleTapToScan': 'Tryck på skanna för att söka efter BLE-enheter', + 'weekMon': 'Mån', + 'weekTue': 'Tis', + 'weekWed': 'Ons', + 'weekThu': 'Tors', + 'weekFri': 'Fre', + 'weekSat': 'Lör', + 'weekSun': 'Sön', + 'agentMeeting': 'Röstprotokoll', + 'agentMeetingDesc': 'Sammanfatta inspelningar, minnescenter', + 'agentEmai': 'EMAI-assistent', + 'agentEmaiDesc': 'Chatta och fråga vad som helst med rösten', + 'agentSimultaneous': 'Realtidsöversättning', + 'agentSimultaneousDesc': 'Översätt medan du talar', + 'agentFaceToFace': 'Ansikte mot ansikte', + 'agentFaceToFaceDesc': 'Tvåvägs samtalsöversättning', + 'agentCallRecording': 'Samtalsinspelning', + 'agentCallRecordingDesc': 'Samtal sparas automatiskt', + 'agentFieldRecording': 'Fältinspelning', + 'agentFieldRecordingDesc': 'Enhetens eller telefonens mikrofon', + 'agentCall': 'Samtalsöversättning', + 'agentCallDesc': 'Realtidsöversättning under samtal', + 'agentAudioVideo': 'Medieöversättning', + 'agentAudioVideoDesc': 'Kamerainramning / ljud- och videoöversättning', + 'agentEnglishChat': 'Engelsk konversation', + 'agentEnglishChatDesc': 'Uppslukande talträning', + 'agentEnglishStudy': 'Engelskstudier', + 'agentEnglishStudyDesc': 'Ordförråds- och grammatiklektioner', + 'agentKidsStory': 'Barnsagor', + 'agentKidsStoryDesc': 'Godnattsagor och frågor och svar', + 'moduleRemovedDesc': 'borttagen från AI-sidan', + 'moduleAddedDesc': 'tillagd längst ner på AI-sidan', + 'calNoRecords': 'Inga poster', + 'calNoRecordsDay': 'Inget planerat', + 'calTodos': 'Att göra', + 'calExpenses': 'Utgifter', + 'calTodoCount': '@count att göra', + 'calExpenseCount': '@count utgifter', + 'calEntryCount': '@count poster', + 'calItemsUnit': 'st', + 'calCountUnit': 'poster', + 'calTotalAmount': 'Totalt', + 'recordPause': 'Pausa', + 'recordResume': 'Fortsätt', + 'recordDeleteConfirm': 'Ta bort den här inspelningen?', + 'scopeDay': 'Dag', + 'scopeWeek': 'Vecka', + 'scopeMonth': 'Månad', + 'allDay': 'Hela dagen', + 'guestModeTitle': 'Gästläge', + 'guestModeDesc': 'Gäster kan bara titta. Logga in för att använda röstprotokoll, översättning och inspelning — dina data sparas på ditt konto.', + 'guestKeepBrowsing': 'Fortsätt titta', + 'guestGoLogin': 'Logga in', + 'guestViewOnlyTag': 'Endast visning', + 'autoConnectReenableHint': 'Automatisk anslutning är av. Slå på den igen i Inställningar → Anslut enheter automatiskt.', + 'plazaEntryDesc': 'Bläddra och lägg till fler agenter', + 'agentTextTranslation': 'Textöversättning', + 'agentTextTranslationDesc': 'Översätt skriven eller inklistrad text', + 'agentPictureTranslation': 'Bildöversättning', + 'agentPictureTranslationDesc': 'Ta eller välj ett foto att översätta', + 'callRequiredTitle': 'Samtal krävs', + 'callRequiredDesc': 'Den här funktionen fungerar bara under ett samtal', + 'inCallBusyTitle': 'Inte tillgänglig under samtal', + 'inCallBusyDesc': 'Mikrofonen och ljudvägen används av samtalet. Försök igen när du har lagt på.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Gratis', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/th_th.dart b/apps/client/lib/core/translations/language/th_th.dart index d764e72f..9bdd6000 100644 --- a/apps/client/lib/core/translations/language/th_th.dart +++ b/apps/client/lib/core/translations/language/th_th.dart @@ -1861,4 +1861,208 @@ const Map thTH = { 'unmarkFavorite': 'นำออกจากรายการโปรด', 'unnamedDevice': 'อุปกรณ์ที่ไม่มีชื่อ', 'userDataParseFailed': 'อ่านข้อมูลผู้ใช้ไม่สำเร็จ', + 'catEarphone': 'หูฟัง AI', + 'catEarphoneDesc': 'หูฟัง Bluetooth คลาสสิก / BLE', + 'catPhoneHolder': 'ขาตั้งโทรศัพท์ AI', + 'catPhoneHolderDesc': 'อุปกรณ์ประเภทขาตั้ง', + 'catCarAroma': 'เครื่องหอมในรถ AI', + 'catCarAromaDesc': 'เครื่องกระจายกลิ่นในรถ', + 'agreeAndContinue': 'ยอมรับและดำเนินการต่อ', + 'memberServiceAgreement': 'ข้อตกลงการให้บริการสมาชิก', + 'memberServiceAgreementTitle': 'ข้อตกลงการให้บริการสมาชิก', + 'memberServiceAgreementIntro': 'เพื่อให้บริการสมาชิกที่ดียิ่งขึ้น กรุณาอ่านอย่างละเอียดก่อนสมัคร: ', + 'memberServiceAgreementOutro': ' เมื่อแตะ "ยอมรับและดำเนินการต่อ" ถือว่าคุณได้อ่านและยอมรับข้อตกลงข้างต้นครบถ้วนแล้ว', + 'memberAgreementRejectedTip': 'คุณต้องยอมรับข้อตกลงการให้บริการสมาชิกจึงจะดำเนินการต่อได้', + 'translationCallExitTitle': 'ออกจากการแปลการโทร', + 'translationCallExitMessage': 'เลือกสิ่งที่ต้องการทำก่อนออก', + 'translationCallEnd': 'สิ้นสุดการแปลการโทร', + 'translationContinueInBackground': 'แปลต่อในเบื้องหลัง', + 'backgroundRecordingIndicatorBody': 'กำลังบันทึกต่อในเบื้องหลัง แตะเพื่อกลับ', + 'backgroundTranslationIndicatorBody': 'กำลังแปลการโทรต่อในเบื้องหลัง แตะเพื่อกลับ', + 'meetingRecordScreenCapturePermissionDenied': 'ต้องได้รับสิทธิ์บันทึกหน้าจอเพื่อบันทึกเสียงของระบบ กรุณาอนุญาตแล้วลองใหม่', + 'pleaseGrantBluetoothPermission': 'กรุณาอนุญาตสิทธิ์บลูทูธเพื่อสแกน', + 'startScanFailed': 'เริ่มสแกนไม่สำเร็จ', + 'pleaseLoginFirst': 'กรุณาเข้าสู่ระบบก่อน', + 'deviceUnauthorized': 'อุปกรณ์ไม่ได้รับอนุญาต กรุณาลองใหม่', + 'boundDevices': 'อุปกรณ์ที่ผูกไว้', + 'currentConnection': 'การเชื่อมต่อปัจจุบัน', + 'binding': 'กำลังผูกอุปกรณ์...', + 'permissionDisabled': 'ปิดอยู่', + 'confirmDisablePermissionTitle': 'ปิดสิทธิ์', + 'confirmDisablePermissionContent': 'ปิดสิทธิ์ {permission} หรือไม่? คุณจะต้องไปเปิดใหม่ในการตั้งค่าระบบ', + 'confirmPermanentlyDisallowTitle': 'ไม่ถามอีก?', + 'confirmPermanentlyDisallowContent': 'คุณปฏิเสธสิทธิ์ {permission} ต้องการให้ไม่ถามอีกหรือไม่? หากเลือก "ไม่อนุญาต" คุณยังเปิดได้ภายหลังในการตั้งค่าระบบ', + 'notNow': 'ไว้ทีหลัง', + 'permanentlyDisallow': 'ไม่อนุญาต', + 'otaBesNotSupported': 'หูฟังนี้ยังไม่รองรับการอัปเกรดเฟิร์มแวร์ในแอป กรุณาติดต่อฝ่ายสนับสนุน', + 'tabDevice': 'อุปกรณ์', + 'tabPlaza': 'พลาซ่า', + 'sloganHome': 'เทคโนโลยีเพื่อชีวิตที่ฉลาดขึ้น', + 'sloganAi': 'ความอัจฉริยะไร้ขีดจำกัด', + 'sloganDevice': 'ฮาร์ดแวร์อัจฉริยะ พร้อมสู่อนาคต', + 'sloganPlaza': 'โลกอัจฉริยะที่เข้าใจคุณ', + 'aiEditHint': 'กดค้างที่การ์ดเพื่อลากจัดเรียงโมดูล', + 'aiEmptyTitle': 'ยังไม่ได้เพิ่มโมดูล', + 'aiEmptyDesc': 'เลือกเอเจนต์ที่คุณต้องการได้ในพลาซ่า', + 'goToPlaza': 'ไปที่พลาซ่า', + 'plazaOnline': 'ใช้งานได้', + 'plazaPlanned': 'เร็วๆ นี้', + 'plazaSearchHint': 'ค้นหาเอเจนต์ เช่น “แปล”, “บันทึก”', + 'moduleRemove': 'นำออก', + 'moduleAdd': 'เพิ่ม', + 'moduleRemoved': 'นำออกแล้ว', + 'moduleAdded': 'เพิ่มแล้ว', + 'goSee': 'ดู', + 'comingSoonTag': 'เร็วๆ นี้', + 'needDeviceTag': 'ต้องใช้อุปกรณ์', + 'featureInDev': 'ฟีเจอร์นี้อยู่ระหว่างการพัฒนา', + 'featureNotWired': 'ยังไม่พร้อมใช้งาน', + 'todayLabel': 'วันนี้', + 'deviceConnected': 'เชื่อมต่อแล้ว', + 'licenseUnknown': 'ไม่ทราบสถานะสิทธิ์การใช้งาน', + 'selectDevice': 'เลือกอุปกรณ์', + 'catNoteCard': 'การ์ดบันทึกเสียง AI', + 'catNoteCardDesc': 'เครื่องบันทึกเสียงทรงการ์ด', + 'catParkerPen': 'ปากกา AI', + 'catParkerPenDesc': 'ปากกาบันทึกเสียง', + 'catStylusPen': 'สไตลัส AI', + 'catStylusPenDesc': 'อุปกรณ์เขียนด้วยลายมือ / สไตลัส', + 'catStudyMachine': 'แท็บเล็ตการเรียนรู้ AI', + 'catStudyMachineDesc': 'อุปกรณ์เพื่อการเรียนรู้', + 'besAddTitle': 'เพิ่มหูฟัง AI', + 'besConnecting': 'กำลังเชื่อมต่อหูฟัง…', + 'besNotFound': 'ไม่พบหูฟัง', + 'besNotFoundIosDesc': 'กรุณาเชื่อมต่อหูฟังใน การตั้งค่า → บลูทูธ ก่อน แล้วกลับมาที่นี่', + 'besNotFoundAndroidDesc': 'กรุณาจับคู่หูฟังใน การตั้งค่า → บลูทูธ ก่อน แล้วมาเชื่อมต่อที่นี่', + 'besReadFailed': 'อ่านข้อมูลไม่สำเร็จ', + 'besConnectFailIos': 'ตรวจสอบว่าหูฟังแสดงสถานะ "เชื่อมต่อแล้ว" ในบลูทูธของระบบ แล้วลองใหม่', + 'besConnectFailAndroid': 'ตรวจสอบว่าหูฟังเปิดอยู่ อยู่ใกล้ๆ และไม่ได้เชื่อมต่อกับอุปกรณ์อื่น เมื่อเชื่อมต่อแล้วจะเชื่อมต่อใหม่โดยอัตโนมัติ', + 'holderAddTitle': 'เพิ่มขาตั้งโทรศัพท์ AI', + 'holderConnecting': 'กำลังเชื่อมต่ออุปกรณ์…', + 'holderSearching': 'กำลังค้นหาอุปกรณ์…', + 'holderNotFound': 'ไม่พบอุปกรณ์', + 'holderPairHint': 'ตรวจสอบว่าขาตั้งเปิดอยู่และอยู่ในโหมดจับคู่', + 'holderRetryHint': 'ตรวจสอบว่าอุปกรณ์เปิดอยู่และอยู่ใกล้ๆ แล้วลองใหม่', + 'autoConnectTitle': 'เชื่อมต่ออุปกรณ์อัตโนมัติ', + 'autoConnectDesc': 'ปลุกแอปเพื่อเชื่อมต่อใหม่และรับการบันทึกเมื่ออุปกรณ์เปิดเครื่องหรืออยู่ใกล้', + 'autoConnectConsentTitle': 'เปิดการเชื่อมต่ออัตโนมัติ', + 'autoConnectConsentIntro': 'เพื่อให้อุปกรณ์ของคุณ (หูฟัง AI / ขาตั้งโทรศัพท์ AI) เชื่อมต่อโดยอัตโนมัติและบันทึกเสียงเมื่อคุณกดปุ่มบันทึกบนอุปกรณ์ เราต้องขอความยินยอมจากคุณ:', + 'autoConnectConsentB1': 'ลงทะเบียนการสแกนบลูทูธในเบื้องหลัง เพื่อให้แอปถูกปลุก (เริ่มทำงานอัตโนมัติ) เมื่อตรวจพบอุปกรณ์ที่ผูกไว้ สำหรับเชื่อมต่อใหม่และรับการบันทึก', + 'autoConnectConsentB2': 'เมื่อถูกปลุกแล้ว จะใช้เพื่อเชื่อมต่ออุปกรณ์ บันทึกเสียง และอัปโหลดเท่านั้น ไม่ทำอย่างอื่น และไม่เปิดแอปอื่น', + 'autoConnectConsentB3': 'คุณยังใช้แอปได้โดยไม่เปิดฟีเจอร์นี้ เพียงเชื่อมต่ออุปกรณ์ด้วยตนเองทุกครั้ง', + 'autoConnectConsentB4': 'คุณปิดได้ทุกเมื่อใน การตั้งค่า → เชื่อมต่ออุปกรณ์อัตโนมัติ', + 'autoConnectAgree': 'ยอมรับและเปิดใช้', + 'autoConnectLater': 'ไว้ทีหลัง', + 'autoConnectRequired': 'การเชื่อมต่ออัตโนมัติปิดอยู่', + 'autoConnectRequiredDesc': 'เปิดการเชื่อมต่ออัตโนมัติเพื่อผูกอุปกรณ์นี้', + 'recordTapToStart': 'แตะปุ่มด้านล่างเพื่อเริ่มบันทึก', + 'recordPaused': 'หยุดชั่วคราว', + 'recordMark': 'ทำเครื่องหมาย', + 'recordDeleteTitle': 'ลบการบันทึก', + 'accountAndProfile': 'บัญชีและโปรไฟล์', + 'nicknameUnset': 'ยังไม่ได้ตั้งชื่อเล่น', + 'nicknameInput': 'กรอกชื่อเล่น', + 'loginMethod': 'วิธีเข้าสู่ระบบ', + 'manageMyLogin': 'จัดการการเข้าสู่ระบบ', + 'logoutAction': 'ออกจากระบบ', + 'warningLabel': 'คำเตือน:', + 'deleteAccountWarn': 'บัญชีและไฟล์ทั้งหมดของคุณจะถูกลบอย่างถาวร', + 'icpFiling': 'การจดทะเบียน ICP', + 'logExport': 'ส่งออกบันทึกระบบ', + 'logExportDesc': 'ดูและส่งออกบันทึกระบบของแอป', + 'permLoadFailed': 'โหลดกลุ่มสิทธิ์ไม่สำเร็จ', + 'permInsufficient': 'ไม่ได้รับสิทธิ์', + 'voiceCloneCreating': 'กำลังสร้างเสียงของคุณ…', + 'voiceCloneCreate': 'สร้างเสียงของฉัน', + 'voiceCloneAgree': 'ยอมรับและอ่านข้อความออกเสียง', + 'voiceCloneReadPrompt': 'กรุณาอ่าน:', + 'voiceCloneFirstMonthFree': 'ฟรีเดือนแรก', + 'voiceCloneEnable': 'เปิดใช้การโคลนเสียง', + 'noMusicPlaying': 'ไม่มีเพลงที่กำลังเล่น', + 'qqMusicNoSeek': 'QQ Music ไม่รองรับการเลื่อนตำแหน่งเล่น', + 'bleScanTitle': 'สแกน BLE', + 'bluetoothOn': 'บลูทูธเปิดอยู่', + 'bleScanning': 'กำลังสแกน…', + 'bleConnectedDevices': 'อุปกรณ์ที่เชื่อมต่อแล้ว', + 'bleUnknownDevice': 'อุปกรณ์ที่ไม่รู้จัก', + 'bleTapToScan': 'แตะสแกนเพื่อค้นหาอุปกรณ์ BLE', + 'weekMon': 'จ.', + 'weekTue': 'อ.', + 'weekWed': 'พ.', + 'weekThu': 'พฤ.', + 'weekFri': 'ศ.', + 'weekSat': 'ส.', + 'weekSun': 'อา.', + 'agentMeeting': 'บันทึกเสียงสรุป', + 'agentMeetingDesc': 'สรุปการบันทึกเสียง ศูนย์รวมความจำ', + 'agentEmai': 'ผู้ช่วย EMAI', + 'agentEmaiDesc': 'พูดคุยและถามได้ทุกเรื่องด้วยเสียง', + 'agentSimultaneous': 'แปลสด', + 'agentSimultaneousDesc': 'แปลทันทีขณะที่คุณพูด', + 'agentFaceToFace': 'แปลแบบเห็นหน้า', + 'agentFaceToFaceDesc': 'แปลบทสนทนาสองทาง', + 'agentCallRecording': 'บันทึกการโทร', + 'agentCallRecordingDesc': 'บันทึกสายโทรอัตโนมัติ', + 'agentFieldRecording': 'บันทึกเสียงภาคสนาม', + 'agentFieldRecordingDesc': 'ผ่านอุปกรณ์หรือไมโครโฟนโทรศัพท์', + 'agentCall': 'แปลการโทร', + 'agentCallDesc': 'แปลแบบเรียลไทม์ระหว่างโทร', + 'agentAudioVideo': 'แปลสื่อ', + 'agentAudioVideoDesc': 'จัดเฟรมกล้อง / แปลเสียงและวิดีโอ', + 'agentEnglishChat': 'สนทนาภาษาอังกฤษ', + 'agentEnglishChatDesc': 'ฝึกพูดแบบเสมือนจริง', + 'agentEnglishStudy': 'เรียนภาษาอังกฤษ', + 'agentEnglishStudyDesc': 'บทเรียนคำศัพท์และไวยากรณ์', + 'agentKidsStory': 'นิทานเด็ก', + 'agentKidsStoryDesc': 'นิทานก่อนนอนและถาม-ตอบ', + 'moduleRemovedDesc': 'ถูกนำออกจากหน้า AI แล้ว', + 'moduleAddedDesc': 'ถูกเพิ่มไว้ท้ายหน้า AI แล้ว', + 'calNoRecords': 'ไม่มีรายการ', + 'calNoRecordsDay': 'ไม่มีกำหนดการ', + 'calTodos': 'สิ่งที่ต้องทำ', + 'calExpenses': 'ค่าใช้จ่าย', + 'calTodoCount': 'สิ่งที่ต้องทำ @count รายการ', + 'calExpenseCount': 'ค่าใช้จ่าย @count รายการ', + 'calEntryCount': '@count รายการ', + 'calItemsUnit': 'รายการ', + 'calCountUnit': 'รายการ', + 'calTotalAmount': 'รวม', + 'recordPause': 'หยุดชั่วคราว', + 'recordResume': 'บันทึกต่อ', + 'recordDeleteConfirm': 'ลบการบันทึกนี้หรือไม่?', + 'scopeDay': 'วัน', + 'scopeWeek': 'สัปดาห์', + 'scopeMonth': 'เดือน', + 'allDay': 'ทั้งวัน', + 'guestModeTitle': 'โหมดผู้เยี่ยมชม', + 'guestModeDesc': 'ผู้เยี่ยมชมดูได้อย่างเดียว เข้าสู่ระบบเพื่อใช้บันทึกเสียงสรุป การแปล และการบันทึก ข้อมูลของคุณจะถูกบันทึกไว้ในบัญชี', + 'guestKeepBrowsing': 'ดูต่อ', + 'guestGoLogin': 'เข้าสู่ระบบ', + 'guestViewOnlyTag': 'ดูได้อย่างเดียว', + 'autoConnectReenableHint': 'การเชื่อมต่ออัตโนมัติปิดอยู่ เปิดใหม่ได้ใน การตั้งค่า → เชื่อมต่ออุปกรณ์อัตโนมัติ', + 'plazaEntryDesc': 'สำรวจและเพิ่มเอเจนต์เพิ่มเติม', + 'agentTextTranslation': 'แปลข้อความ', + 'agentTextTranslationDesc': 'แปลข้อความที่พิมพ์หรือวาง', + 'agentPictureTranslation': 'แปลรูปภาพ', + 'agentPictureTranslationDesc': 'ถ่ายหรือเลือกรูปเพื่อแปล', + 'callRequiredTitle': 'ต้องอยู่ระหว่างการโทร', + 'callRequiredDesc': 'ฟีเจอร์นี้ใช้ได้เฉพาะระหว่างการโทรเท่านั้น', + 'inCallBusyTitle': 'ใช้งานไม่ได้ระหว่างการโทร', + 'inCallBusyDesc': 'ไมโครโฟนและเส้นทางเสียงกำลังถูกใช้โดยการโทร กรุณาลองใหม่หลังวางสาย', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'ฟรี', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/tl_ph.dart b/apps/client/lib/core/translations/language/tl_ph.dart index 97759c0b..4f1d504b 100644 --- a/apps/client/lib/core/translations/language/tl_ph.dart +++ b/apps/client/lib/core/translations/language/tl_ph.dart @@ -1946,4 +1946,208 @@ const Map tlPH = { 'unmarkFavorite': 'Alisin sa mga paborito', 'unnamedDevice': 'Device na walang pangalan', 'userDataParseFailed': 'Nabigong basahin ang data ng user', + 'catEarphone': 'AI Earbuds', + 'catEarphoneDesc': 'Classic Bluetooth / BLE earbuds', + 'catPhoneHolder': 'AI Phone Stand', + 'catPhoneHolderDesc': 'Mga stand device', + 'catCarAroma': 'AI Car Diffuser', + 'catCarAromaDesc': 'Pang-kotseng aroma diffuser', + 'agreeAndContinue': 'Sumang-ayon at Magpatuloy', + 'memberServiceAgreement': 'Kasunduan sa Serbisyo ng Membership', + 'memberServiceAgreementTitle': 'Kasunduan sa Serbisyo ng Membership', + 'memberServiceAgreementIntro': 'Para mabigyan ka ng mas mahusay na serbisyo ng membership, pakibasa nang mabuti bago mag-subscribe: ', + 'memberServiceAgreementOutro': '. Sa pag-tap sa "Sumang-ayon at Magpatuloy", kinukumpirma mong nabasa mo nang buo at tinatanggap ang kasunduan sa itaas.', + 'memberAgreementRejectedTip': 'Kailangan mong sumang-ayon sa Kasunduan sa Serbisyo ng Membership para magpatuloy.', + 'translationCallExitTitle': 'Umalis sa Pagsasalin ng Tawag', + 'translationCallExitMessage': 'Piliin ang gagawin bago umalis', + 'translationCallEnd': 'Tapusin ang pagsasalin ng tawag', + 'translationContinueInBackground': 'Ipagpatuloy ang pagsasalin sa background', + 'backgroundRecordingIndicatorBody': 'Nagpapatuloy ang pag-record sa background. I-tap para bumalik.', + 'backgroundTranslationIndicatorBody': 'Nagpapatuloy ang pagsasalin ng tawag sa background. I-tap para bumalik.', + 'meetingRecordScreenCapturePermissionDenied': 'Kailangan ng pahintulot sa screen recording para ma-record ang audio ng system. Pakibigay ito at subukang muli.', + 'pleaseGrantBluetoothPermission': 'Pakibigay ang pahintulot sa Bluetooth para mag-scan', + 'startScanFailed': 'Nabigong simulan ang pag-scan', + 'pleaseLoginFirst': 'Mag-login muna', + 'deviceUnauthorized': 'Hindi awtorisado ang device, pakisubukang muli', + 'boundDevices': 'Mga Naka-bind na Device', + 'currentConnection': 'Kasalukuyang Koneksyon', + 'binding': 'Nagbi-bind...', + 'permissionDisabled': 'Naka-off', + 'confirmDisablePermissionTitle': 'I-off ang pahintulot', + 'confirmDisablePermissionContent': 'I-off ang pahintulot sa {permission}? Kailangan mong pumunta sa mga setting ng system para i-enable itong muli.', + 'confirmPermanentlyDisallowTitle': 'Huwag nang magtanong?', + 'confirmPermanentlyDisallowContent': 'Tinanggihan mo ang pahintulot sa {permission}. Huwag nang magtanong mula ngayon? Kung pipiliin mo ang "Huwag payagan", maaari mo pa rin itong i-enable sa mga setting ng system.', + 'notNow': 'Hindi ngayon', + 'permanentlyDisallow': 'Huwag payagan', + 'otaBesNotSupported': 'Hindi pa sinusuportahan ng headset na ito ang in-app na pag-upgrade ng firmware. Makipag-ugnayan sa support.', + 'tabDevice': 'Mga Device', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Teknolohiya para sa mas matalinong buhay', + 'sloganAi': 'Walang hangganang talino', + 'sloganDevice': 'Matalinong hardware, handa sa hinaharap', + 'sloganPlaza': 'Matalinong mundong nakakaintindi sa iyo', + 'aiEditHint': 'Pindutin nang matagal ang card para i-drag at ayusin ang mga module', + 'aiEmptyTitle': 'Wala pang naidadagdag na module', + 'aiEmptyDesc': 'Piliin ang mga agent na kailangan mo sa Plaza', + 'goToPlaza': 'Pumunta sa Plaza', + 'plazaOnline': 'Available', + 'plazaPlanned': 'Malapit na', + 'plazaSearchHint': 'Maghanap ng agent, hal. “isalin”, “i-record”', + 'moduleRemove': 'Alisin', + 'moduleAdd': 'Idagdag', + 'moduleRemoved': 'Inalis', + 'moduleAdded': 'Naidagdag', + 'goSee': 'Tingnan', + 'comingSoonTag': 'Malapit na', + 'needDeviceTag': 'Kailangan ng device', + 'featureInDev': 'Ginagawa pa ang feature na ito', + 'featureNotWired': 'Hindi pa available', + 'todayLabel': 'Ngayon', + 'deviceConnected': 'Konektado', + 'licenseUnknown': 'Hindi alam ang lisensya', + 'selectDevice': 'Pumili ng device', + 'catNoteCard': 'AI Recorder Card', + 'catNoteCardDesc': 'Recorder na hugis card', + 'catParkerPen': 'AI Pen', + 'catParkerPenDesc': 'Mga voice recorder pen', + 'catStylusPen': 'AI Stylus', + 'catStylusPenDesc': 'Mga device para sa sulat-kamay / stylus', + 'catStudyMachine': 'AI Learning Pad', + 'catStudyMachineDesc': 'Mga device para sa pag-aaral', + 'besAddTitle': 'Magdagdag ng AI Earbuds', + 'besConnecting': 'Kumokonekta sa earbuds…', + 'besNotFound': 'Hindi natagpuan ang earbuds', + 'besNotFoundIosDesc': 'Ikonekta muna ang earbuds sa Settings → Bluetooth, pagkatapos ay bumalik dito', + 'besNotFoundAndroidDesc': 'I-pair muna ang earbuds sa Settings → Bluetooth, pagkatapos ay kumonekta dito', + 'besReadFailed': 'Nabigo ang pagbasa', + 'besConnectFailIos': 'Siguraduhing nakalagay na Connected ang earbuds sa Bluetooth ng system, pagkatapos ay subukang muli', + 'besConnectFailAndroid': 'Siguraduhing naka-on ang earbuds, malapit, at hindi konektado sa ibang device. Awtomatiko itong muling kokonekta kapag na-link na.', + 'holderAddTitle': 'Magdagdag ng AI Phone Stand', + 'holderConnecting': 'Kumokonekta sa device…', + 'holderSearching': 'Naghahanap ng mga device…', + 'holderNotFound': 'Walang natagpuang device', + 'holderPairHint': 'Siguraduhing naka-on ang stand at nasa pairing mode', + 'holderRetryHint': 'Siguraduhing naka-on at malapit ang device, pagkatapos ay subukang muli', + 'autoConnectTitle': 'Auto-connect ng mga device', + 'autoConnectDesc': 'Gisingin ang app para muling kumonekta at tumanggap ng mga recording kapag naka-on o malapit ang iyong device', + 'autoConnectConsentTitle': 'I-enable ang auto-connect', + 'autoConnectConsentIntro': 'Para awtomatikong kumonekta ang iyong device (AI Earbuds / AI Phone Stand) at ma-save ang mga recording kapag pinindot mo ang record button nito, kailangan namin ang iyong pahintulot:', + 'autoConnectConsentB1': 'Magrehistro ng background Bluetooth scan para magising (awtomatikong masimulan) ang app kapag na-detect ang iyong naka-bind na device, para muling kumonekta at tumanggap ng mga recording', + 'autoConnectConsentB2': 'Kapag nagising, gagamitin lang ito para sa koneksyon ng device, pag-record at pag-upload — wala nang iba, at walang ibang app na bubuksan', + 'autoConnectConsentB3': 'Magagamit mo pa rin ang app kahit wala ito — ikonekta na lang nang manu-mano ang device sa bawat pagkakataon', + 'autoConnectConsentB4': 'Maaari mo itong i-off anumang oras sa Settings → Auto-connect ng mga device', + 'autoConnectAgree': 'Sumang-ayon at i-enable', + 'autoConnectLater': 'Hindi ngayon', + 'autoConnectRequired': 'Naka-off ang auto-connect', + 'autoConnectRequiredDesc': 'I-enable ang auto-connect para i-bind ang device na ito', + 'recordTapToStart': 'I-tap ang button sa ibaba para simulan ang pag-record', + 'recordPaused': 'Naka-pause', + 'recordMark': 'Markahan', + 'recordDeleteTitle': 'Burahin ang recording', + 'accountAndProfile': 'Account at profile', + 'nicknameUnset': 'Walang nakatakdang nickname', + 'nicknameInput': 'Maglagay ng nickname', + 'loginMethod': 'Paraan ng pag-login', + 'manageMyLogin': 'Pamahalaan ang pag-login', + 'logoutAction': 'Mag-logout', + 'warningLabel': 'Babala:', + 'deleteAccountWarn': 'Permanenteng mabubura ang iyong account at lahat ng file.', + 'icpFiling': 'ICP filing', + 'logExport': 'I-export ang mga log', + 'logExportDesc': 'Tingnan at i-export ang mga log ng app', + 'permLoadFailed': 'Nabigong i-load ang mga grupo ng pahintulot', + 'permInsufficient': 'Tinanggihan ang pahintulot', + 'voiceCloneCreating': 'Ginagawa ang iyong boses…', + 'voiceCloneCreate': 'Gawin ang aking boses', + 'voiceCloneAgree': 'Sumang-ayon at basahin nang malakas ang pahayag', + 'voiceCloneReadPrompt': 'Pakibasa:', + 'voiceCloneFirstMonthFree': 'Libre ang unang buwan', + 'voiceCloneEnable': 'I-enable ang pag-clone ng boses', + 'noMusicPlaying': 'Walang tumutugtog', + 'qqMusicNoSeek': 'Hindi suportado ang pag-seek para sa QQ Music', + 'bleScanTitle': 'BLE scan', + 'bluetoothOn': 'Naka-on ang Bluetooth', + 'bleScanning': 'Nag-i-scan…', + 'bleConnectedDevices': 'Mga konektadong device', + 'bleUnknownDevice': 'Hindi kilalang device', + 'bleTapToScan': 'I-tap ang scan para maghanap ng mga BLE device', + 'weekMon': 'Lun', + 'weekTue': 'Mar', + 'weekWed': 'Miy', + 'weekThu': 'Huw', + 'weekFri': 'Biy', + 'weekSat': 'Sab', + 'weekSun': 'Lin', + 'agentMeeting': 'Voice Minutes', + 'agentMeetingDesc': 'Buod ng mga recording, memory hub', + 'agentEmai': 'EMAI Assistant', + 'agentEmaiDesc': 'Makipag-chat at magtanong ng kahit ano gamit ang boses', + 'agentSimultaneous': 'Live na Pagsasalin', + 'agentSimultaneousDesc': 'Isinasalin habang nagsasalita ka', + 'agentFaceToFace': 'Harapan', + 'agentFaceToFaceDesc': 'Two-way na pagsasalin ng usapan', + 'agentCallRecording': 'Pag-record ng Tawag', + 'agentCallRecordingDesc': 'Awtomatikong nase-save ang mga tawag', + 'agentFieldRecording': 'Field Recording', + 'agentFieldRecordingDesc': 'Mikropono ng device o telepono', + 'agentCall': 'Pagsasalin ng Tawag', + 'agentCallDesc': 'Real-time na pagsasalin habang tumatawag', + 'agentAudioVideo': 'Pagsasalin ng Media', + 'agentAudioVideoDesc': 'Camera framing / pagsasalin ng audio at video', + 'agentEnglishChat': 'English Chat', + 'agentEnglishChatDesc': 'Immersive na pagsasanay sa pagsasalita', + 'agentEnglishStudy': 'Pag-aaral ng English', + 'agentEnglishStudyDesc': 'Mga aralin sa bokabularyo at grammar', + 'agentKidsStory': 'Mga Kuwentong Pambata', + 'agentKidsStoryDesc': 'Mga kuwento bago matulog at Q&A', + 'moduleRemovedDesc': 'inalis sa AI page', + 'moduleAddedDesc': 'idinagdag sa ibaba ng AI page', + 'calNoRecords': 'Walang entry', + 'calNoRecordsDay': 'Walang nakaiskedyul', + 'calTodos': 'Mga gagawin', + 'calExpenses': 'Gastos', + 'calTodoCount': '@count gagawin', + 'calExpenseCount': '@count gastos', + 'calEntryCount': '@count entry', + 'calItemsUnit': 'item', + 'calCountUnit': 'entry', + 'calTotalAmount': 'Kabuuan', + 'recordPause': 'I-pause', + 'recordResume': 'Ipagpatuloy', + 'recordDeleteConfirm': 'Burahin ang recording na ito?', + 'scopeDay': 'Araw', + 'scopeWeek': 'Linggo', + 'scopeMonth': 'Buwan', + 'allDay': 'Buong araw', + 'guestModeTitle': 'Guest mode', + 'guestModeDesc': 'Ang mga guest ay maaari lamang mag-browse. Mag-login para gamitin ang voice notes, pagsasalin at pag-record — mase-save ang iyong data sa iyong account.', + 'guestKeepBrowsing': 'Magpatuloy sa pag-browse', + 'guestGoLogin': 'Mag-login', + 'guestViewOnlyTag': 'Tingnan lamang', + 'autoConnectReenableHint': 'Naka-off ang auto-connect. I-on itong muli sa Settings → Auto-connect ng mga device.', + 'plazaEntryDesc': 'Mag-browse at magdagdag ng higit pang agent', + 'agentTextTranslation': 'Pagsasalin ng Teksto', + 'agentTextTranslationDesc': 'Isalin ang na-type o na-paste na teksto', + 'agentPictureTranslation': 'Pagsasalin ng Larawan', + 'agentPictureTranslationDesc': 'Kumuha o pumili ng larawan para isalin', + 'callRequiredTitle': 'Kailangan ng tawag', + 'callRequiredDesc': 'Gumagana lang ang feature na ito habang may tawag', + 'inCallBusyTitle': 'Hindi available habang may tawag', + 'inCallBusyDesc': 'Ginagamit ng tawag ang mikropono at audio path. Subukang muli pagkatapos ibaba ang tawag.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Libre', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/tr_tr.dart b/apps/client/lib/core/translations/language/tr_tr.dart index 294884b4..abea3bfd 100644 --- a/apps/client/lib/core/translations/language/tr_tr.dart +++ b/apps/client/lib/core/translations/language/tr_tr.dart @@ -1900,4 +1900,210 @@ const Map trTR = { 'unmarkFavorite': 'Favorilerden çıkar', 'unnamedDevice': 'Adsız cihaz', 'userDataParseFailed': 'Kullanıcı verileri işlenemedi', + 'catEarphone': 'AI Kulaklık', + 'catEarphoneDesc': 'Klasik Bluetooth / BLE kulaklık', + 'catPhoneHolder': 'AI Telefon Tutucu', + 'catPhoneHolderDesc': 'Tutucu cihazlar', + 'catCarAroma': 'AI Araç Kokusu', + 'catCarAromaDesc': 'Araç içi koku difüzörü', + 'agreeAndContinue': 'Kabul et ve devam et', + 'memberServiceAgreement': 'Üyelik Hizmet Sözleşmesi', + 'memberServiceAgreementTitle': 'Üyelik Hizmet Sözleşmesi', + 'memberServiceAgreementIntro': 'Size daha iyi üyelik hizmetleri sunabilmemiz için lütfen abone olmadan önce dikkatlice okuyun: ', + 'memberServiceAgreementOutro': '. "Kabul et ve devam et"e dokunarak yukarıdaki sözleşmeyi tamamen okuduğunuzu ve kabul ettiğinizi onaylarsınız.', + 'memberAgreementRejectedTip': 'Devam etmek için Üyelik Hizmet Sözleşmesi\'ni kabul etmelisiniz.', + 'translationCallExitTitle': 'Arama Çevirisinden Çık', + 'translationCallExitMessage': 'Ayrılmadan önce ne yapılacağını seçin', + 'translationCallEnd': 'Arama çevirisini bitir', + 'translationContinueInBackground': 'Arka planda çeviriye devam et', + 'backgroundRecordingIndicatorBody': 'Kayıt arka planda devam ediyor. Geri dönmek için dokunun.', + 'backgroundTranslationIndicatorBody': 'Arama çevirisi arka planda devam ediyor. Geri dönmek için dokunun.', + 'meetingRecordScreenCapturePermissionDenied': 'Sistem sesini kaydetmek için ekran kaydı izni gerekir. Lütfen izin verip tekrar deneyin.', + 'pleaseGrantBluetoothPermission': 'Tarama için lütfen Bluetooth izni verin', + 'startScanFailed': 'Tarama başlatılamadı', + 'pleaseLoginFirst': 'Lütfen önce giriş yapın', + 'deviceUnauthorized': 'Cihaz yetkili değil, lütfen tekrar deneyin', + 'boundDevices': 'Bağlı Cihazlar', + 'currentConnection': 'Mevcut Bağlantı', + 'binding': 'Bağlanıyor...', + 'permissionDisabled': 'Kapalı', + 'confirmDisablePermissionTitle': 'İzni kapat', + 'confirmDisablePermissionContent': '{permission} izni kapatılsın mı? Yeniden etkinleştirmek için sistem ayarlarına gitmeniz gerekecek.', + 'confirmPermanentlyDisallowTitle': 'Bir daha sorulmasın mı?', + 'confirmPermanentlyDisallowContent': '{permission} iznini reddettiniz. Bundan sonra sorulmasın mı? "İzin verme"yi seçerseniz daha sonra sistem ayarlarından yine etkinleştirebilirsiniz.', + 'notNow': 'Şimdi değil', + 'permanentlyDisallow': 'İzin verme', + 'otaUpgradeStarted': 'OTA güncellemesi başladı...', + 'otaUpgradeProgressWithPercent': 'Güncelleme ilerlemesi: @percent%', + 'otaBesNotSupported': 'Bu kulaklık henüz uygulama içi donanım yazılımı güncellemesini desteklemiyor. Lütfen destek ile iletişime geçin.', + 'tabDevice': 'Cihazlar', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Daha akıllı bir yaşam için teknoloji', + 'sloganAi': 'Sınırsız zekâ', + 'sloganDevice': 'Akıllı donanım, geleceğe hazır', + 'sloganPlaza': 'Sizi anlayan akıllı bir dünya', + 'aiEditHint': 'Modülleri sürükleyip yeniden sıralamak için bir karta uzun basın', + 'aiEmptyTitle': 'Henüz modül eklenmedi', + 'aiEmptyDesc': 'İhtiyacınız olan ajanları Plaza\'dan seçin', + 'goToPlaza': 'Plaza\'ya git', + 'plazaOnline': 'Kullanılabilir', + 'plazaPlanned': 'Çok yakında', + 'plazaSearchHint': 'Ajan ara, örn. “çeviri”, “kayıt”', + 'moduleRemove': 'Kaldır', + 'moduleAdd': 'Ekle', + 'moduleRemoved': 'Kaldırıldı', + 'moduleAdded': 'Eklendi', + 'goSee': 'Görüntüle', + 'comingSoonTag': 'Çok yakında', + 'needDeviceTag': 'Cihaz gerekli', + 'featureInDev': 'Bu özellik geliştirme aşamasında', + 'featureNotWired': 'Henüz kullanılamıyor', + 'todayLabel': 'Bugün', + 'deviceConnected': 'Bağlandı', + 'licenseUnknown': 'Lisans bilinmiyor', + 'selectDevice': 'Bir cihaz seçin', + 'catNoteCard': 'AI Kayıt Kartı', + 'catNoteCardDesc': 'Kart şeklinde kayıt cihazı', + 'catParkerPen': 'AI Kalem', + 'catParkerPenDesc': 'Ses kayıt kalemleri', + 'catStylusPen': 'AI Stylus', + 'catStylusPenDesc': 'El yazısı / stylus cihazları', + 'catStudyMachine': 'AI Öğrenme Tableti', + 'catStudyMachineDesc': 'Öğrenme cihazları', + 'besAddTitle': 'AI Kulaklık Ekle', + 'besConnecting': 'Kulaklığa bağlanılıyor…', + 'besNotFound': 'Kulaklık bulunamadı', + 'besNotFoundIosDesc': 'Önce Ayarlar → Bluetooth\'tan kulaklığı bağlayın, sonra buraya dönün', + 'besNotFoundAndroidDesc': 'Önce Ayarlar → Bluetooth\'tan kulaklığı eşleştirin, sonra buradan bağlanın', + 'besReadFailed': 'Okuma başarısız', + 'besConnectFailIos': 'Kulaklığın sistem Bluetooth\'unda Bağlı olarak göründüğünden emin olup tekrar deneyin', + 'besConnectFailAndroid': 'Kulaklığın açık, yakında ve başka bir cihaza bağlı olmadığından emin olun. Bağlandıktan sonra otomatik olarak yeniden bağlanacaktır.', + 'holderAddTitle': 'AI Telefon Tutucu Ekle', + 'holderConnecting': 'Cihaza bağlanılıyor…', + 'holderSearching': 'Cihazlar aranıyor…', + 'holderNotFound': 'Cihaz bulunamadı', + 'holderPairHint': 'Tutucunun açık ve eşleştirme modunda olduğundan emin olun', + 'holderRetryHint': 'Cihazın açık ve yakında olduğundan emin olup tekrar deneyin', + 'autoConnectTitle': 'Cihazlara otomatik bağlan', + 'autoConnectDesc': 'Cihazınız açıldığında veya yaklaştığında yeniden bağlanmak ve kayıtları almak için uygulamayı uyandırır', + 'autoConnectConsentTitle': 'Otomatik bağlanmayı etkinleştir', + 'autoConnectConsentIntro': 'Cihazınızın (AI Kulaklık / AI Telefon Tutucu) otomatik bağlanabilmesi ve kayıt düğmesine bastığınızda kayıtların kaydedilebilmesi için onayınıza ihtiyacımız var:', + 'autoConnectConsentB1': 'Bağlı cihazınız algılandığında uygulamanın uyandırılması (otomatik başlatılması), yeniden bağlanması ve kayıtları alması için arka planda Bluetooth taraması kaydedilir', + 'autoConnectConsentB2': 'Uyandırıldıktan sonra yalnızca cihaz bağlantısı, kayıt ve yükleme için kullanılır — başka hiçbir şey için değil, başka uygulama da başlatılmaz', + 'autoConnectConsentB3': 'Bunu kullanmadan da uygulamayı kullanabilirsiniz — her seferinde cihazı elle bağlamanız yeterlidir', + 'autoConnectConsentB4': 'Ayarlar → Cihazlara otomatik bağlan bölümünden istediğiniz zaman kapatabilirsiniz', + 'autoConnectAgree': 'Kabul et ve etkinleştir', + 'autoConnectLater': 'Şimdi değil', + 'autoConnectRequired': 'Otomatik bağlanma kapalı', + 'autoConnectRequiredDesc': 'Bu cihazı bağlamak için otomatik bağlanmayı etkinleştirin', + 'recordTapToStart': 'Kaydı başlatmak için aşağıdaki düğmeye dokunun', + 'recordPaused': 'Duraklatıldı', + 'recordMark': 'İşaretle', + 'recordDeleteTitle': 'Kaydı sil', + 'accountAndProfile': 'Hesap ve profil', + 'nicknameUnset': 'Takma ad ayarlanmadı', + 'nicknameInput': 'Takma ad girin', + 'loginMethod': 'Giriş yöntemi', + 'manageMyLogin': 'Girişi yönet', + 'logoutAction': 'Çıkış yap', + 'warningLabel': 'Uyarı:', + 'deleteAccountWarn': 'Hesabınız ve tüm dosyalarınız kalıcı olarak silinecek.', + 'icpFiling': 'ICP kaydı', + 'logExport': 'Günlükleri dışa aktar', + 'logExportDesc': 'Uygulama günlüklerini görüntüleyin ve dışa aktarın', + 'permLoadFailed': 'İzin grupları yüklenemedi', + 'permInsufficient': 'İzin reddedildi', + 'voiceCloneCreating': 'Sesiniz oluşturuluyor…', + 'voiceCloneCreate': 'Sesimi oluştur', + 'voiceCloneAgree': 'Kabul et ve metni sesli oku', + 'voiceCloneReadPrompt': 'Lütfen okuyun:', + 'voiceCloneFirstMonthFree': 'İlk ay ücretsiz', + 'voiceCloneEnable': 'Ses klonlamayı etkinleştir', + 'noMusicPlaying': 'Hiçbir şey çalmıyor', + 'qqMusicNoSeek': 'QQ Music için ileri/geri sarma desteklenmiyor', + 'bleScanTitle': 'BLE taraması', + 'bluetoothOn': 'Bluetooth açık', + 'bleScanning': 'Taranıyor…', + 'bleConnectedDevices': 'Bağlı cihazlar', + 'bleUnknownDevice': 'Bilinmeyen cihaz', + 'bleTapToScan': 'BLE cihazlarını aramak için tara\'ya dokunun', + 'weekMon': 'Pzt', + 'weekTue': 'Sal', + 'weekWed': 'Çar', + 'weekThu': 'Per', + 'weekFri': 'Cum', + 'weekSat': 'Cmt', + 'weekSun': 'Paz', + 'agentMeeting': 'Sesli Tutanak', + 'agentMeetingDesc': 'Kayıtları özetleyin, hafıza merkezi', + 'agentEmai': 'EMAI Asistan', + 'agentEmaiDesc': 'Sesle sohbet edin ve her şeyi sorun', + 'agentSimultaneous': 'Canlı Çeviri', + 'agentSimultaneousDesc': 'Konuşurken çevirin', + 'agentFaceToFace': 'Yüz Yüze', + 'agentFaceToFaceDesc': 'İki yönlü konuşma çevirisi', + 'agentCallRecording': 'Arama Kaydı', + 'agentCallRecordingDesc': 'Aramalar otomatik kaydedilir', + 'agentFieldRecording': 'Saha Kaydı', + 'agentFieldRecordingDesc': 'Cihaz veya telefon mikrofonu', + 'agentCall': 'Arama Çevirisi', + 'agentCallDesc': 'Aramalar sırasında gerçek zamanlı çeviri', + 'agentAudioVideo': 'Medya Çevirisi', + 'agentAudioVideoDesc': 'Kamera çerçeveleme / ses ve video çevirisi', + 'agentEnglishChat': 'İngilizce Sohbet', + 'agentEnglishChatDesc': 'Sürükleyici konuşma pratiği', + 'agentEnglishStudy': 'İngilizce Çalışma', + 'agentEnglishStudyDesc': 'Kelime ve dil bilgisi dersleri', + 'agentKidsStory': 'Çocuk Hikâyeleri', + 'agentKidsStoryDesc': 'Uyku hikâyeleri ve soru-cevap', + 'moduleRemovedDesc': 'AI sayfasından kaldırıldı', + 'moduleAddedDesc': 'AI sayfasının altına eklendi', + 'calNoRecords': 'Kayıt yok', + 'calNoRecordsDay': 'Planlanmış bir şey yok', + 'calTodos': 'Yapılacaklar', + 'calExpenses': 'Harcamalar', + 'calTodoCount': '@count yapılacak', + 'calExpenseCount': '@count harcama', + 'calEntryCount': '@count kayıt', + 'calItemsUnit': 'öğe', + 'calCountUnit': 'kayıt', + 'calTotalAmount': 'Toplam', + 'recordPause': 'Duraklat', + 'recordResume': 'Devam et', + 'recordDeleteConfirm': 'Bu kayıt silinsin mi?', + 'scopeDay': 'Gün', + 'scopeWeek': 'Hafta', + 'scopeMonth': 'Ay', + 'allDay': 'Tüm gün', + 'guestModeTitle': 'Misafir modu', + 'guestModeDesc': 'Misafirler yalnızca göz atabilir. Sesli notlar, çeviri ve kayıt için giriş yapın — verileriniz hesabınıza kaydedilecek.', + 'guestKeepBrowsing': 'Gezinmeye devam et', + 'guestGoLogin': 'Giriş yap', + 'guestViewOnlyTag': 'Yalnızca görüntüleme', + 'autoConnectReenableHint': 'Otomatik bağlanma kapalı. Ayarlar → Cihazlara otomatik bağlan bölümünden yeniden açın.', + 'plazaEntryDesc': 'Daha fazla ajana göz atın ve ekleyin', + 'agentTextTranslation': 'Metin Çevirisi', + 'agentTextTranslationDesc': 'Yazılan veya yapıştırılan metni çevirin', + 'agentPictureTranslation': 'Fotoğraf Çevirisi', + 'agentPictureTranslationDesc': 'Çevirmek için fotoğraf çekin veya seçin', + 'callRequiredTitle': 'Arama gerekli', + 'callRequiredDesc': 'Bu özellik yalnızca arama sırasında çalışır', + 'inCallBusyTitle': 'Arama sırasında kullanılamaz', + 'inCallBusyDesc': 'Mikrofon ve ses yolu arama tarafından kullanılıyor. Aramayı kapattıktan sonra tekrar deneyin.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Ücretsiz', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/uk_ua.dart b/apps/client/lib/core/translations/language/uk_ua.dart index 214759d2..43c7db08 100644 --- a/apps/client/lib/core/translations/language/uk_ua.dart +++ b/apps/client/lib/core/translations/language/uk_ua.dart @@ -1920,4 +1920,208 @@ const Map ukUA = { 'unmarkFavorite': 'Прибрати з обраного', 'unnamedDevice': 'Пристрій без назви', 'userDataParseFailed': 'Не вдалося обробити дані користувача', + 'catEarphone': 'ШІ-навушники', + 'catEarphoneDesc': 'Навушники Bluetooth Classic / BLE', + 'catPhoneHolder': 'ШІ-тримач телефона', + 'catPhoneHolderDesc': 'Пристрої-тримачі', + 'catCarAroma': 'ШІ-ароматизатор для авто', + 'catCarAromaDesc': 'Автомобільний ароматизатор', + 'agreeAndContinue': 'Погодитися й продовжити', + 'memberServiceAgreement': 'Угода про членські послуги', + 'memberServiceAgreementTitle': 'Угода про членські послуги', + 'memberServiceAgreementIntro': 'Щоб надавати вам кращі членські послуги, уважно прочитайте перед оформленням підписки: ', + 'memberServiceAgreementOutro': '. Натискаючи «Погодитися й продовжити», ви підтверджуєте, що повністю прочитали й приймаєте наведену вище угоду.', + 'memberAgreementRejectedTip': 'Щоб продовжити, потрібно погодитися з Угодою про членські послуги.', + 'translationCallExitTitle': 'Вийти з перекладу дзвінка', + 'translationCallExitMessage': 'Виберіть, що зробити перед виходом', + 'translationCallEnd': 'Завершити переклад дзвінка', + 'translationContinueInBackground': 'Продовжити переклад у фоні', + 'backgroundRecordingIndicatorBody': 'Запис триває у фоновому режимі. Торкніться, щоб повернутися.', + 'backgroundTranslationIndicatorBody': 'Переклад дзвінка триває у фоновому режимі. Торкніться, щоб повернутися.', + 'meetingRecordScreenCapturePermissionDenied': 'Для запису системного звуку потрібен дозвіл на запис екрана. Надайте його та повторіть спробу.', + 'pleaseGrantBluetoothPermission': 'Надайте дозвіл на Bluetooth для сканування', + 'startScanFailed': 'Не вдалося почати сканування', + 'pleaseLoginFirst': 'Спочатку увійдіть', + 'deviceUnauthorized': 'Пристрій не авторизовано, повторіть спробу', + 'boundDevices': 'Прив’язані пристрої', + 'currentConnection': 'Поточне підключення', + 'binding': 'Прив’язування...', + 'permissionDisabled': 'Вимкнено', + 'confirmDisablePermissionTitle': 'Вимкнути дозвіл', + 'confirmDisablePermissionContent': 'Вимкнути дозвіл {permission}? Щоб увімкнути його знову, потрібно буде перейти в системні налаштування.', + 'confirmPermanentlyDisallowTitle': 'Більше не запитувати?', + 'confirmPermanentlyDisallowContent': 'Ви відхилили дозвіл {permission}. Більше не запитувати? Якщо вибрати «Не дозволяти», його все одно можна буде ввімкнути пізніше в системних налаштуваннях.', + 'notNow': 'Не зараз', + 'permanentlyDisallow': 'Не дозволяти', + 'otaBesNotSupported': 'Ці навушники поки не підтримують оновлення прошивки із застосунку. Зверніться до служби підтримки.', + 'tabDevice': 'Пристрої', + 'tabPlaza': 'Площа', + 'sloganHome': 'Технології для розумнішого життя', + 'sloganAi': 'Безмежний інтелект', + 'sloganDevice': 'Розумне обладнання, готове до майбутнього', + 'sloganPlaza': 'Розумний світ, який тебе розуміє', + 'aiEditHint': 'Утримуйте картку, щоб перетягнути й упорядкувати модулі', + 'aiEmptyTitle': 'Модулів ще не додано', + 'aiEmptyDesc': 'Оберіть потрібних агентів на Площі', + 'goToPlaza': 'Перейти на Площу', + 'plazaOnline': 'Доступно', + 'plazaPlanned': 'Незабаром', + 'plazaSearchHint': 'Пошук агентів, напр. «переклад», «запис»', + 'moduleRemove': 'Видалити', + 'moduleAdd': 'Додати', + 'moduleRemoved': 'Видалено', + 'moduleAdded': 'Додано', + 'goSee': 'Переглянути', + 'comingSoonTag': 'Незабаром', + 'needDeviceTag': 'Потрібен пристрій', + 'featureInDev': 'Ця функція в розробці', + 'featureNotWired': 'Поки що недоступно', + 'todayLabel': 'Сьогодні', + 'deviceConnected': 'Підключено', + 'licenseUnknown': 'Ліцензія невідома', + 'selectDevice': 'Виберіть пристрій', + 'catNoteCard': 'ШІ-картка-диктофон', + 'catNoteCardDesc': 'Диктофон у формі картки', + 'catParkerPen': 'ШІ-ручка', + 'catParkerPenDesc': 'Ручки з диктофоном', + 'catStylusPen': 'ШІ-стилус', + 'catStylusPenDesc': 'Пристрої для рукопису / стилуси', + 'catStudyMachine': 'ШІ-планшет для навчання', + 'catStudyMachineDesc': 'Навчальні пристрої', + 'besAddTitle': 'Додати ШІ-навушники', + 'besConnecting': 'Підключення до навушників…', + 'besNotFound': 'Навушники не знайдено', + 'besNotFoundIosDesc': 'Спочатку підключіть навушники в Налаштування → Bluetooth, а потім поверніться сюди', + 'besNotFoundAndroidDesc': 'Спочатку створіть пару з навушниками в Налаштування → Bluetooth, а потім підключіть їх тут', + 'besReadFailed': 'Помилка читання', + 'besConnectFailIos': 'Переконайтеся, що навушники позначено як «Підключено» в системному Bluetooth, і повторіть спробу', + 'besConnectFailAndroid': 'Переконайтеся, що навушники ввімкнено, вони поруч і не підключені до іншого пристрою. Після з’єднання вони підключатимуться автоматично.', + 'holderAddTitle': 'Додати ШІ-тримач телефона', + 'holderConnecting': 'Підключення до пристрою…', + 'holderSearching': 'Пошук пристроїв…', + 'holderNotFound': 'Пристроїв не знайдено', + 'holderPairHint': 'Переконайтеся, що тримач увімкнено й він у режимі створення пари', + 'holderRetryHint': 'Переконайтеся, що пристрій увімкнено й він поруч, і повторіть спробу', + 'autoConnectTitle': 'Автопідключення пристроїв', + 'autoConnectDesc': 'Пробуджує застосунок для повторного підключення та отримання записів, коли пристрій вмикається або опиняється поруч', + 'autoConnectConsentTitle': 'Увімкнути автопідключення', + 'autoConnectConsentIntro': 'Щоб ваш пристрій (ШІ-навушники / ШІ-тримач телефона) підключався автоматично та зберігав записи після натискання кнопки запису, нам потрібна ваша згода:', + 'autoConnectConsentB1': 'Реєстрація фонового сканування Bluetooth, щоб застосунок пробуджувався (запускався автоматично) при виявленні прив’язаного пристрою для повторного підключення та отримання записів', + 'autoConnectConsentB2': 'Після пробудження використовується лише для підключення пристрою, запису та завантаження — нічого іншого, інші застосунки не запускаються', + 'autoConnectConsentB3': 'Застосунком можна користуватися й без цього — просто підключайте пристрій вручну щоразу', + 'autoConnectConsentB4': 'Це можна будь-коли вимкнути в Налаштування → Автопідключення пристроїв', + 'autoConnectAgree': 'Погодитися й увімкнути', + 'autoConnectLater': 'Не зараз', + 'autoConnectRequired': 'Автопідключення вимкнено', + 'autoConnectRequiredDesc': 'Увімкніть автопідключення, щоб прив’язати цей пристрій', + 'recordTapToStart': 'Натисніть кнопку нижче, щоб почати запис', + 'recordPaused': 'Призупинено', + 'recordMark': 'Позначка', + 'recordDeleteTitle': 'Видалити запис', + 'accountAndProfile': 'Обліковий запис і профіль', + 'nicknameUnset': 'Псевдонім не задано', + 'nicknameInput': 'Введіть псевдонім', + 'loginMethod': 'Спосіб входу', + 'manageMyLogin': 'Керувати входом', + 'logoutAction': 'Вийти', + 'warningLabel': 'Увага:', + 'deleteAccountWarn': 'Ваш обліковий запис і всі файли буде видалено назавжди.', + 'icpFiling': 'Реєстрація ICP', + 'logExport': 'Експорт журналів', + 'logExportDesc': 'Перегляд і експорт журналів застосунку', + 'permLoadFailed': 'Не вдалося завантажити групи дозволів', + 'permInsufficient': 'Немає дозволу', + 'voiceCloneCreating': 'Створення вашого голосу…', + 'voiceCloneCreate': 'Створити мій голос', + 'voiceCloneAgree': 'Погодитися й прочитати заяву вголос', + 'voiceCloneReadPrompt': 'Прочитайте:', + 'voiceCloneFirstMonthFree': 'Перший місяць безкоштовно', + 'voiceCloneEnable': 'Увімкнути клонування голосу', + 'noMusicPlaying': 'Нічого не відтворюється', + 'qqMusicNoSeek': 'Перемотування не підтримується для QQ Music', + 'bleScanTitle': 'Сканування BLE', + 'bluetoothOn': 'Bluetooth увімкнено', + 'bleScanning': 'Сканування…', + 'bleConnectedDevices': 'Підключені пристрої', + 'bleUnknownDevice': 'Невідомий пристрій', + 'bleTapToScan': 'Натисніть «Сканувати», щоб знайти BLE-пристрої', + 'weekMon': 'Пн', + 'weekTue': 'Вт', + 'weekWed': 'Ср', + 'weekThu': 'Чт', + 'weekFri': 'Пт', + 'weekSat': 'Сб', + 'weekSun': 'Нд', + 'agentMeeting': 'Голосові нотатки', + 'agentMeetingDesc': 'Підсумки записів, центр пам’яті', + 'agentEmai': 'Асистент EMAI', + 'agentEmaiDesc': 'Спілкуйтеся й запитуйте будь-що голосом', + 'agentSimultaneous': 'Синхронний переклад', + 'agentSimultaneousDesc': 'Переклад під час мовлення', + 'agentFaceToFace': 'Віч-на-віч', + 'agentFaceToFaceDesc': 'Двосторонній переклад розмови', + 'agentCallRecording': 'Запис дзвінка', + 'agentCallRecordingDesc': 'Дзвінки зберігаються автоматично', + 'agentFieldRecording': 'Запис на місці', + 'agentFieldRecordingDesc': 'Мікрофон пристрою або телефона', + 'agentCall': 'Переклад дзвінків', + 'agentCallDesc': 'Переклад у реальному часі під час дзвінка', + 'agentAudioVideo': 'Переклад медіа', + 'agentAudioVideoDesc': 'Кадрування камерою / переклад аудіо та відео', + 'agentEnglishChat': 'Розмова англійською', + 'agentEnglishChatDesc': 'Занурення в розмовну практику', + 'agentEnglishStudy': 'Вивчення англійської', + 'agentEnglishStudyDesc': 'Уроки лексики та граматики', + 'agentKidsStory': 'Дитячі казки', + 'agentKidsStoryDesc': 'Казки на ніч і відповіді на запитання', + 'moduleRemovedDesc': 'видалено зі сторінки ШІ', + 'moduleAddedDesc': 'додано в кінець сторінки ШІ', + 'calNoRecords': 'Немає записів', + 'calNoRecordsDay': 'Нічого не заплановано', + 'calTodos': 'Завдання', + 'calExpenses': 'Витрати', + 'calTodoCount': 'Завдань: @count', + 'calExpenseCount': 'Витрат: @count', + 'calEntryCount': 'Записів: @count', + 'calItemsUnit': 'елементів', + 'calCountUnit': 'записів', + 'calTotalAmount': 'Разом', + 'recordPause': 'Пауза', + 'recordResume': 'Продовжити', + 'recordDeleteConfirm': 'Видалити цей запис?', + 'scopeDay': 'День', + 'scopeWeek': 'Тиждень', + 'scopeMonth': 'Місяць', + 'allDay': 'Увесь день', + 'guestModeTitle': 'Гостьовий режим', + 'guestModeDesc': 'Гості можуть лише переглядати. Увійдіть, щоб користуватися голосовими нотатками, перекладом і записом — ваші дані зберігатимуться в обліковому записі.', + 'guestKeepBrowsing': 'Продовжити перегляд', + 'guestGoLogin': 'Увійти', + 'guestViewOnlyTag': 'Лише перегляд', + 'autoConnectReenableHint': 'Автопідключення вимкнено. Увімкніть його знову в Налаштування → Автопідключення пристроїв.', + 'plazaEntryDesc': 'Переглядайте й додавайте більше агентів', + 'agentTextTranslation': 'Текстовий переклад', + 'agentTextTranslationDesc': 'Переклад введеного або вставленого тексту', + 'agentPictureTranslation': 'Переклад фото', + 'agentPictureTranslationDesc': 'Зробіть або виберіть фото для перекладу', + 'callRequiredTitle': 'Потрібен дзвінок', + 'callRequiredDesc': 'Ця функція працює лише під час дзвінка', + 'inCallBusyTitle': 'Недоступно під час дзвінка', + 'inCallBusyDesc': 'Мікрофон і аудіотракт зайняті дзвінком. Спробуйте ще раз після завершення дзвінка.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Безкоштовно', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/vi_vn.dart b/apps/client/lib/core/translations/language/vi_vn.dart index b4963ad8..529ea6f0 100644 --- a/apps/client/lib/core/translations/language/vi_vn.dart +++ b/apps/client/lib/core/translations/language/vi_vn.dart @@ -1880,4 +1880,208 @@ const Map viVN = { 'unmarkFavorite': 'Bỏ khỏi yêu thích', 'unnamedDevice': 'Thiết bị chưa đặt tên', 'userDataParseFailed': 'Không đọc được dữ liệu người dùng', + 'catEarphone': 'Tai nghe AI', + 'catEarphoneDesc': 'Tai nghe Bluetooth cổ điển / BLE', + 'catPhoneHolder': 'Giá đỡ điện thoại AI', + 'catPhoneHolderDesc': 'Thiết bị giá đỡ', + 'catCarAroma': 'Máy khuếch tán hương ô tô AI', + 'catCarAromaDesc': 'Máy khuếch tán hương trên xe', + 'agreeAndContinue': 'Đồng ý và tiếp tục', + 'memberServiceAgreement': 'Thỏa thuận dịch vụ hội viên', + 'memberServiceAgreementTitle': 'Thỏa thuận dịch vụ hội viên', + 'memberServiceAgreementIntro': 'Để cung cấp dịch vụ hội viên tốt hơn, vui lòng đọc kỹ trước khi đăng ký: ', + 'memberServiceAgreementOutro': '. Khi nhấn "Đồng ý và tiếp tục", bạn xác nhận đã đọc đầy đủ và chấp nhận thỏa thuận trên.', + 'memberAgreementRejectedTip': 'Bạn phải đồng ý Thỏa thuận dịch vụ hội viên để tiếp tục.', + 'translationCallExitTitle': 'Thoát dịch cuộc gọi', + 'translationCallExitMessage': 'Chọn thao tác trước khi rời đi', + 'translationCallEnd': 'Kết thúc dịch cuộc gọi', + 'translationContinueInBackground': 'Tiếp tục dịch trong nền', + 'backgroundRecordingIndicatorBody': 'Đang tiếp tục ghi âm trong nền. Nhấn để quay lại.', + 'backgroundTranslationIndicatorBody': 'Đang tiếp tục dịch cuộc gọi trong nền. Nhấn để quay lại.', + 'meetingRecordScreenCapturePermissionDenied': 'Cần quyền ghi màn hình để ghi âm thanh hệ thống. Vui lòng cấp quyền rồi thử lại.', + 'pleaseGrantBluetoothPermission': 'Vui lòng cấp quyền Bluetooth để quét', + 'startScanFailed': 'Không thể bắt đầu quét', + 'pleaseLoginFirst': 'Vui lòng đăng nhập trước', + 'deviceUnauthorized': 'Thiết bị chưa được cấp phép, vui lòng thử lại', + 'boundDevices': 'Thiết bị đã liên kết', + 'currentConnection': 'Kết nối hiện tại', + 'binding': 'Đang liên kết...', + 'permissionDisabled': 'Đã tắt', + 'confirmDisablePermissionTitle': 'Tắt quyền', + 'confirmDisablePermissionContent': 'Tắt quyền {permission}? Bạn sẽ cần vào cài đặt hệ thống để bật lại.', + 'confirmPermanentlyDisallowTitle': 'Không hỏi lại?', + 'confirmPermanentlyDisallowContent': 'Bạn đã từ chối quyền {permission}. Không hỏi lại từ giờ? Nếu chọn "Không cho phép", bạn vẫn có thể bật lại sau trong cài đặt hệ thống.', + 'notNow': 'Để sau', + 'permanentlyDisallow': 'Không cho phép', + 'otaBesNotSupported': 'Tai nghe này chưa hỗ trợ nâng cấp firmware trong ứng dụng. Vui lòng liên hệ bộ phận hỗ trợ.', + 'tabDevice': 'Thiết bị', + 'tabPlaza': 'Plaza', + 'sloganHome': 'Công nghệ cho cuộc sống thông minh hơn', + 'sloganAi': 'Trí tuệ không giới hạn', + 'sloganDevice': 'Phần cứng thông minh, sẵn sàng cho tương lai', + 'sloganPlaza': 'Thế giới thông minh thấu hiểu bạn', + 'aiEditHint': 'Nhấn giữ thẻ để kéo và sắp xếp lại mô-đun', + 'aiEmptyTitle': 'Chưa thêm mô-đun nào', + 'aiEmptyDesc': 'Chọn tác nhân bạn cần trong Plaza', + 'goToPlaza': 'Đến Plaza', + 'plazaOnline': 'Sẵn sàng', + 'plazaPlanned': 'Sắp ra mắt', + 'plazaSearchHint': 'Tìm tác nhân, ví dụ “dịch”, “ghi âm”', + 'moduleRemove': 'Gỡ', + 'moduleAdd': 'Thêm', + 'moduleRemoved': 'Đã gỡ', + 'moduleAdded': 'Đã thêm', + 'goSee': 'Xem', + 'comingSoonTag': 'Sắp ra mắt', + 'needDeviceTag': 'Cần thiết bị', + 'featureInDev': 'Tính năng này đang được phát triển', + 'featureNotWired': 'Chưa khả dụng', + 'todayLabel': 'Hôm nay', + 'deviceConnected': 'Đã kết nối', + 'licenseUnknown': 'Không rõ trạng thái cấp phép', + 'selectDevice': 'Chọn thiết bị', + 'catNoteCard': 'Thẻ ghi âm AI', + 'catNoteCardDesc': 'Máy ghi âm dạng thẻ', + 'catParkerPen': 'Bút AI', + 'catParkerPenDesc': 'Bút ghi âm', + 'catStylusPen': 'Bút cảm ứng AI', + 'catStylusPenDesc': 'Thiết bị viết tay / bút cảm ứng', + 'catStudyMachine': 'Máy học tập AI', + 'catStudyMachineDesc': 'Thiết bị học tập', + 'besAddTitle': 'Thêm tai nghe AI', + 'besConnecting': 'Đang kết nối tai nghe…', + 'besNotFound': 'Không tìm thấy tai nghe', + 'besNotFoundIosDesc': 'Hãy kết nối tai nghe trong Cài đặt → Bluetooth trước, rồi quay lại đây', + 'besNotFoundAndroidDesc': 'Hãy ghép nối tai nghe trong Cài đặt → Bluetooth trước, rồi kết nối tại đây', + 'besReadFailed': 'Đọc dữ liệu thất bại', + 'besConnectFailIos': 'Hãy chắc chắn tai nghe hiển thị "Đã kết nối" trong Bluetooth hệ thống, rồi thử lại', + 'besConnectFailAndroid': 'Hãy chắc chắn tai nghe đã bật, ở gần và không kết nối với thiết bị khác. Sau khi liên kết, tai nghe sẽ tự động kết nối lại.', + 'holderAddTitle': 'Thêm giá đỡ điện thoại AI', + 'holderConnecting': 'Đang kết nối thiết bị…', + 'holderSearching': 'Đang tìm thiết bị…', + 'holderNotFound': 'Không tìm thấy thiết bị', + 'holderPairHint': 'Hãy chắc chắn giá đỡ đã bật và đang ở chế độ ghép nối', + 'holderRetryHint': 'Hãy chắc chắn thiết bị đã bật và ở gần, rồi thử lại', + 'autoConnectTitle': 'Tự động kết nối thiết bị', + 'autoConnectDesc': 'Đánh thức ứng dụng để kết nối lại và nhận bản ghi âm khi thiết bị bật nguồn hoặc ở gần', + 'autoConnectConsentTitle': 'Bật tự động kết nối', + 'autoConnectConsentIntro': 'Để thiết bị của bạn (tai nghe AI / giá đỡ điện thoại AI) tự động kết nối và lưu bản ghi âm khi bạn nhấn nút ghi âm trên thiết bị, chúng tôi cần sự đồng ý của bạn:', + 'autoConnectConsentB1': 'Đăng ký quét Bluetooth trong nền để ứng dụng được đánh thức (tự khởi động) khi phát hiện thiết bị đã liên kết, nhằm kết nối lại và nhận bản ghi âm', + 'autoConnectConsentB2': 'Sau khi được đánh thức, chỉ dùng để kết nối thiết bị, ghi âm và tải lên — không làm gì khác và không mở ứng dụng nào khác', + 'autoConnectConsentB3': 'Bạn vẫn có thể dùng ứng dụng mà không bật tính năng này — chỉ cần kết nối thiết bị thủ công mỗi lần', + 'autoConnectConsentB4': 'Bạn có thể tắt bất cứ lúc nào trong Cài đặt → Tự động kết nối thiết bị', + 'autoConnectAgree': 'Đồng ý và bật', + 'autoConnectLater': 'Để sau', + 'autoConnectRequired': 'Tự động kết nối đang tắt', + 'autoConnectRequiredDesc': 'Bật tự động kết nối để liên kết thiết bị này', + 'recordTapToStart': 'Nhấn nút bên dưới để bắt đầu ghi âm', + 'recordPaused': 'Đã tạm dừng', + 'recordMark': 'Đánh dấu', + 'recordDeleteTitle': 'Xóa bản ghi', + 'accountAndProfile': 'Tài khoản và hồ sơ', + 'nicknameUnset': 'Chưa đặt biệt danh', + 'nicknameInput': 'Nhập biệt danh', + 'loginMethod': 'Phương thức đăng nhập', + 'manageMyLogin': 'Quản lý đăng nhập', + 'logoutAction': 'Đăng xuất', + 'warningLabel': 'Cảnh báo:', + 'deleteAccountWarn': 'Tài khoản và toàn bộ tệp của bạn sẽ bị xóa vĩnh viễn.', + 'icpFiling': 'Đăng ký ICP', + 'logExport': 'Xuất nhật ký', + 'logExportDesc': 'Xem và xuất nhật ký ứng dụng', + 'permLoadFailed': 'Không tải được nhóm quyền', + 'permInsufficient': 'Không đủ quyền', + 'voiceCloneCreating': 'Đang tạo giọng nói của bạn…', + 'voiceCloneCreate': 'Tạo giọng nói của tôi', + 'voiceCloneAgree': 'Đồng ý và đọc to đoạn tuyên bố', + 'voiceCloneReadPrompt': 'Vui lòng đọc:', + 'voiceCloneFirstMonthFree': 'Miễn phí tháng đầu', + 'voiceCloneEnable': 'Bật sao chép giọng nói', + 'noMusicPlaying': 'Không có nhạc đang phát', + 'qqMusicNoSeek': 'QQ Music không hỗ trợ tua nhạc', + 'bleScanTitle': 'Quét BLE', + 'bluetoothOn': 'Bluetooth đã bật', + 'bleScanning': 'Đang quét…', + 'bleConnectedDevices': 'Thiết bị đã kết nối', + 'bleUnknownDevice': 'Thiết bị không xác định', + 'bleTapToScan': 'Nhấn quét để tìm thiết bị BLE', + 'weekMon': 'T2', + 'weekTue': 'T3', + 'weekWed': 'T4', + 'weekThu': 'T5', + 'weekFri': 'T6', + 'weekSat': 'T7', + 'weekSun': 'CN', + 'agentMeeting': 'Biên bản giọng nói', + 'agentMeetingDesc': 'Tóm tắt bản ghi âm, trung tâm ký ức', + 'agentEmai': 'Trợ lý EMAI', + 'agentEmaiDesc': 'Trò chuyện và hỏi mọi thứ bằng giọng nói', + 'agentSimultaneous': 'Dịch trực tiếp', + 'agentSimultaneousDesc': 'Dịch ngay khi bạn nói', + 'agentFaceToFace': 'Mặt đối mặt', + 'agentFaceToFaceDesc': 'Dịch hội thoại hai chiều', + 'agentCallRecording': 'Ghi âm cuộc gọi', + 'agentCallRecordingDesc': 'Tự động lưu cuộc gọi', + 'agentFieldRecording': 'Ghi âm hiện trường', + 'agentFieldRecordingDesc': 'Qua thiết bị hoặc micro điện thoại', + 'agentCall': 'Dịch cuộc gọi', + 'agentCallDesc': 'Dịch thời gian thực trong cuộc gọi', + 'agentAudioVideo': 'Dịch đa phương tiện', + 'agentAudioVideoDesc': 'Khung hình camera / dịch âm thanh và video', + 'agentEnglishChat': 'Trò chuyện tiếng Anh', + 'agentEnglishChatDesc': 'Luyện nói theo phong cách nhập vai', + 'agentEnglishStudy': 'Học tiếng Anh', + 'agentEnglishStudyDesc': 'Bài học từ vựng và ngữ pháp', + 'agentKidsStory': 'Truyện thiếu nhi', + 'agentKidsStoryDesc': 'Truyện trước khi ngủ và hỏi đáp', + 'moduleRemovedDesc': 'đã gỡ khỏi trang AI', + 'moduleAddedDesc': 'đã thêm vào cuối trang AI', + 'calNoRecords': 'Không có mục nào', + 'calNoRecordsDay': 'Không có lịch trình', + 'calTodos': 'Việc cần làm', + 'calExpenses': 'Chi tiêu', + 'calTodoCount': '@count việc cần làm', + 'calExpenseCount': '@count khoản chi', + 'calEntryCount': '@count mục', + 'calItemsUnit': 'mục', + 'calCountUnit': 'mục', + 'calTotalAmount': 'Tổng', + 'recordPause': 'Tạm dừng', + 'recordResume': 'Tiếp tục', + 'recordDeleteConfirm': 'Xóa bản ghi này?', + 'scopeDay': 'Ngày', + 'scopeWeek': 'Tuần', + 'scopeMonth': 'Tháng', + 'allDay': 'Cả ngày', + 'guestModeTitle': 'Chế độ khách', + 'guestModeDesc': 'Khách chỉ có thể xem. Đăng nhập để dùng biên bản giọng nói, dịch và ghi âm — dữ liệu của bạn sẽ được lưu vào tài khoản.', + 'guestKeepBrowsing': 'Tiếp tục xem', + 'guestGoLogin': 'Đăng nhập', + 'guestViewOnlyTag': 'Chỉ xem', + 'autoConnectReenableHint': 'Tự động kết nối đang tắt. Bật lại trong Cài đặt → Tự động kết nối thiết bị.', + 'plazaEntryDesc': 'Khám phá và thêm tác nhân khác', + 'agentTextTranslation': 'Dịch văn bản', + 'agentTextTranslationDesc': 'Dịch văn bản đã nhập hoặc dán', + 'agentPictureTranslation': 'Dịch hình ảnh', + 'agentPictureTranslationDesc': 'Chụp hoặc chọn ảnh để dịch', + 'callRequiredTitle': 'Cần có cuộc gọi', + 'callRequiredDesc': 'Tính năng này chỉ hoạt động trong cuộc gọi', + 'inCallBusyTitle': 'Không khả dụng trong cuộc gọi', + 'inCallBusyDesc': 'Micro và đường âm thanh đang được cuộc gọi sử dụng. Hãy thử lại sau khi cúp máy.', + 'vipSectionTitle': 'VIP', + 'freeSectionTitle': 'Miễn phí', + 'smartcarConnected': 'Connected', + 'smartcarConnectFailed': 'Connection failed', + 'smartcarConnecting': 'Connecting…', + 'smartcarSearching': 'Searching for nearby car diffusers…', + 'smartcarNotFound': 'No device found', + 'smartcarScanHint': 'Make sure the device is powered on and close to your phone', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/zh_cn.dart b/apps/client/lib/core/translations/language/zh_cn.dart index 876b437a..605078bf 100644 --- a/apps/client/lib/core/translations/language/zh_cn.dart +++ b/apps/client/lib/core/translations/language/zh_cn.dart @@ -1685,6 +1685,8 @@ const Map zhCN = { 'catNoteCardDesc': '卡片式录音设备', 'catPhoneHolder': 'AI手机支架', 'catPhoneHolderDesc': '支架类设备', + 'catCarAroma': 'AI车载香薰', + 'catCarAromaDesc': '车载香薰设备', 'catParkerPen': 'AI派克笔', 'catParkerPenDesc': '录音笔类设备', 'catStylusPen': 'AI电容笔', @@ -1924,4 +1926,18 @@ const Map zhCN = { 'unmarkFavorite': '取消收藏', 'unnamedDevice': '未命名设备', 'userDataParseFailed': '用户数据解析失败', + 'smartcarConnected': '已连接', + 'smartcarConnectFailed': '连接失败', + 'smartcarConnecting': '正在连接…', + 'smartcarSearching': '正在搜索附近的车载香薰…', + 'smartcarNotFound': '没有找到设备', + 'smartcarScanHint': '请确认设备已通电,并靠近手机', + 'vipRequiredTitle': '需要会员', + 'vipRequiredDesc': '翻译与会议纪要需要会员。续费会员,或绑定带会员的设备即可使用。', + 'vipRequiredGo': '去开通', + 'vipFromDevice': '来自设备', + 'computeSummary': '算力:设备 @device · 账户 @user', + 'computePack': '算力包', + 'vipExpiringSoon': '会员还有 @days 天到期,续费后可继续使用翻译与会议纪要', + 'computeLow': '算力不多了,用完后将无法继续使用', }; diff --git a/apps/client/lib/core/translations/language/zh_hk.dart b/apps/client/lib/core/translations/language/zh_hk.dart index 96dceb85..24337960 100644 --- a/apps/client/lib/core/translations/language/zh_hk.dart +++ b/apps/client/lib/core/translations/language/zh_hk.dart @@ -1660,6 +1660,8 @@ const Map zhHK = { 'catNoteCardDesc': '卡片式錄音裝置', 'catPhoneHolder': 'AI 手機支架', 'catPhoneHolderDesc': '支架類裝置', + 'catCarAroma': 'AI 車載香薰', + 'catCarAromaDesc': '車載香薰裝置', 'catParkerPen': 'AI 派克筆', 'catParkerPenDesc': '錄音筆類裝置', 'catStylusPen': 'AI 觸控筆', @@ -1907,4 +1909,32 @@ const Map zhHK = { 'unmarkFavorite': '取消收藏', 'unnamedDevice': '未命名裝置', 'userDataParseFailed': '使用者資料解析失敗', + 'translationCallExitTitle': '退出通話翻譯', + 'translationCallExitMessage': '請選擇離開後的操作', + 'translationCallEnd': '結束通話翻譯', + 'translationContinueInBackground': '背景繼續翻譯', + 'backgroundRecordingIndicatorBody': '正在背景繼續錄音,點擊返回', + 'backgroundTranslationIndicatorBody': '正在背景繼續通話翻譯,點擊返回', + 'permissionDisabled': '已停用', + 'confirmDisablePermissionTitle': '關閉權限', + 'confirmDisablePermissionContent': '確定要永久關閉{permission}權限嗎?關閉後需要前往系統設定重新開啟。', + 'confirmPermanentlyDisallowTitle': '是否永久不允許', + 'confirmPermanentlyDisallowContent': '你拒絕了{permission}權限,是否以後都不再詢問?選擇「永久不允許」後,如需開啟請前往系統設定。', + 'notNow': '暫不', + 'permanentlyDisallow': '永久不允許', + 'otaBesNotSupported': '此耳機暫不支援在 App 內升級韌體,請聯絡客服獲取升級方式', + 'smartcarConnected': '已連接', + 'smartcarConnectFailed': '連接失敗', + 'smartcarConnecting': '正在連接…', + 'smartcarSearching': '正在搜尋附近的車載香薰…', + 'smartcarNotFound': '沒有找到裝置', + 'smartcarScanHint': '請確認裝置已通電,並靠近手機', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/translations/language/zh_tw.dart b/apps/client/lib/core/translations/language/zh_tw.dart index 29cf04ec..29b4747b 100644 --- a/apps/client/lib/core/translations/language/zh_tw.dart +++ b/apps/client/lib/core/translations/language/zh_tw.dart @@ -1660,6 +1660,8 @@ const Map zhTW = { 'catNoteCardDesc': '卡片式錄音裝置', 'catPhoneHolder': 'AI 手機支架', 'catPhoneHolderDesc': '支架類裝置', + 'catCarAroma': 'AI 車載香氛', + 'catCarAromaDesc': '車載香氛裝置', 'catParkerPen': 'AI 派克筆', 'catParkerPenDesc': '錄音筆類裝置', 'catStylusPen': 'AI 觸控筆', @@ -1907,4 +1909,32 @@ const Map zhTW = { 'unmarkFavorite': '取消收藏', 'unnamedDevice': '未命名裝置', 'userDataParseFailed': '使用者資料解析失敗', + 'translationCallExitTitle': '退出通話翻譯', + 'translationCallExitMessage': '請選擇離開後的操作', + 'translationCallEnd': '結束通話翻譯', + 'translationContinueInBackground': '背景繼續翻譯', + 'backgroundRecordingIndicatorBody': '正在背景繼續錄音,點選返回', + 'backgroundTranslationIndicatorBody': '正在背景繼續通話翻譯,點選返回', + 'permissionDisabled': '已停用', + 'confirmDisablePermissionTitle': '關閉權限', + 'confirmDisablePermissionContent': '確定要永久關閉{permission}權限嗎?關閉後需要前往系統設定重新開啟。', + 'confirmPermanentlyDisallowTitle': '是否永久不允許', + 'confirmPermanentlyDisallowContent': '您拒絕了{permission}權限,是否以後都不再詢問?選擇「永久不允許」後,如需開啟請前往系統設定。', + 'notNow': '暫不', + 'permanentlyDisallow': '永久不允許', + 'otaBesNotSupported': '此耳機暫不支援在 App 內升級韌體,請聯絡客服取得升級方式', + 'smartcarConnected': '已連接', + 'smartcarConnectFailed': '連接失敗', + 'smartcarConnecting': '正在連接…', + 'smartcarSearching': '正在搜尋附近的車載香氛…', + 'smartcarNotFound': '沒有找到裝置', + 'smartcarScanHint': '請確認裝置已通電,並靠近手機', + 'vipRequiredTitle': 'Membership required', + 'vipRequiredDesc': 'Translation and meeting notes require a membership. Renew, or pair a device that includes one.', + 'vipRequiredGo': 'Get membership', + 'vipFromDevice': 'from device', + 'computeSummary': 'Compute: device @device · account @user', + 'computePack': 'Compute packs', + 'vipExpiringSoon': 'Membership expires in @days day(s). Renew to keep using translation and meeting notes.', + 'computeLow': 'Running low on compute. You won\'t be able to continue once it runs out.', }; diff --git a/apps/client/lib/core/utils/device_connection.dart b/apps/client/lib/core/utils/device_connection.dart index d0e1614f..fac511c9 100644 --- a/apps/client/lib/core/utils/device_connection.dart +++ b/apps/client/lib/core/utils/device_connection.dart @@ -1,54 +1,33 @@ -import 'package:echomeet_device_sdk/echomeet_device_sdk.dart'; -import 'package:get/get.dart'; +import 'package:device_plugin_interface/device_plugin_interface.dart'; import '../../data/models/device_images.dart'; import '../../data/models/user_Info.dart'; -import '../../data/services/bes_bluetooth_service.dart'; -import '../../data/services/holder_device_service.dart'; -import '../../modules/home/controllers/home_controller.dart'; +import '../../devices/device_hub.dart'; -/// 「当前有没有连着设备」的统一判断。 +/// 「当前有没有连着设备」的统一判断——[DeviceHub] 之上的薄门面。 /// -/// 项目里有三条互相独立的蓝牙链路,之前各页面各判各的:设备页三条都看, -/// AI 页却只看了杰理那条,于是恒玄耳机连上后「通话录音 / 通话翻译」还是灰的。 -/// 统一收到这里,谁都别再自己拼。 +/// 早先三条蓝牙链路各页面各判各的(设备页三条都看,AI 页只看杰理那条), +/// 现在只有一个真相源。**这里不出现任何厂商名**,要按能力区分就问 +/// [DeviceHub.has]。 class DeviceConnection { DeviceConnection._(); - /// 杰理 BLE 耳机 - static bool get jieliConnected => - Get.isRegistered() && - HomeController.to.isFullyConnectedRx.value; + static DeviceHub get _hub => DeviceHub.to; - /// 蓝讯手机支架 - static bool get holderConnected => - Get.isRegistered() && - HolderDeviceService.to.connection.value == - EchoMeetConnectionState.connected; + /// 任意一台设备在线即算「已连接设备」 + static bool get any => _hub.anyConnected.value; - /// 恒玄耳机(经典蓝牙 / iOS 走 GATT 桥接) - static bool get besConnected => - Get.isRegistered() && - BesBluetoothService.to.deviceStatus.value == 2; - - /// 任意一条链路连上即算「已连接设备」 - static bool get any => jieliConnected || holderConnected || besConnected; - - /// 依赖设备的功能是否可用(预留:将来若某功能只认某条链路,在这里区分) + /// 依赖设备的功能是否可用 static bool get canUseDeviceFeatures => any && User.isLoggedIn(); - /// 是否正处于通话中。 - /// - /// 以耳机上报为准:0xD1/0x02 接通 → true,0xD2/0x03 挂断 → false。 + /// 是否正处于通话中(由声明了 callState 能力的设备上报)。 /// 通话录音和通话翻译都依赖双路通话音频,不在通话里拿不到数据。 - static bool get inCall => - besConnected && BesBluetoothService.to.isCallOngoing.value; + static bool get inCall => _hub.inCall.value; + + /// 有没有一台设备具备该能力 + static bool has(DeviceCapability c) => _hub.capabilities.contains(c); - /// 通话中被禁用的功能。 - /// - /// 通话时耳机的麦克风和音频通路被通话占用(`AA 51` 之后是双路通话流), - /// 这些功能要么抢不到麦、要么会把通话打断,所以直接禁掉: - /// 现场录音、同声翻译、面对面翻译、多媒体翻译。 + /// 通话中被禁用的功能:通话时设备的麦克风和音频通路被通话占用。 /// 通话录音和通话翻译反过来——只有通话中才可用。 static const Set blockedDuringCall = { 'fieldRecording', @@ -57,45 +36,22 @@ class DeviceConnection { 'audioVideo', }; - /// 该功能此刻是否因为「正在通话」而不可用 static bool isBlockedByCall(String moduleId) => inCall && blockedDuringCall.contains(moduleId); - /// 当前连着的设备名(恒玄耳机 / 蓝讯支架);都没连返回空 - static String get connectedName { - if (besConnected) return BesBluetoothService.to.connectedDeviceName.value; - if (holderConnected) return HolderDeviceService.to.connectedName; - return ''; - } + /// 当前连着的设备名;都没连返回空 + static String get connectedName => _hub.primaryName.value; /// 当前(或最近一次)连接设备的**产品主图**。 - /// - /// 取图规则统一在 [DeviceImages]:按设备名找 `<设备名>.png`,找不到退默认图。 - /// 设备页、固件升级页、设备管理页都走这一份,避免出现「设备页显示 A、 - /// 固件升级页显示 B」这种对不上的情况。 static String currentAssetImage() => DeviceImages.imageFor(_nameForImage()); - /// 同一台设备的**小图标**(列表、卡片里用,别拿主图去塞 44px 的位置) + /// 同一台设备的**小图标** static String currentIconImage() => DeviceImages.iconFor(_nameForImage()); /// 取图用的设备名:优先当前连着的,其次最近连过的。 - /// - /// 断连后仍然认「最近连过的那台」是刻意的——用户拔掉耳机不代表他换了设备, - /// 这时候把图换成通用图会让人以为设备丢了。从没连过任何设备才返回空。 - static String _nameForImage() { - if (besConnected) return BesBluetoothService.to.connectedDeviceName.value; - if (holderConnected) return HolderDeviceService.to.connectedName; - if (Get.isRegistered()) { - final n = HolderDeviceService.to.lastDeviceName; - if (n.isNotEmpty) return n; - } - if (Get.isRegistered() && - BesBluetoothService.to.hasPairedDevice) { - return BesBluetoothService.to.lastDeviceName; - } - return ''; - } + /// 断连后仍然认「最近连过的那台」是刻意的——用户拔掉耳机不代表他换了设备。 + static String _nameForImage() => _hub.lastKnownName; /// 是否曾经连过设备(用来决定断连时要不要把图压暗) - static bool get hasKnownDevice => _nameForImage().isNotEmpty; + static bool get hasKnownDevice => _hub.hasKnownDevice; } diff --git a/apps/client/lib/core/utils/version_compare.dart b/apps/client/lib/core/utils/version_compare.dart new file mode 100644 index 00000000..8c1d74f2 --- /dev/null +++ b/apps/client/lib/core/utils/version_compare.dart @@ -0,0 +1,34 @@ +/// 版本号比较,与服务端 `comm.CompareVersion` 同口径:按 `.` 切段、每段只取 +/// 前导数字(`3+4` → 3,`0-beta` → 0),逐段按整数比。 +/// +/// 用 `int.parse` 的写法遇到 `1.0.0-beta` / `1.2.3+4` 会直接抛,被外层 catch +/// 吞成「无更新」——表现是「明明有新版本却说已是最新」。 +class VersionCompare { + VersionCompare._(); + + static List split(String v) { + final s = v.trim(); + if (s.isEmpty) return const []; + return s.split('.').map((seg) { + final m = RegExp(r'^\d+').firstMatch(seg.trim()); + return m == null ? 0 : int.parse(m.group(0)!); + }).toList(); + } + + /// 负数:a < b;0:相等;正数:a > b + static int compare(String a, String b) { + final pa = split(a); + final pb = split(b); + if (pa.isEmpty || pb.isEmpty) return a.trim().compareTo(b.trim()); + final len = pa.length > pb.length ? pa.length : pb.length; + for (var i = 0; i < len; i++) { + final x = i < pa.length ? pa[i] : 0; + final y = i < pb.length ? pb[i] : 0; + if (x != y) return x > y ? 1 : -1; + } + return 0; + } + + /// [a] 是否比 [b] 新 + static bool isNewer(String a, String b) => compare(a, b) > 0; +} diff --git a/apps/client/lib/data/models/agent_module.dart b/apps/client/lib/data/models/agent_module.dart index 81afc0d4..314c49a8 100644 --- a/apps/client/lib/data/models/agent_module.dart +++ b/apps/client/lib/data/models/agent_module.dart @@ -5,8 +5,7 @@ import 'device_category.dart'; /// 功能模块(agent)定义。 /// /// AI 页与广场页共用同一份注册表:广场展示全部,AI 页只展示用户启用的那些, -/// 顺序由 [AgentModuleService] 持久化。新增 agent 只需往 [AgentModules.all] -/// 里加一条,两个页面自动生效。 +/// 顺序由 [AgentModuleService] 持久化。新增 agent 见 `lib/modules/module_registry.dart`。 class AgentModule { const AgentModule({ required this.id, @@ -16,6 +15,7 @@ class AgentModule { this.subtitle, this.requiresDevice = false, this.comingSoon = false, + this.bailianAppId, }); /// 唯一标识,持久化时存的就是它,改名会导致用户已有配置失效 @@ -36,6 +36,25 @@ class AgentModule { /// 尚未实现的占位模块:可以加到 AI 页排版,但点击只提示"敬请期待" final bool comingSoon; + + /// 这个模块用哪个百炼应用(app_id)。null = 用全局默认(EMAI 那个)。 + /// + /// **设备按键唤醒时用它决定接哪个助手**:`DeviceAiSessionService` 按 + /// 厂商 → 品类 → 默认编排第一个模块 → 这个字段,找到该说话的那个 agent。 + /// 车载香薰唤醒的是「Smartcar 车载助手」而不是 EMAI,就是靠这一条。 + /// + /// ⚠️ 放在 data 层的基类而不是 `AgentModuleDescriptor`(modules 层),是为了让 + /// `DeviceAiSessionService`(data 层)读得到 —— **data 层不反向依赖 modules 层**。 + final String? bailianAppId; +} + +/// 按模块 id 取它要接的百炼 app_id。查不到返回 null(用全局默认)。 +String? bailianAppIdForModule(String? moduleId) { + if (moduleId == null) return null; + for (final m in AgentModules.all) { + if (m.id == moduleId) return m.bailianAppId; + } + return null; } /// 全部可用模块的注册表 @@ -53,6 +72,9 @@ class AgentModules { /// EMAI 助手:原来 AI 页底部那颗悬浮球,改成广场里的一个正式 agent static const String emaiAssistant = 'emaiAssistant'; + + /// Smartcar 车载助手(车载香薰的对话 agent,另一个百炼应用) + static const String smartcarChat = 'smartcarChat'; static const String textTranslation = 'textTranslation'; static const String pictureTranslation = 'pictureTranslation'; @@ -61,106 +83,10 @@ class AgentModules { static const String englishStudy = 'englishStudy'; static const String kidsStory = 'kidsStory'; - static const List all = [ - AgentModule( - id: meeting, - title: 'agentMeeting', - subtitle: 'agentMeetingDesc', - icon: Icons.groups_2, - gradient: [Color(0xFFAB47BC), Color(0xFFEC407A)], - ), - AgentModule( - id: emaiAssistant, - title: 'agentEmai', - subtitle: 'agentEmaiDesc', - icon: Icons.auto_awesome, - gradient: [Color(0xFF5B8DEF), Color(0xFF7E57C2)], - ), - AgentModule( - id: simultaneous, - title: 'agentSimultaneous', - subtitle: 'agentSimultaneousDesc', - icon: Icons.record_voice_over, - gradient: [Color(0xFF4CAF50), Color(0xFF009688)], - ), - AgentModule( - id: faceToFace, - title: 'agentFaceToFace', - subtitle: 'agentFaceToFaceDesc', - icon: Icons.forum, - gradient: [Color(0xFF42A5F5), Color(0xFF1E88E5)], - ), - AgentModule( - id: callRecording, - title: 'agentCallRecording', - subtitle: 'agentCallRecordingDesc', - icon: Icons.fiber_manual_record, - gradient: [Color(0xFFEF5350), Color(0xFFE53935)], - requiresDevice: true, - ), - AgentModule( - id: fieldRecording, - title: 'agentFieldRecording', - // 有设备走设备录音通路,没设备退回手机麦克风,两种情况都能用 - subtitle: 'agentFieldRecordingDesc', - icon: Icons.mic, - gradient: [Color(0xFF26C6DA), Color(0xFF00838F)], - ), - AgentModule( - id: call, - title: 'agentCall', - subtitle: 'agentCallDesc', - icon: Icons.phone_in_talk, - gradient: [Color(0xFFFFA726), Color(0xFFFB8C00)], - requiresDevice: true, - ), - AgentModule( - id: audioVideo, - title: 'agentAudioVideo', - subtitle: 'agentAudioVideoDesc', - // 放映机图标:这个功能是音视频内容翻译,用投影/放映的意象更贴切 - icon: Icons.slideshow, - gradient: [Color(0xFF5C6BC0), Color(0xFF3949AB)], - ), - AgentModule( - id: textTranslation, - title: 'agentTextTranslation', - subtitle: 'agentTextTranslationDesc', - icon: Icons.translate, - gradient: [Color(0xFF26A69A), Color(0xFF00796B)], - ), - AgentModule( - id: pictureTranslation, - title: 'agentPictureTranslation', - subtitle: 'agentPictureTranslationDesc', - icon: Icons.image_search, - gradient: [Color(0xFFEC407A), Color(0xFFAD1457)], - ), - AgentModule( - id: englishChat, - title: 'agentEnglishChat', - subtitle: 'agentEnglishChatDesc', - icon: Icons.chat_bubble_outline, - gradient: [Color(0xFF7E57C2), Color(0xFF5E35B1)], - comingSoon: true, - ), - AgentModule( - id: englishStudy, - title: 'agentEnglishStudy', - subtitle: 'agentEnglishStudyDesc', - icon: Icons.menu_book, - gradient: [Color(0xFF29B6F6), Color(0xFF0288D1)], - comingSoon: true, - ), - AgentModule( - id: kidsStory, - title: 'agentKidsStory', - subtitle: 'agentKidsStoryDesc', - icon: Icons.auto_stories, - gradient: [Color(0xFFFF7043), Color(0xFFF4511E)], - comingSoon: true, - ), - ]; + /// 全部模块。由 `ModuleRegistry.install()` 在启动时注入——注册表本体在 + /// `lib/modules/module_registry.dart`(描述符要引用各模块的页面,只能放在 + /// modules 层;data 层不反向依赖它)。 + static List all = const []; /// AI 页首次进入时的默认模块。 /// @@ -187,11 +113,22 @@ class AgentModules { /// key 用的是 [DeviceCategories] 的品类 id。只在该品类首次连接时生效一次 /// (由 AgentModuleService 记录已应用过的品类),之后用户怎么增删排序都不再覆盖。 static const Map> defaultsByCategory = { - // AI手机支架 / AI录音卡片:只有录音相关能力,AI 页就只留这三个 - DeviceCategories.phoneHolder: [meeting, fieldRecording, callRecording], + // AI手机支架(EaiRec):连上后 AI 页默认就这三个 —— 语音纪要 / 现场录音 / + // EMAI助手。**不含通话录音**:支架没有接管通话音频的能力,摆在这儿点进去 + // 也用不了。 + DeviceCategories.phoneHolder: [meeting, fieldRecording, emaiAssistant], + // AI录音卡片是另一条产品线,保持原编排不动。 DeviceCategories.noteCard: [meeting, fieldRecording, callRecording], // AI耳机(恒玄):通话 + 翻译整套都能跑,铺开全量默认编排 DeviceCategories.earphone: defaultEnabled, + // AI车载香薰(Smartcar):随时开聊 + 现场录音 + 语音纪要。 + // 这三个都不依赖设备能力(只有通话录音/翻译才声明 requiredCapabilities), + // 所以连上香薰就能直接用,不会灰。 + // ⚠️ 这是**默认编排不是权限限制**——用户仍可去广场把别的功能加回来, + // 这是产品有意接受的(落地文档 6.5)。 + // ⚠️ 2026-09-11 从「只有 smartcarChat」改成这三个;已经铺过旧编排的装机 + // 由 AgentModuleService 的一次性补铺处理,见那边的 _migrateCarAromaDefaults。 + DeviceCategories.carAroma: [smartcarChat, fieldRecording, meeting], }; static List defaultsForCategory(String? categoryId) { diff --git a/apps/client/lib/data/models/appconfig.dart b/apps/client/lib/data/models/appconfig.dart index 660862b0..bc78f95b 100644 --- a/apps/client/lib/data/models/appconfig.dart +++ b/apps/client/lib/data/models/appconfig.dart @@ -49,11 +49,6 @@ class AppConfig { return names; } - static List allproductUuids() { - List uuids = config.products.map((user) => user.scanuuid).toList(); - return uuids; - } - /// 根据产品名称获取产品配置,查不到返回 null。 /// /// ⚠️ **不要改回 `firstWhere`**:它没有 orElse,查不到时抛 StateError 而不是 diff --git a/apps/client/lib/data/models/appconfig_model.dart b/apps/client/lib/data/models/appconfig_model.dart index 788289e6..fff97e95 100644 --- a/apps/client/lib/data/models/appconfig_model.dart +++ b/apps/client/lib/data/models/appconfig_model.dart @@ -3,11 +3,19 @@ import 'package:get/get.dart'; part 'appconfig_model.g.dart'; // 生成的文件名 +/// ⚠️ 每个非空字段都带 `defaultValue`:服务端少下发一个键时用默认值, +/// **而不是**整个 fromJson 抛 TypeError 让产品表/设备列表整体空白 +/// (见 CLAUDE.md「客户端模型是手写镜像」那一段踩过的坑)。 +/// 契约测试在 test/appconfig_model_test.dart。 @JsonSerializable() class UserGetAppConfigResp { + @JsonKey(defaultValue: {}) final Map env; + @JsonKey(defaultValue: []) final List agents; + @JsonKey(defaultValue: {}) final Map mcps; + @JsonKey(defaultValue: []) final List products; UserGetAppConfigResp( @@ -23,12 +31,19 @@ class UserGetAppConfigResp { @JsonSerializable() class DBAgent { + @JsonKey(defaultValue: '') final String id; + @JsonKey(defaultValue: '') final String name; + @JsonKey(defaultValue: '') final String avatarUrl; + @JsonKey(defaultValue: '') final String description; + @JsonKey(defaultValue: '') final String tag; + @JsonKey(defaultValue: false) final bool isOnline; + @JsonKey(defaultValue: '') final String voice; final String? welcomeMessage; final String? voiceWelcomeMessage; @@ -56,9 +71,13 @@ class DBAgent { @JsonSerializable() class DBMCPServer { + @JsonKey(defaultValue: '') final String servername; + @JsonKey(defaultValue: '') final String url; + @JsonKey(defaultValue: 0) final int type; + @JsonKey(defaultValue: '') final String tools; DBMCPServer({ required this.servername, @@ -74,12 +93,19 @@ class DBMCPServer { @JsonSerializable() class DBProduct { + @JsonKey(defaultValue: 0) final int id; + @JsonKey(defaultValue: 0) final int factoryid; + /// 服务端已废弃(恒为 0),只为老包兼容保留 + @JsonKey(defaultValue: 0) final int devicetype; + @JsonKey(defaultValue: '') final String devicename; final String? productimage; - final String scanuuid; + // ⚠️ scanuuid 已于 2026-09-08 删除:设备校验早就改成按 MAC 走,绑定奖励也是按 MAC 判 + // 「这台设备有没有被绑过」,跟这个 UUID 没关系。服务端仍会下发这个键(恒为空串, + // 只为老 App 包不炸),新端直接不解析。 final String? version; bool? isforceupdate; @@ -103,7 +129,6 @@ class DBProduct { required this.devicetype, required this.devicename, required this.productimage, - required this.scanuuid, required this.version, required this.isforceupdate, //该产品固件版本是否强制更新 this.updateonmismatch, //可选:老服务端不下发这个字段,缺省即 null→按 false diff --git a/apps/client/lib/data/models/appconfig_model.g.dart b/apps/client/lib/data/models/appconfig_model.g.dart index e776602a..879b442f 100644 --- a/apps/client/lib/data/models/appconfig_model.g.dart +++ b/apps/client/lib/data/models/appconfig_model.g.dart @@ -9,16 +9,23 @@ part of 'appconfig_model.dart'; UserGetAppConfigResp _$UserGetAppConfigRespFromJson( Map json) => UserGetAppConfigResp( - env: Map.from(json['env'] as Map), - agents: (json['agents'] as List) - .map((e) => DBAgent.fromJson(e as Map)) - .toList(), - mcps: (json['mcps'] as Map).map( - (k, e) => MapEntry(k, DBMCPServer.fromJson(e as Map)), - ), - products: (json['products'] as List) - .map((e) => DBProduct.fromJson(e as Map)) - .toList(), + env: (json['env'] as Map?)?.map( + (k, e) => MapEntry(k, e as String), + ) ?? + {}, + agents: (json['agents'] as List?) + ?.map((e) => DBAgent.fromJson(e as Map)) + .toList() ?? + [], + mcps: (json['mcps'] as Map?)?.map( + (k, e) => + MapEntry(k, DBMCPServer.fromJson(e as Map)), + ) ?? + {}, + products: (json['products'] as List?) + ?.map((e) => DBProduct.fromJson(e as Map)) + .toList() ?? + [], ); Map _$UserGetAppConfigRespToJson( @@ -31,13 +38,13 @@ Map _$UserGetAppConfigRespToJson( }; DBAgent _$DBAgentFromJson(Map json) => DBAgent( - id: json['id'] as String, - name: json['name'] as String, - avatarUrl: json['avatarUrl'] as String, - description: json['description'] as String, - tag: json['tag'] as String, - isOnline: json['isOnline'] as bool, - voice: json['voice'] as String, + id: json['id'] as String? ?? '', + name: json['name'] as String? ?? '', + avatarUrl: json['avatarUrl'] as String? ?? '', + description: json['description'] as String? ?? '', + tag: json['tag'] as String? ?? '', + isOnline: json['isOnline'] as bool? ?? false, + voice: json['voice'] as String? ?? '', welcomeMessage: json['welcomeMessage'] as String?, voiceWelcomeMessage: json['voiceWelcomeMessage'] as String?, systemPrompt: json['systemPrompt'] as String?, @@ -59,10 +66,10 @@ Map _$DBAgentToJson(DBAgent instance) => { }; DBMCPServer _$DBMCPServerFromJson(Map json) => DBMCPServer( - servername: json['servername'] as String, - url: json['url'] as String, - type: (json['type'] as num).toInt(), - tools: json['tools'] as String, + servername: json['servername'] as String? ?? '', + url: json['url'] as String? ?? '', + type: (json['type'] as num?)?.toInt() ?? 0, + tools: json['tools'] as String? ?? '', ); Map _$DBMCPServerToJson(DBMCPServer instance) => @@ -74,12 +81,11 @@ Map _$DBMCPServerToJson(DBMCPServer instance) => }; DBProduct _$DBProductFromJson(Map json) => DBProduct( - id: (json['id'] as num).toInt(), - factoryid: (json['factoryid'] as num).toInt(), - devicetype: (json['devicetype'] as num).toInt(), - devicename: json['devicename'] as String, + id: (json['id'] as num?)?.toInt() ?? 0, + factoryid: (json['factoryid'] as num?)?.toInt() ?? 0, + devicetype: (json['devicetype'] as num?)?.toInt() ?? 0, + devicename: json['devicename'] as String? ?? '', productimage: json['productimage'] as String?, - scanuuid: json['scanuuid'] as String, version: json['version'] as String?, isforceupdate: json['isforceupdate'] as bool?, updateonmismatch: json['updateonmismatch'] as bool?, @@ -96,7 +102,6 @@ Map _$DBProductToJson(DBProduct instance) => { 'devicetype': instance.devicetype, 'devicename': instance.devicename, 'productimage': instance.productimage, - 'scanuuid': instance.scanuuid, 'version': instance.version, 'isforceupdate': instance.isforceupdate, 'updateonmismatch': instance.updateonmismatch, diff --git a/apps/client/lib/data/models/assistant_directive.dart b/apps/client/lib/data/models/assistant_directive.dart index 7bcb2358..ca815e54 100644 --- a/apps/client/lib/data/models/assistant_directive.dart +++ b/apps/client/lib/data/models/assistant_directive.dart @@ -4,6 +4,10 @@ import 'package:get/get.dart'; import 'memory_item.dart'; +/// 端侧指令处理器:由各能力模块注册,处理完自己把 [AssistantDirective.status] +/// / `note` 填好(见 `AssistantDirectiveService.registerHandlers`)。 +typedef DirectiveHandler = void Function(AssistantDirective directive); + /// 助手指令:百炼多模态在 `RespondingContent.extra_info.tool_calls` 里下发的 /// 端侧函数调用。 /// @@ -90,7 +94,10 @@ class AssistantDirective { final extra = output['extra_info']; if (extra is! Map) return const []; final calls = extra['tool_calls']; - if (calls is! List || calls.isEmpty) return const []; + final commands = extra['commands']; + final hasCalls = calls is List && calls.isNotEmpty; + final hasCommands = commands is List && commands.isNotEmpty; + if (!hasCalls && !hasCommands) return const []; final dialogId = (output['dialog_id'] ?? '').toString(); final roundId = (output['round_id'] ?? '').toString(); @@ -98,6 +105,16 @@ class AssistantDirective { final now = DateTime.now(); final result = []; + if (!hasCalls) { + _appendCommands(commands, result, + dialogId: dialogId, + roundId: roundId, + llmRequestId: llmRequestId, + source: source, + now: now, + replyText: (output['text'] ?? '').toString()); + return result; + } for (var i = 0; i < calls.length; i++) { final call = calls[i]; if (call is! Map) continue; @@ -130,9 +147,77 @@ class AssistantDirective { replyText: (output['text'] ?? '').toString(), )); } + if (hasCommands) { + _appendCommands(commands, result, + dialogId: dialogId, + roundId: roundId, + llmRequestId: llmRequestId, + source: source, + now: now, + replyText: (output['text'] ?? '').toString()); + } return result; } + /// 解析 `extra_info.commands` —— **另一种指令形状**。 + /// + /// ⚠️ 2026-09-11 真机发现:Smartcar 车载助手下发的指令不在 `tool_calls` 里, + /// 而是 `extra_info.commands`,形如 + /// ```json + /// "commands":[{"intent_info":{"domain":"general_command","intent":"quit"}, + /// "name":"quit","params":[]}] + /// ``` + /// 只解析 `tool_calls` 的话这里恒为 0 条 —— 表现就是"AI 说好的已经关闭了, + /// 但实际什么都没发生"。两种形状都要认,且**不能互斥**:同一帧可能都带。 + static void _appendCommands( + List commands, + List out, { + required String dialogId, + required String roundId, + required String llmRequestId, + required String source, + required DateTime now, + required String replyText, + }) { + for (var i = 0; i < commands.length; i++) { + final c = commands[i]; + if (c is! Map) continue; + final name = (c['name'] ?? '').toString(); + if (name.isEmpty) continue; + + // params 形状没有文档,实测是空数组。能转成 Map 就转,转不成就原样留着, + // 别为了凑格式把信息丢了。 + final params = c['params']; + final args = {}; + if (params is Map) { + args.addAll(params.cast()); + } else if (params is List) { + for (final p in params) { + if (p is Map && p['name'] != null) { + args[p['name'].toString()] = p['value']; + } + } + } + final intent = c['intent_info']; + if (intent is Map && intent['intent'] != null) { + args.putIfAbsent('intent', () => intent['intent']); + } + + out.add(AssistantDirective( + id: '${roundId.isEmpty ? now.microsecondsSinceEpoch : roundId}#cmd$i', + name: name, + args: args, + rawArguments: json.encode(c), + dialogId: dialogId, + roundId: roundId, + llmRequestId: llmRequestId, + source: source, + createdAt: now, + replyText: replyText, + )); + } + } + Map toJson() => { 'id': id, 'name': name, diff --git a/apps/client/lib/data/models/device_category.dart b/apps/client/lib/data/models/device_category.dart index 6bb8b5a8..b6e0f6e6 100644 --- a/apps/client/lib/data/models/device_category.dart +++ b/apps/client/lib/data/models/device_category.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'appconfig.dart'; import 'appconfig_model.dart'; +import 'device_images.dart'; /// 「添加设备」第一步要用户选的产品品类。 /// @@ -58,17 +59,21 @@ class DeviceCategories { static const String studyMachine = 'studyMachine'; static const String noteCard = 'noteCard'; + /// AI车载香薰(Smartcar)。2026-09-08 新增。 + static const String carAroma = 'carAroma'; + // ⚠️ 这里原来有一组写死的图片常量(earphoneImage / earphoneIconImage / // noteCardImage / phoneHolderImage)和一个按关键字猜图的 imageForDeviceName()。 // 已全部删除:取图改成「按设备名找 <设备名>.png / <设备名>_icon.png」, // 统一在 [DeviceImages]。加新产品只要按这个命名把图丢进 // assets/images/devices/ 即可,不用再回这里加一条映射。 - // ⚠️ 下面的 deviceTypes / nameKeywords 是按服务端现有产品数据推测的, - // 需要产品侧确认后再定稿。未配置的品类会退回扫描全部 UUID。 + // ⚠️ **deviceTypes 这个筛选条件已经失效**:服务端 DBProduct.devicetype 于 + // 2026-09-08 废弃,下发的值恒为 0,再也匹配不到 1/2/3。留着字段只为不动 + // 老数据结构,**新品类一律用 nameKeywords 圈定**。圈不到时 productsOf 返回空。 // - // 「选择设备」页当前只上架 AI耳机(恒玄)这一条品类,手机支架暂时下架到 - // [hidden](2026-08-26),要恢复直接把条目挪回 all 即可。 + // 「选择设备」页当前上架三条:AI耳机(恒玄)、AI手机支架(EaiRec)、AI车载香薰(Smartcar)。 + // 下架某条 = 把它挪回 [hidden]。 static const List all = [ DeviceCategory( id: earphone, @@ -76,11 +81,32 @@ class DeviceCategories { subtitle: 'catEarphoneDesc', icon: Icons.headphones, gradient: [Color(0xFFAB47BC), Color(0xFF7B1FA2)], - deviceTypes: [ - 1, // classicBluetoothHeadset - 2, // bleBluetoothDoubleHeadset - 3, // bleBluetoothSingleHeadset - ], + imageAsset: '${DeviceImages.dir}Echo-one.png', + // deviceTypes 已失效(见上),耳机改由名字圈定 + nameKeywords: ['echo-one', 'deepvoice', 'deepsound', 'buds', 'ai80', 'a80'], + ), + // AI手机支架 = EaiRec(EAIMAR 圆盘)。2026-09-08 上架,取代原先挂在这个 + // 品类下、已停售的EaiRec Echomeet 支架 —— 所以沿用 phoneHolder 这个 id: + // AI 页的默认功能编排(会议/现场录音/通话录音)本来就是按它配的,换 id 要一起改。 + // ⚠️ 蓝牙链路还没接,点击不进扫描页(见 device_category_view._openCategory)。 + DeviceCategory( + id: phoneHolder, + title: 'catPhoneHolder', + subtitle: 'catPhoneHolderDesc', + icon: Icons.stay_current_portrait, + gradient: [Color(0xFF42A5F5), Color(0xFF1E88E5)], + imageAsset: '${DeviceImages.dir}EaiRec.png', + nameKeywords: ['echomeet', 'eairec', 'eaimar', '支架', 'holder', 'stand'], + ), + // AI车载香薰 = Smartcar。2026-09-08 新增,蓝牙链路同样未接。 + DeviceCategory( + id: carAroma, + title: 'catCarAroma', + subtitle: 'catCarAromaDesc', + icon: Icons.air, + gradient: [Color(0xFFFFB74D), Color(0xFFE65100)], + imageAsset: '${DeviceImages.dir}Smartcar.png', + nameKeywords: ['smartcar', '车载', '香薰', 'aroma', 'diffuser'], ), ]; @@ -89,15 +115,8 @@ class DeviceCategories { /// 只是不展示,定义都留着:AI 页的默认功能编排([AgentModules.defaultsByCategory]) /// 和主图映射还按 id 引用它们,老用户存下来的数据也要能查得到, /// 所以 [byId] 仍然会在这里查。上架时把条目挪回 [all] 就行。 + // 注:phoneHolder 已于 2026-09-08 挪到 [all] 上架(产品换成 EaiRec)。 static const List hidden = [ - DeviceCategory( - id: phoneHolder, - title: 'catPhoneHolder', - subtitle: 'catPhoneHolderDesc', - icon: Icons.stay_current_portrait, - gradient: [Color(0xFF42A5F5), Color(0xFF1E88E5)], - nameKeywords: ['支架', 'holder', 'stand', 'echomeet'], - ), DeviceCategory( id: noteCard, title: 'catNoteCard', @@ -157,21 +176,7 @@ class DeviceCategories { }).toList(growable: false); } - /// 扫描该品类时要下发给 BLE SDK 的 UUID 列表。 - /// - /// 圈不出产品(品类没配筛选条件,或服务端产品表里暂时没有这类产品)时 - /// 返回全部 UUID —— 宁可多扫,也不能让用户扫不到自己的设备。 - static List scanUuidsFor(String? categoryId) { - if (!AppConfig.isInitialized()) return const []; - final category = byId(categoryId); - if (category == null) return AppConfig.allproductUuids(); - - final uuids = productsOf(category) - .map((p) => p.scanuuid) - .where((u) => u.isNotEmpty) - .toSet() - .toList(growable: false); - - return uuids.isEmpty ? AppConfig.allproductUuids() : uuids; - } + // ⚠️ 这里原来有个 scanUuidsFor(categoryId),按品类把产品的 scanuuid 拼成 BLE 扫描 + // 白名单。scanuuid 已于 2026-09-08 整体废弃(设备校验与绑定奖励都改成按 MAC 判定), + // 扫描不再做 UUID 过滤,改由扫到之后按名字/品类筛。 } diff --git a/apps/client/lib/data/models/goods.dart b/apps/client/lib/data/models/goods.dart index 0738a7a6..f0cb6812 100644 --- a/apps/client/lib/data/models/goods.dart +++ b/apps/client/lib/data/models/goods.dart @@ -13,9 +13,10 @@ enum UsageType { Meet, // 2 /// 智能体 AI, // 3 - /// 智能体 - Vip; // 4 - /// Vip + /// VIP 时长 + Vip, // 4 + /// 算力包(2026-09 起;商品的 compute 字段即本次发放量,归账号、不过期) + Compute; // 5 // 解析支持 int 或 string(大小写不敏感) static UsageType from(dynamic value) { @@ -31,6 +32,8 @@ enum UsageType { return UsageType.AI; case 4: return UsageType.Vip; + case 5: + return UsageType.Compute; default: return UsageType.UsageNull; } @@ -52,6 +55,8 @@ enum UsageType { return UsageType.AI; case 'vip': return UsageType.Vip; + case 'compute': + return UsageType.Compute; default: return UsageType.UsageNull; } @@ -71,6 +76,8 @@ enum UsageType { return 3; case UsageType.Vip: return 4; + case UsageType.Compute: + return 5; } } @@ -86,6 +93,8 @@ enum UsageType { return 'AI'; case UsageType.Vip: return 'Vip'; + case UsageType.Compute: + return 'Compute'; } } } @@ -107,6 +116,13 @@ class DBGoods { final UsageType usagetype; final int usagenum; + /// 本商品发放的算力(服务端 DBGoods.compute,2026-09 起)。 + /// 老商品没配就是 0,服务端发货时会把旧资源点按换算系数折成算力,这里只用于展示。 + final int compute; + + /// 本商品发放的 VIP 天数(服务端 DBGoods.viptime)。 + final int viptime; + const DBGoods({ required this.id, required this.enable, @@ -115,6 +131,8 @@ class DBGoods { required this.price, required this.usagetype, required this.usagenum, + this.compute = 0, + this.viptime = 0, }); /// 解析后端 JSON @@ -150,6 +168,8 @@ class DBGoods { price: _asInt(json['price']), usagetype: UsageType.from(json['usagetype']), usagenum: _asInt(json['usagenum']), + compute: _asInt(json['compute']), + viptime: _asInt(json['viptime']), ); } @@ -163,6 +183,8 @@ class DBGoods { 'price': price, 'usagetype': usagetype.toInt, 'usagenum': usagenum, + 'compute': compute, + 'viptime': viptime, }; } diff --git a/apps/client/lib/data/models/user_Info.dart b/apps/client/lib/data/models/user_Info.dart index b6075d48..8ebdc864 100644 --- a/apps/client/lib/data/models/user_Info.dart +++ b/apps/client/lib/data/models/user_Info.dart @@ -288,4 +288,22 @@ class UserDevice { 'license': license, 'cmei': cmei, }; + + /// 这台设备有没有「值得展示」的授权码。 + /// + /// ⚠️ 光判非空不够:服务端绑定时写回的是**从设备表查到的** code + /// (`api_binddevice.go` 的 `License: model.Code`,不是客户端传的空串), + /// 而后台「导入 MAC」模式建的记录,`code` 就是 MAC 串本身 + /// (`device_mac` 合表迁移里 `code := devicemac`)。于是界面上会出现 + /// **MAC 一行、授权码一行、两行值一模一样**,看着像显示了两个 MAC。 + /// 这种占位值不展示;真授权码(如 `71E5E5C3A797C043B5A7`)照常展示。 + /// + /// ⚠️ 规则只放这一份:设备页和「我的设备」页都用它,各写各的必然走岔。 + bool get hasRealLicense { + final lic = license.trim(); + if (lic.isEmpty) return false; + String norm(String v) => + v.replaceAll(':', '').replaceAll('-', '').toUpperCase(); + return norm(lic) != norm(devicemac); + } } diff --git a/apps/client/lib/data/services/account_service.dart b/apps/client/lib/data/services/account_service.dart index 73f1a444..92418fd4 100644 --- a/apps/client/lib/data/services/account_service.dart +++ b/apps/client/lib/data/services/account_service.dart @@ -10,7 +10,7 @@ import 'db/database_helper.dart'; import '../../data/models/user_Info.dart'; import 'meeting/meeting_upload_service.dart'; import '../../core/utils/toast_throttle.dart'; -import 'bes_device_auth.dart'; +import '../../devices/device_auth.dart'; import 'mcp_token_service.dart'; import 'memory_reminder_scheduler.dart'; import 'memory_service.dart'; @@ -43,7 +43,7 @@ class AccountService extends GetxService { User.clearUserSession(); // 换账号后同一台耳机要重新登记到新账号名下, // 不清这个 set 的话「本进程已登记过」会把新账号的绑定吞掉。 - BesDeviceAuth.reset(); + DeviceAuth.reset(); // MCP 令牌是按 uid 签的:不清的话新账号会拿着上一个人的令牌去调 MCP, // 读到的是别人的会议纪要和待办。 McpTokenService.reset(); @@ -70,7 +70,7 @@ class AccountService extends GetxService { try { await _storage.erase(); User.clearUserSession(); - BesDeviceAuth.reset(); + DeviceAuth.reset(); McpTokenService.reset(); if (Get.isRegistered()) { MemoryService.to.clear(); diff --git a/apps/client/lib/data/services/agent_module_defaults.dart b/apps/client/lib/data/services/agent_module_defaults.dart index d663fc0f..563afba4 100644 --- a/apps/client/lib/data/services/agent_module_defaults.dart +++ b/apps/client/lib/data/services/agent_module_defaults.dart @@ -1,35 +1,58 @@ +import 'package:device_plugin_interface/device_plugin_interface.dart'; import 'package:get/get.dart'; +import '../../devices/device_hub.dart'; +import '../../devices/device_vendors.dart'; +import '../models/agent_module.dart'; import '../models/device_category.dart'; import 'agent_module_service.dart'; -/// 设备品类首次连接时,把该品类的默认功能铺到 AI 页。 +/// 设备品类**首次连接成功**时,把该品类的默认功能铺到 AI 页。 /// -/// AgentModuleService 是 MainTabBinding 里 put 的,蓝牙服务可能比它先跑, -/// 没注册就先建出来(permanent,和 MainTabBinding 里的守卫互不冲突)。 -void applyAgentDefaultsFor(String categoryId) { - try { - final service = Get.isRegistered() - ? AgentModuleService.to - : Get.put(AgentModuleService(), permanent: true); - service.applyDeviceDefaults(categoryId); - } catch (_) { - // 铺默认功能失败不能影响连接本身 - } -} - -/// 便捷别名,避免各处再去 import device_category +/// 挂在 [DeviceHub.sessions] 上,谁上线就按厂商 → 品类映射铺一次; +/// 「只铺一次」由 [AgentModuleService.applyDeviceDefaults] 记录。 class AgentDefaults { AgentDefaults._(); - static void onHolderConnected() => - applyAgentDefaultsFor(DeviceCategories.phoneHolder); + static const Map _vendorCategory = { + DeviceVendors.bes: DeviceCategories.earphone, + DeviceVendors.holder: DeviceCategories.phoneHolder, + DeviceVendors.smartcar: DeviceCategories.carAroma, + }; + + /// 厂商 → 品类。设备按键唤醒时用它找该接哪个 agent(见 + /// `DeviceAiSessionService._resolveAgentAppId`)。 + static String? categoryForVendor(String vendor) => _vendorCategory[vendor]; - static void onEarphoneConnected() => - applyAgentDefaultsFor(DeviceCategories.earphone); + /// 这个品类默认该由哪个 agent 接管对话 —— 取默认编排里的第一个模块。 + /// 找不到返回 null,调用方回退到全局默认(EMAI)。 + static String? primaryModuleForVendor(String vendor) { + final cat = _vendorCategory[vendor]; + if (cat == null) return null; + final list = AgentModules.defaultsForCategory(cat); + return list.isEmpty ? null : list.first; + } + + static Worker? _worker; + + static void bind(DeviceHub hub) { + _worker?.dispose(); + _worker = ever>(hub.sessions, (list) { + for (final s in list) { + final cat = _vendorCategory[s.vendor]; + if (cat != null) applyAgentDefaultsFor(cat); + } + }); + } - static void onJieliConnected(String? categoryId) { - if (categoryId == null || categoryId.isEmpty) return; - applyAgentDefaultsFor(categoryId); + static void applyAgentDefaultsFor(String categoryId) { + try { + final service = Get.isRegistered() + ? AgentModuleService.to + : Get.put(AgentModuleService(), permanent: true); + service.applyDeviceDefaults(categoryId); + } catch (_) { + // 铺默认功能失败不能影响连接本身 + } } } diff --git a/apps/client/lib/data/services/agent_module_service.dart b/apps/client/lib/data/services/agent_module_service.dart index 76c0f985..22279da8 100644 --- a/apps/client/lib/data/services/agent_module_service.dart +++ b/apps/client/lib/data/services/agent_module_service.dart @@ -16,6 +16,10 @@ class AgentModuleService extends GetxService { /// 已经应用过默认编排的设备品类 id,保证「第一次连接」只铺一次 static const String _appliedCategoriesKey = 'ai_tab_device_defaults_applied'; + /// 上一次**自动铺**下去的编排清单。用来判断用户有没有自己动过, + /// 见 [applyDeviceDefaults]。 + static const String _lastAppliedKey = 'ai_tab_device_defaults_last'; + final GetStorage _storage = GetStorage(); /// AI 页当前展示的模块 id,顺序即展示顺序 @@ -140,35 +144,53 @@ class AgentModuleService extends GetxService { return i == query.length; } - /// 某个设备品类**第一次连接成功**时铺开它的默认功能。 + /// 连上某品类的设备时,把 AI 页铺成这个品类的默认编排。 + /// + /// 规则只有一条:**只要用户没自己动过编排,AI 页就跟着当前设备走**。 + /// 于是「连上车载香薰 → 只剩 Smartcar / 现场录音 / 语音纪要」「换回耳机 → 恢复全量」 + /// 都成立,而用户一旦增删或排序过,就再也不会被自动改动。 + /// + /// 判据是 [_lastAppliedKey]:上一次**自动铺**下去的那份清单。 + /// 当前编排和它逐项相同 = 用户没动过;不同 = 动过,直接放手。 /// - /// - 只生效一次:品类 id 记在 [_appliedCategoriesKey] 里,之后再连同类设备 - /// 不会覆盖用户自己的增删和排序; - /// - 采用「补齐」而不是「替换」:用户已有的模块和顺序原样保留, - /// 缺的按品类默认顺序追加到后面。 + /// ⚠️ 2026-09-11 之前的规则是「每个品类只铺一次」,切设备时编排不跟着换—— + /// 表现是先连耳机(铺 11 个)再连香薰,香薰的三个编排永远铺不上。 + /// 别改回去。 /// - /// 三条蓝牙链路(蓝讯支架 / 恒玄耳机 / 杰理)连上后各自调用它, - /// 传自己的 [DeviceCategories] 品类 id。 + /// ⚠️ 老装机没有 [_lastAppliedKey] 这条记录,无法判断有没有动过, + /// 按「允许铺一次」处理:升级后第一次连设备会按品类重铺一次 AI 页。 + /// + /// 采用**整套替换**而不是追加:支架/香薰只有录音与开聊,AI 页就该只剩那几个; + /// 耳机能跑通话和翻译,就铺全量。追加式做不到「只显示这几个」。 bool applyDeviceDefaults(String? categoryId) { final defaults = AgentModules.defaultsForCategory(categoryId); - if (defaults.isEmpty) return false; + if (defaults.isEmpty || categoryId == null) return false; - final applied = (_storage.read(_appliedCategoriesKey) ?? const []) - .map((e) => e.toString()) - .toList(); - if (applied.contains(categoryId)) return false; - - // 按该设备的能力**整套铺开**,而不是往用户现有编排上追加: - // 支架/录音卡片只有录音能力,AI 页就该只剩三个;耳机能跑通话和翻译, - // 就铺全量。追加式做不到「只显示」这个要求。 final next = defaults .where((id) => AgentModules.byId(id) != null) .toList(growable: false); + if (next.isEmpty) return false; + + final hasRecord = _storage.hasData(_lastAppliedKey); + if (hasRecord) { + final last = (_storage.read(_lastAppliedKey) ?? const []) + .map((e) => e.toString()) + .toList(); + // 用户动过编排 → 不再自动改动 + if (!_sameOrder(enabledIds, last)) return false; + } + final changed = !_sameOrder(enabledIds, next); if (changed) enabledIds.assignAll(next); + _storage.write(_lastAppliedKey, next); - applied.add(categoryId!); - _storage.write(_appliedCategoriesKey, applied); + final applied = (_storage.read(_appliedCategoriesKey) ?? const []) + .map((e) => e.toString()) + .toList(); + if (!applied.contains(categoryId)) { + applied.add(categoryId); + _storage.write(_appliedCategoriesKey, applied); + } if (changed) _persist(); return changed; } diff --git a/apps/client/lib/data/services/assistant_directive_service.dart b/apps/client/lib/data/services/assistant_directive_service.dart index 578e4918..b6738a45 100644 --- a/apps/client/lib/data/services/assistant_directive_service.dart +++ b/apps/client/lib/data/services/assistant_directive_service.dart @@ -43,6 +43,14 @@ class AssistantDirectiveService extends GetxService { final GetStorage _storage = GetStorage(); + /// 各能力模块注册的指令处理器(`ModuleRegistry.directiveHandlers`)。 + /// 查不到的指令走 [_dispatch] 里的内置处理(SET_clock)或记 unsupported。 + final Map _handlers = {}; + + void registerHandlers(Map handlers) { + _handlers.addAll(handlers); + } + /// 指令流水,新的在前 final RxList directives = [].obs; @@ -98,6 +106,17 @@ class AssistantDirectiveService extends GetxService { return; } + final h = _handlers[d.name]; + if (h != null) { + try { + h(d); + } catch (e) { + d.status = DirectiveStatus.failed; + d.note = '模块处理失败: $e'; + Logger.e(_tag, '指令 ${d.name} 处理失败: $e'); + } + return; + } switch (d.name) { case 'SET_clock': _handleSetClock(d); diff --git a/apps/client/lib/data/services/bailian_multimodal_service.dart b/apps/client/lib/data/services/bailian_multimodal_service.dart index 4c30e7f5..8b63d86a 100644 --- a/apps/client/lib/data/services/bailian_multimodal_service.dart +++ b/apps/client/lib/data/services/bailian_multimodal_service.dart @@ -87,7 +87,26 @@ class BailianEvent { /// - `ALIBABA_OPENSPEECH_APP_KEY`:DashScope API Key(与语音翻译、拍照翻译共用),**没有默认值** /// - `ALIBABA_BAILIAN_WORKSPACE_ID`:业务空间 ID,默认 [_defaultWorkspaceId] /// - `ALIBABA_BAILIAN_APP_ID`:多模态应用 ID,默认 [_defaultAppId] +/// +/// ## 一个应用一个实例 +/// +/// [appId] / [workspaceId] 传了就用传的,**不传(默认)完全走上面那套全局配置**—— +/// 也就是说 EMAI 与设备唤醒会话的行为一个字节都没变。 +/// +/// 之所以做成实例级而不是改全局:不同 agent 用的是百炼里不同的应用 +/// (EMAI 一个、Smartcar 车载助手另一个),改全局值会把所有 agent 一起换掉。 +/// +/// ⚠️ 每个应用**必须各自 new 一个实例**,不能共用:`start()` 第一件事就是 `stop()`, +/// 共用会让两边互相把对方的会话掐掉,下行音频还会串到对方的播放器上。 class BailianMultimodalService extends GetxService { + BailianMultimodalService({String? appId, String? workspaceId}) + : _appIdOverride = appId, + _workspaceIdOverride = workspaceId; + + /// 实例级覆盖;null/空 = 用全局配置 + final String? _appIdOverride; + final String? _workspaceIdOverride; + static const String _tag = 'BailianMultimodal'; static BailianMultimodalService get to => Get.find(); @@ -132,11 +151,15 @@ class BailianMultimodalService extends GetxService { String get _apiKey => AppConfig.env('ALIBABA_OPENSPEECH_APP_KEY') ?? ''; String get _workspaceId { + final o = _workspaceIdOverride?.trim() ?? ''; + if (o.isNotEmpty) return o; final v = (AppConfig.env('ALIBABA_BAILIAN_WORKSPACE_ID') ?? '').trim(); return v.isEmpty ? _defaultWorkspaceId : v; } String get _appId { + final o = _appIdOverride?.trim() ?? ''; + if (o.isNotEmpty) return o; final v = (AppConfig.env('ALIBABA_BAILIAN_APP_ID') ?? '').trim(); return v.isEmpty ? _defaultAppId : v; } diff --git a/apps/client/lib/data/services/device_ai_session_service.dart b/apps/client/lib/data/services/device_ai_session_service.dart new file mode 100644 index 00000000..3d2bad31 --- /dev/null +++ b/apps/client/lib/data/services/device_ai_session_service.dart @@ -0,0 +1,666 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:get/get.dart'; + +import '../../core/utils/logger.dart'; +import '../../devices/device_hub.dart'; +import '../models/agent_module.dart'; +import '../models/emai_message.dart'; +import '../models/user_Info.dart' as user_info; +import '../utils/cue_tone.dart'; +import 'agent_module_defaults.dart'; +import 'assistant_directive_service.dart'; +import 'bailian_multimodal_service.dart'; +import 'emai_chat_store.dart'; +import 'mcp_token_service.dart'; + +/// 设备按键唤醒的 AI 实时对话会话——**厂商无关**,要求设备具备 +/// [DeviceCapability.aiWake]。 +/// +/// 把「设备按键唤醒」接到阿里百炼多模态上:设备麦的音频由插件解码成 16k PCM +/// (`openMic(ai)`)推给百炼,百炼回的 16k PCM 交给 `openSpeaker(ai)` 由插件/原生 +/// 编码后按节奏发回设备播放。整条链路上这里只搬运 PCM。 +/// +/// **握手是设备主导的**,App 只能应答(恒玄时序,其它厂商在插件里对齐到同一语义): +/// ``` +/// 设备按键 ──► wakeEvents(ptt) 恒玄: BB 64 +/// App ──► ai.accept 恒玄: AA 6A,必须 3 秒内,否则设备停止送音频 +/// …会话进行中… +/// App ──► ai.exit 恒玄: AA 65 +/// 设备 ──► wakeEvents(hangup) 恒玄: BB E5;2 秒不回就本地强制结束 +/// ``` +/// +/// 常驻服务:按键在任意页面(含 App 在后台、EMAI 页没打开)都要能唤醒。 +class DeviceAiSessionService extends GetxService { + static const String _tag = 'DeviceAiSession'; + static DeviceAiSessionService get to => Get.find(); + + /// 设备侧的会话与手机 EMAI 页各用一条独立的 WebSocket。 + /// 共用一个单例的话两边会互相 stop 掉对方、下行音频也会串。 + /// + /// ⚠️ **接哪个百炼应用要看是哪台设备唤醒的**:耳机/支架接 EMAI,车载香薰接 + /// 「Smartcar 车载助手」(各自的 app_id 不同)。所以这里不能是 final 单例, + /// 由 [_ensureService] 按厂商换实例;app_id 没变就复用,不白开 WebSocket。 + BailianMultimodalService _svc = BailianMultimodalService(); + String? _svcAppId; + + /// 厂商 → 该接哪个 agent 的 app_id。走的是「厂商 → 品类 → 默认编排第一个模块 + /// → 模块声明的 bailianAppId」这条链,**设备层不认识 agent、agent 层不认识厂商**。 + /// 查不到返回 null = 用全局默认(EMAI)。 + String? _resolveAgentAppId(String vendor) { + try { + return bailianAppIdForModule(AgentDefaults.primaryModuleForVendor(vendor)); + } catch (e) { + Logger.w(_tag, '解析 agent app_id 失败(回退默认): $e'); + return null; + } + } + + /// 按需换一个指向目标 app_id 的服务实例。 + void _ensureService(String? appId) { + final want = (appId ?? '').trim(); + final cur = (_svcAppId ?? '').trim(); + if (want == cur) return; + Logger.i(_tag, + '切换设备侧百炼应用: ${cur.isEmpty ? '(默认)' : cur} → ${want.isEmpty ? '(默认)' : want}'); + // 旧实例可能还挂着 WebSocket,先停掉再丢 + unawaited(_svc.stop()); + _svc = BailianMultimodalService(appId: want.isEmpty ? null : want); + _svcAppId = want; + } + + /// 设备上行 PCM 就是 16k/16bit/mono,与百炼上行要求一致 + static const int _deviceRate = 16000; + + /// 上行攒够这么多字节再发一包:3200B = 100ms @16k。设备每 20ms 上来一包, + /// 逐包转发就是 50 条 WS 消息/秒,攒成 100ms 一条降到 1/5。 + static const int _micBatchBytes = 3200; + final BytesBuilder _micAccum = BytesBuilder(copy: false); + + /// 收到唤醒后必须在这个时间内应答。我们是立即回,这个常量只是把固件约束写在代码里。 + static const Duration _ackDeadline = Duration(seconds: 3); + + /// 发出 ai.exit 后等设备回 hangup 的时间,超时就本地强制结束 + static const Duration _stopAckTimeout = Duration(seconds: 2); + + StreamSubscription? _wakeSub; + StreamSubscription? _hubSub; + StreamSubscription? _micSub; + StreamSubscription? _eventSub; + StreamSubscription? _audioSub; + DeviceSession? _session; + DeviceAudioSource? _mic; + DeviceAudioSink? _spk; + Timer? _stopAckTimer; + Timer? _playoutTimer; + + /// 会话是否在跑(已应答,还没收到/发出结束) + final RxBool isActive = false.obs; + + /// 手机 EMAI 页(打开时由它自己 attach 上来)。 + /// 不用 `Get.put(controller)`:GetX 的 put 会对实例调 + /// onInit,而页面正是在自己的 onInit 里注册的,会递归到 Stack Overflow。 + EmaiSessionOwner? _phonePage; + + int _respondingBytes = 0; + DateTime? _respondingStartedAt; + + /// 上行是否被门控住(AI 正在设备里播报期间)。 + /// 设备没有把下发的音频接进自己的 AEC,播出去的 AI 声音会被麦克风原样收回, + /// duplex 模式下服务端 VAD 把它当成用户插话。没有 AEC 就只能做半双工。 + bool _uplinkGated = false; + Timer? _gateTimer; + bool _tearingDown = false; + static const Duration _gateTail = Duration(milliseconds: 500); + static const Duration _idleTimeout = Duration(seconds: 5); + Timer? _idleTimer; + DateTime? _firstAudioAt; + int _micPackets = 0; + int _downPackets = 0; + + EmaiChatStore get _store => EmaiChatStore.to; + EmaiMessage? _streamingUser; + EmaiMessage? _streamingAssistant; + + @override + void onInit() { + super.onInit(); + final hub = DeviceHub.to; + _wakeSub = hub.wakeEvents.listen(_onWake, onError: (e) { + Logger.e(_tag, '唤醒事件流错误: $e'); + }); + _hubSub = hub.sessionEvents.listen((e) { + if (e.type == DeviceSessionEventType.connectionStateChanged && + e.connectionState == DeviceConnectionState.disconnected && + isActive.value && + _session?.deviceId == e.deviceId) { + Logger.w(_tag, '设备断连,结束 AI 会话'); + _teardown(notifyDevice: false, playEndTone: false); + } + }); + Logger.i(_tag, '设备 AI 会话服务已就绪,等待按键唤醒'); + } + + @override + void onClose() { + _wakeSub?.cancel(); + _hubSub?.cancel(); + _teardown(notifyDevice: true, playEndTone: false); + super.onClose(); + } + + // ---------------- 设备事件 ---------------- + + void _onWake(DeviceWakeEvent e) { + switch (e.reason) { + case WakeReason.ptt: + case WakeReason.voiceWake: + _handleStart(e.deviceId); + break; + case WakeReason.hangup: + Logger.i(_tag, '设备通知结束 AI'); + _teardown(notifyDevice: false); + break; + default: + break; + } + } + + void _onMicPcm(Uint8List pcm) { + if (!isActive.value || pcm.isEmpty) return; + _micPackets++; + if (_micPackets == 1 || _micPackets % 50 == 0) { + Logger.i(_tag, + '设备上行 #$_micPackets (${pcm.length}B/包)${_uplinkGated ? ' [门控中]' : ''}'); + } + // 门控期间推等长静音而不是断流:上行保持连续,服务端 VAD 收到的是 + // "真的没人说话",而不是一段数据缺口 + _micAccum.add(_uplinkGated ? Uint8List(pcm.length) : pcm); + if (_micAccum.length >= _micBatchBytes) { + _svc.pushAudio(_micAccum.takeBytes()); + } + } + + Future _handleStart(String deviceId) async { + if (isActive.value) { + Logger.w(_tag, '已有会话在跑,忽略重复唤醒'); + return; + } + final hub = DeviceHub.to; + final session = + hub.sessions.firstWhereOrNull((s) => s.deviceId == deviceId) ?? + hub.sessionWith(DeviceCapability.aiWake); + if (session == null || session.state != DeviceConnectionState.ready) { + Logger.e(_tag, '设备未处于已连接状态,拒绝本次唤醒'); + return; + } + // ★ 先按厂商选中该说话的那个 agent(车载香薰 → Smartcar 车载助手), + // 再去看 isConfigured —— 反过来的话检查的是上一台设备的应用 + _ensureService(_resolveAgentAppId(session.vendor)); + Logger.i(_tag, + '设备按键唤醒 AI (${session.vendor},应用=${_svcAppId?.isNotEmpty == true ? _svcAppId : '默认'})'); + + // 起不来就别应答,直接让设备退出 AI 模式——应答之后设备会一直送音频, + // 而我们这边没有会话接,它会白等到超时 + if (!_svc.isConfigured) { + Logger.e(_tag, '百炼未配置(${_svc.configHint}),拒绝本次唤醒'); + await _sendExit(session); + return; + } + + // 固件要求 3 秒内确认,先应答再做后面的初始化。 + // 反过来的话,百炼握手(一次 WebSocket 往返)可能就吃掉大半个预算。 + final ackAt = DateTime.now(); + _session = session; + try { + await session.invokeFeature(DeviceFeatures.aiAccept); + } catch (e) { + Logger.e(_tag, '应答唤醒失败: $e'); + _session = null; + return; + } + isActive.value = true; + // 换了设备就重新试一次 ai.state(上一台不支持不代表这台也不支持) + _aiStateUnsupported = false; + _quitAfterPlayout = false; + _micPackets = 0; + _downPackets = 0; + _uplinkGated = false; + _micAccum.clear(); + + await _yieldPhonePage(); + + try { + _mic = await session.openMic(route: AudioRoute.ai); + _micSub = _mic!.pcm.listen(_onMicPcm); + _eventSub = _svc.events.listen(_onBailianEvent); + // 下行 16k:G.722 编码器就是 16k,让服务端直接出 16k 省掉一次重采样 + _audioSub = _svc.audioOut.listen(_onDownstreamPcm); + _spk = await session.openSpeaker(route: AudioRoute.ai); + } catch (e) { + Logger.e(_tag, '打开设备音频通路失败: $e'); + await _teardown(notifyDevice: true, playEndTone: false); + return; + } + // 先给一声「叮」,让用户立刻知道已经在听了——百炼握手还要一次往返 + await _playCue(CueTone.ding(sampleRate: _deviceRate)); + _touchActivity(); + + final ok = await _svc.start( + mode: 'duplex', + downstreamRate: _deviceRate, + userId: _currentUserId(), + source: 'earphone', + mcpToken: await McpTokenService.get(), + ); + final elapsed = DateTime.now().difference(ackAt); + if (elapsed > _ackDeadline) { + Logger.w( + _tag, + '会话初始化耗时 ${elapsed.inMilliseconds}ms,已超过固件 ' + '${_ackDeadline.inSeconds}s 预算(应答已提前回,通常无碍)'); + } + if (!ok) { + Logger.e(_tag, '百炼会话启动失败,结束'); + await _teardown(notifyDevice: true); + } + } + + // ---------------- 百炼事件 ---------------- + + void _onBailianEvent(BailianEvent e) { + Logger.i(_tag, '百炼事件 $e'); + switch (e.type) { + case BailianEventType.speechStarted: + case BailianEventType.speechContent: + case BailianEventType.speechEnded: + case BailianEventType.respondingStarted: + case BailianEventType.respondingContent: + case BailianEventType.respondingEnded: + _touchActivity(); + break; + default: + break; + } + switch (e.type) { + case BailianEventType.speechStarted: + // 只有真人插话才丢队列。门控期间的 speechStarted 是 AI 自己的回声触发的 + if (!_uplinkGated) { + _spk?.discardPending(); + _cancelPlayoutTimer(); + } + _streamingUser = null; + break; + + case BailianEventType.speechContent: + _streamingUser ??= _store + .append(EmaiMessage(isUser: true, text: '', fromEarphone: true)); + _store.applyText(_streamingUser!, e.text); + if (e.isFinal) { + _store.finalize(_streamingUser); + _streamingUser = null; + } + break; + + case BailianEventType.speechEnded: + if (e.text.isNotEmpty && _streamingUser != null) { + _store.applyText(_streamingUser!, e.text); + } + _store.finalize(_streamingUser); + _streamingUser = null; + break; + + case BailianEventType.respondingStarted: + _respondingBytes = 0; + _firstAudioAt = null; + _respondingStartedAt = DateTime.now(); + _cancelPlayoutTimer(); + _streamingAssistant = null; + break; + + case BailianEventType.respondingContent: + if (e.directives.isNotEmpty && + Get.isRegistered()) { + AssistantDirectiveService.to.handle(e.directives); + } + // 「关闭对话」:模型会下发 quit 指令并同时回一句告别语。 + // 不能立刻结束——那样告别语还没播完就被掐了;标记下来,等播完再收尾。 + if (e.directives.any((d) => d.name == _quitDirective)) { + Logger.i(_tag, '收到 quit 指令,本轮播完后结束会话'); + _quitAfterPlayout = true; + } + // 纯指令帧没有文本,别建空气泡 + if (e.text.isEmpty && e.finishReason == 'command_calls') break; + _streamingAssistant ??= _store + .append(EmaiMessage(isUser: false, text: '', fromEarphone: true)); + _store.applyText(_streamingAssistant!, e.text); + break; + + case BailianEventType.respondingEnded: + if (e.text.isNotEmpty && _streamingAssistant != null) { + _store.applyText(_streamingAssistant!, e.text); + } + _store.finalize(_streamingAssistant); + _streamingAssistant = null; + _logResponseAudioStats(); + _schedulePlayoutDone(); + break; + + case BailianEventType.error: + Logger.e(_tag, '会话错误: ${e.code} ${e.text} fatal=${e.fatal}'); + _store.dropIfEmpty(_streamingUser); + _streamingUser = null; + _store.dropIfEmpty(_streamingAssistant); + _streamingAssistant = null; + if (e.text.isNotEmpty) { + _store.append(EmaiMessage( + isUser: false, + text: e.text, + isFinal: true, + isError: true, + fromEarphone: true)); + _store.persist(); + } + if (e.fatal) _teardown(notifyDevice: true); + break; + + case BailianEventType.stateChanged: + // 把会话状态同步给设备,驱动它的指示灯/表情动画。 + // ⚠️ 只有声明了这个 feature 的厂商会真发字节,其余抛 not_supported 被吞掉。 + switch (e.state) { + case BailianDialogState.listening: + _pushAiState(DeviceAiState.listening); + break; + case BailianDialogState.thinking: + _pushAiState(DeviceAiState.thinking); + break; + case BailianDialogState.responding: + _pushAiState(DeviceAiState.speaking); + break; + default: + break; + } + break; + + case BailianEventType.closed: + if (isActive.value) { + Logger.w(_tag, '百炼会话关闭,结束设备 AI'); + _teardown(notifyDevice: true); + } + break; + + default: + break; + } + } + + void _onDownstreamPcm(Uint8List pcm) { + if (!isActive.value || pcm.isEmpty) return; + if (_firstAudioAt == null) { + _firstAudioAt = DateTime.now(); + _openGate(); + } + _respondingBytes += pcm.length; + _downPackets++; + if (_downPackets == 1 || _downPackets % 50 == 0) { + Logger.i(_tag, '下行给设备 #$_downPackets (${pcm.length}B)'); + } + _spk?.write(pcm); + } + + /// 有动静就把静默计时重新拨回 5 秒。播报期间不计时。 + /// 设备是否支持 [DeviceFeatures.aiState]。不支持就别每次都试、别每次都打日志。 + bool _aiStateUnsupported = false; + + /// 模型下发的「结束对话」指令名(`extra_info.commands` 里的 `name`) + static const String _quitDirective = 'quit'; + + /// 收到 quit 指令,等这一轮告别语播完就收尾 + bool _quitAfterPlayout = false; + + /// 把 AI 会话状态推给设备(驱动指示灯/表情)。 + /// + /// **fire-and-forget**:设备不支持、或这条命令失败,都不该影响对话本身, + /// 所以既不 await 也不往上抛。 + void _pushAiState(DeviceAiState state) { + if (_aiStateUnsupported) return; + final s = _session; + if (s == null || s.state != DeviceConnectionState.ready) return; + s.invokeFeature(DeviceFeatures.aiState, {'state': state}).catchError( + (Object e) { + if (e is DeviceException && e.code == DeviceErrorCode.notSupported) { + // 这台设备没有表情/指示灯,记一次就够了 + _aiStateUnsupported = true; + Logger.i(_tag, '设备不支持 ai.state,后续不再推送会话状态'); + } else { + Logger.w(_tag, '推送 ai.state($state) 失败: $e'); + } + return {}; + }, + ); + } + + void _touchActivity() { + _idleTimer?.cancel(); + _idleTimer = null; + if (!isActive.value || _uplinkGated) return; + _idleTimer = Timer(_idleTimeout, () { + if (!isActive.value) return; + Logger.i(_tag, '双方 ${_idleTimeout.inSeconds}s 无声,自动结束 AI 会话'); + requestStop(); + }); + } + + /// 在设备里放一段提示音(走 AI 下行通道)。播放期间开门控。 + Future _playCue(Uint8List pcm, {bool waitForPlayout = false}) async { + final spk = _spk; + if (spk == null || _session?.state != DeviceConnectionState.ready) return; + _openGate(); + await spk.write(pcm); + final ms = pcm.length * 1000 ~/ (_deviceRate * 2); + if (waitForPlayout) { + // 结束音要等它真的发完+播完,否则紧接着关通道会把它清掉 + await Future.delayed(Duration(milliseconds: ms + 400)); + } else { + _gateTimer?.cancel(); + _gateTimer = Timer(Duration(milliseconds: ms + 300), _closeGate); + } + } + + void _openGate() { + _gateTimer?.cancel(); + _gateTimer = null; + if (_uplinkGated) return; + _uplinkGated = true; + _idleTimer?.cancel(); + _idleTimer = null; + Logger.i(_tag, '上行门控开启(AI 播报中)'); + } + + void _closeGate() { + _gateTimer?.cancel(); + _gateTimer = null; + if (!_uplinkGated) return; + _uplinkGated = false; + Logger.i(_tag, '上行门控解除'); + _touchActivity(); + } + + void _logResponseAudioStats() { + final start = _firstAudioAt; + if (start == null || _respondingBytes == 0) return; + final ms = DateTime.now().difference(start).inMilliseconds; + final audioMs = _respondingBytes * 1000 ~/ (_deviceRate * 2); + Logger.i(_tag, + '本轮下行音频 ${_respondingBytes}B ≈ ${audioMs}ms(按16k算),实际用时 ${ms}ms'); + } + + /// 估算设备什么时候把这一轮播完,然后回 `LocalRespondingEnded`。 + void _schedulePlayoutDone() { + _cancelPlayoutTimer(); + const bytesPerSecond = _deviceRate * 2; + final totalMs = _respondingBytes * 1000 ~/ bytesPerSecond; + final elapsedMs = DateTime.now() + .difference(_respondingStartedAt ?? DateTime.now()) + .inMilliseconds; + // 上限 10 分钟,跟原生下行队列的容量对齐 + final remainMs = (totalMs - elapsedMs).clamp(0, 600000); + Logger.i(_tag, '预计还需 ${remainMs}ms 播完(已推 ${totalMs}ms 音频)'); + _playoutTimer = Timer(Duration(milliseconds: remainMs), () { + if (!isActive.value) return; + _svc.notifyLocalRespondingEnded(); + _gateTimer = Timer(_gateTail, _closeGate); + if (_quitAfterPlayout) { + _quitAfterPlayout = false; + Logger.i(_tag, '告别语已播完,按 quit 指令结束会话'); + _teardown(notifyDevice: true, playEndTone: false); + } + }); + } + + void _cancelPlayoutTimer() { + _playoutTimer?.cancel(); + _playoutTimer = null; + } + + // ---------------- 结束 ---------------- + + /// 主动结束:发 ai.exit,等设备回 hangup;超时就本地强制收尾。 + Future requestStop() async { + if (!isActive.value) return; + Logger.i(_tag, '请求设备退出 AI 模式'); + final s = _session; + if (s != null) await _sendExit(s); + _stopAckTimer?.cancel(); + _stopAckTimer = Timer(_stopAckTimeout, () { + if (!isActive.value) return; + Logger.w(_tag, '${_stopAckTimeout.inSeconds}s 未收到设备的结束应答,本地强制结束'); + _teardown(notifyDevice: false); + }); + } + + Future _sendExit(DeviceSession s) async { + if (s.state != DeviceConnectionState.ready) return; + try { + await s.invokeFeature(DeviceFeatures.aiExit); + } catch (e) { + Logger.w(_tag, '发送 ai.exit 失败: $e'); + } + } + + /// [notifyDevice] 为 true 时补发 ai.exit:不是设备主导的结束,必须告诉设备退出。 + /// [playEndTone] 为 false 用于设备已经断连的场景。 + Future _teardown({ + required bool notifyDevice, + bool playEndTone = true, + }) async { + if (_tearingDown) return; + _tearingDown = true; + try { + await _doTeardown(notifyDevice: notifyDevice, playEndTone: playEndTone); + } finally { + _tearingDown = false; + } + } + + Future _doTeardown({ + required bool notifyDevice, + bool playEndTone = true, + }) async { + _stopAckTimer?.cancel(); + _stopAckTimer = null; + _idleTimer?.cancel(); + _idleTimer = null; + _cancelPlayoutTimer(); + _micAccum.clear(); + + if (isActive.value && playEndTone) { + // 先把还没播完的 AI 语音丢掉,不然「咚」要排在几十秒的队尾 + await _spk?.discardPending(); + await _playCue(CueTone.dong(sampleRate: _deviceRate), waitForPlayout: true); + } + _closeGate(); + + final wasActive = isActive.value; + isActive.value = false; + + _store.dropIfEmpty(_streamingUser); + _streamingUser = null; + _store.dropIfEmpty(_streamingAssistant); + _streamingAssistant = null; + if (wasActive) _store.persist(); + + await _eventSub?.cancel(); + _eventSub = null; + await _audioSub?.cancel(); + _audioSub = null; + await _micSub?.cancel(); + _micSub = null; + + await _spk?.close(); + _spk = null; + await _mic?.close(); + _mic = null; + await _svc.stop(); + + final s = _session; + if (wasActive && notifyDevice && s != null) await _sendExit(s); + _session = null; + if (wasActive) { + Logger.i(_tag, '设备 AI 会话已结束 (上行 $_micPackets 包 / 下行 $_downPackets 包)'); + await _resumePhonePage(); + } + } + + // ---------------- 与手机 EMAI 页互斥 ---------------- + + void attachPhonePage(EmaiSessionOwner page) => _phonePage = page; + + void detachPhonePage(EmaiSessionOwner page) { + if (identical(_phonePage, page)) _phonePage = null; + } + + Future _yieldPhonePage() async { + final ctrl = _phonePage; + if (ctrl == null) return; + Logger.i(_tag, '手机 EMAI 页正开着,让它让出会话'); + try { + await ctrl.yieldToEarphone(); + } catch (e) { + Logger.w(_tag, '通知 EMAI 页让出失败: $e'); + } + } + + Future _resumePhonePage() async { + final ctrl = _phonePage; + if (ctrl == null) return; + try { + await ctrl.resumeFromEarphone(); + } catch (e) { + Logger.w(_tag, '通知 EMAI 页恢复失败: $e'); + } + } + + String _currentUserId() { + try { + return user_info.User.isLoggedIn() + ? user_info.User.instance.uid + : 'eaimar-guest'; + } catch (_) { + return 'eaimar-guest'; + } + } +} + +/// 手机 EMAI 页实现这个接口,让设备会话能在不反向依赖 modules 层的前提下 +/// 通知它让出/恢复。EmaiController 在 onInit/onClose 里 +/// 调 [DeviceAiSessionService.attachPhonePage] / [DeviceAiSessionService.detachPhonePage]。 +abstract class EmaiSessionOwner { + /// 设备接管:停掉本页的播放与会话,并且不要自动重连 + Future yieldToEarphone(); + + /// 设备结束:把本页的会话接回来 + Future resumeFromEarphone(); +} diff --git a/apps/client/lib/data/services/device_call_recording_service.dart b/apps/client/lib/data/services/device_call_recording_service.dart new file mode 100644 index 00000000..da25dd18 --- /dev/null +++ b/apps/client/lib/data/services/device_call_recording_service.dart @@ -0,0 +1,296 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:get/get.dart'; +import 'package:intl/intl.dart'; +import 'package:path_provider/path_provider.dart'; + +import '../../core/utils/audio_foreground_service.dart'; +import '../../core/utils/logger.dart'; +import '../../devices/device_hub.dart'; +import 'recording_archive.dart'; +import 'wav_writer.dart'; + +/// **通话录音**的全局服务——厂商无关,要求设备具备 [DeviceCapability.callAudioTap]。 +/// +/// 两路音频 `openMic(callLocal)`(本端麦)+ `openMic(callPeer)`(对端声音), +/// 落成**双声道 WAV:左=本端,右=对端**。恒玄是 G.722 mode=0x03 交织上行, +/// 原生按帧标好 mic/spk 后分两路给出,这里按到达顺序配对。 +/// +/// 只在通话中可用([DeviceHub.inCall]),通话结束自动收尾。 +class DeviceCallRecordingService extends GetxService { + static const String _tag = 'DeviceCallRecording'; + static DeviceCallRecordingService get to => Get.find(); + + final RxBool isRecording = false.obs; + final RxInt elapsedMs = 0.obs; + final RxDouble level = 0.0.obs; + final RxList waveform = [].obs; + static const int sampleIntervalMs = 100; + static const int _maxSamples = 600; + + StreamSubscription? _hubSub; + Worker? _callWorker; + DeviceSession? _session; + DeviceAudioSource? _local; + DeviceAudioSource? _peer; + StreamSubscription? _localSub; + StreamSubscription? _peerSub; + + /// 暂存的对端帧,等本端帧到齐后一起交织写盘 + Uint8List? _pendingPeer; + int _frameCount = 0; + Timer? _silenceCheck; + WavWriter? _wav; + String? _path; + Timer? _tick; + Timer? _sampleTimer; + final Stopwatch _stopwatch = Stopwatch(); + bool _busy = false; + + /// 本次录音是不是设备按键发起的。设备侧处于录音态时,停止要额外补一条 + /// `record.stop` 让它自己也退出来,只发 `call.stop` 不足以清掉设备端的录音状态。 + bool _deviceRecordingActive = false; + + @override + void onInit() { + super.onInit(); + _hubSub = DeviceHub.to.sessionEvents.listen(_onSessionEvent); + // 通话结束时如果还在录,收尾归档(不能让文件一直挂着) + _callWorker = ever(DeviceHub.to.inCall, (calling) async { + if (!calling && isRecording.value && !_busy) { + Logger.i(_tag, '通话结束,停止并归档'); + await stop(sendCommand: true); + } + }); + } + + @override + void onClose() { + _hubSub?.cancel(); + _callWorker?.dispose(); + _localSub?.cancel(); + _peerSub?.cancel(); + _tick?.cancel(); + _sampleTimer?.cancel(); + super.onClose(); + } + + void _onSessionEvent(DeviceSessionEvent e) async { + switch (e.type) { + case DeviceSessionEventType.feature: + if (_busy) return; + final key = e.feature?.key; + // 通话开始**不再自动录音**。入口只有两个:录音页点开始、设备按录音键。 + if (key == DeviceFeatureKeys.recordStarted && !isRecording.value) { + if (!DeviceHub.to.inCall.value) return; // 不在通话里的按键归现场录音管 + Logger.i(_tag, '设备端按下录音键,开始通话录音'); + _deviceRecordingActive = true; + await start(sendCommand: true, deviceId: e.deviceId); + } else if (key == DeviceFeatureKeys.recordStopped && isRecording.value) { + Logger.i(_tag, '设备端结束录音,落盘并归档'); + _deviceRecordingActive = false; + await stop(sendCommand: true); + } + break; + case DeviceSessionEventType.connectionStateChanged: + if (e.connectionState == DeviceConnectionState.disconnected && + isRecording.value && + _session?.deviceId == e.deviceId) { + Logger.w(_tag, '设备断开,结束当前通话录音'); + stop(); + } + break; + default: + break; + } + } + + Future start({bool sendCommand = false, String? deviceId}) async { + if (isRecording.value || _busy) return isRecording.value; + _busy = true; + try { + return await _start(sendCommand, deviceId); + } finally { + _busy = false; + } + } + + Future _start(bool sendCommand, String? deviceId) async { + final hub = DeviceHub.to; + final session = (deviceId == null + ? null + : hub.sessions.firstWhereOrNull((s) => s.deviceId == deviceId)) ?? + hub.sessionWith(DeviceCapability.callAudioTap); + if (session == null) return false; + _session = session; + + try { + final docs = await getApplicationDocumentsDirectory(); + final dir = Directory('${docs.path}/call_recordings'); + if (!await dir.exists()) await dir.create(recursive: true); + final ts = DateFormat('yyyyMMdd_HHmmss').format(DateTime.now()); + _path = '${dir.path}/call_$ts.wav'; + _wav = await WavWriter.open(_path!, channels: 2); + + _pendingPeer = null; + _frameCount = 0; + _peer = await session.openMic(route: AudioRoute.callPeer); + _local = await session.openMic(route: AudioRoute.callLocal); + _peerSub = _peer!.pcm.listen(_onPeer); + _localSub = _local!.pcm.listen(_onLocal); + + // 进通话模式,设备才会双路上行。不管是不是 App 主动发起的都补发一次—— + // 只靠设备自己进通话模式时,它未必会把音频回传给 App。 + await session.invokeFeature(DeviceFeatures.callStart); + + // 2 秒还没收到任何音频帧就再补一次指令,并把情况打进日志 + _silenceCheck?.cancel(); + _silenceCheck = Timer(const Duration(seconds: 2), () async { + if (!isRecording.value) return; + if (_frameCount == 0) { + Logger.w(_tag, '进通话模式 2s 内没收到任何音频帧,重发 call.start'); + try { + await session.invokeFeature(DeviceFeatures.callStart); + } catch (_) {} + } else { + Logger.i(_tag, '通话音频已上行,2s 内收到 $_frameCount 帧'); + } + }); + + // 把进程钉住,否则切后台后录音会被国内 ROM 悄悄掐断 + unawaited(AudioForegroundService.start()); + + isRecording.value = true; + elapsedMs.value = 0; + level.value = 0; + waveform.clear(); + _stopwatch + ..reset() + ..start(); + _tick = Timer.periodic(const Duration(milliseconds: 200), (_) { + elapsedMs.value = _stopwatch.elapsedMilliseconds; + }); + _sampleTimer = Timer.periodic( + const Duration(milliseconds: sampleIntervalMs), + (_) => _sample(), + ); + Logger.i(_tag, '开始录制: $_path'); + return true; + } catch (e) { + Logger.e(_tag, '启动本地采集失败: $e'); + await _closeFile(save: false); + return false; + } + } + + Future stop({bool sendCommand = false}) async { + if (!isRecording.value || _busy) return; + _busy = true; + try { + await _stop(sendCommand); + } finally { + _busy = false; + } + } + + Future _stop(bool sendCommand) async { + _silenceCheck?.cancel(); + Logger.i(_tag, '停止通话录音: 收到 $_frameCount 帧,写入 ${_wav?.dataBytes} 字节'); + _tick?.cancel(); + _sampleTimer?.cancel(); + _stopwatch.stop(); + + final int seconds = elapsedMs.value ~/ 1000; + final String? path = _path; + final session = _session; + + if (sendCommand && + session != null && + session.state == DeviceConnectionState.ready) { + try { + // 设备侧还在录音态时先让它停录,再退出通话模式。顺序不能反: + // 先退通话模式的话,录音停止指令未必还能被正确处理。 + if (_deviceRecordingActive) { + await session.invokeFeature(DeviceFeatures.recordStop); + Logger.i(_tag, '已下发 record.stop,通知设备退出录音态'); + } + await session.invokeFeature(DeviceFeatures.callStop); + } catch (e) { + Logger.e(_tag, '下发停止指令失败: $e'); + } + } + _deviceRecordingActive = false; + + final dataBytes = _wav?.dataBytes ?? 0; + await _closeFile(save: true); + unawaited(AudioForegroundService.stop()); + isRecording.value = false; + elapsedMs.value = 0; + level.value = 0; + waveform.clear(); + _session = null; + + if (path != null && dataBytes > 0) { + await RecordingArchive.archive(path: path, seconds: seconds, tag: _tag); + } else { + Logger.w(_tag, '本次没有收到音频数据,删除空文件'); + if (path != null) { + try { + final f = File(path); + if (await f.exists()) await f.delete(); + } catch (e) { + Logger.e(_tag, '删除空录音文件失败: $e'); + } + } + } + _path = null; + } + + void _onPeer(Uint8List pcm) { + if (_wav == null || pcm.isEmpty) return; + _frameCount++; + _pendingPeer = pcm; + } + + void _onLocal(Uint8List pcm) { + if (_wav == null || pcm.isEmpty) return; + _frameCount++; + if (_frameCount <= 3 || _frameCount % 200 == 0) { + Logger.d(_tag, '收到通话音频帧 #$_frameCount len=${pcm.length}'); + } + final peer = _pendingPeer; + _pendingPeer = null; + if (peer == null) return; + // 左声道=本端麦克风,右声道=对端声音 + _wav!.write(WavWriter.interleave(pcm, peer), onWritten: () { + level.value = WavWriter.rmsLevel(pcm); + }); + } + + void _sample() { + final list = waveform.toList(); + list.add(level.value); + if (list.length > _maxSamples) { + list.removeRange(0, list.length - _maxSamples); + } + waveform.assignAll(list); + } + + Future _closeFile({required bool save}) async { + await _localSub?.cancel(); + await _peerSub?.cancel(); + _localSub = null; + _peerSub = null; + await _local?.close(); + await _peer?.close(); + _local = null; + _peer = null; + final w = _wav; + _wav = null; + if (w == null) return; + await w.close(save: save); + } +} diff --git a/apps/client/lib/data/services/device_file_import_service.dart b/apps/client/lib/data/services/device_file_import_service.dart new file mode 100644 index 00000000..f1fe1a50 --- /dev/null +++ b/apps/client/lib/data/services/device_file_import_service.dart @@ -0,0 +1,489 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:path/path.dart' as p; +import 'package:path_provider/path_provider.dart'; + +import '../../core/utils/logger.dart'; +import '../../devices/device_hub.dart'; +import '../utils/device_file_match.dart'; +import '../utils/ogg_opus_duration.dart'; +import 'db/sqflite_api.dart'; +import 'recording_archive.dart'; + +/// 把「设备自己录在本机存储里的音频」同步进语音纪要 —— **厂商无关**。 +/// +/// 适用于任何声明了 [DeviceCapability.fileStore] 的设备。当前只有 EaiRec 支架 +/// (TF 卡,通道 B),但录音笔、眼镜都是同一个形态,接进来零改动。 +/// +/// 触发时机三个,缺一不可: +/// 1. 设备上线(连上后延时几秒,等厂商插件把文件通道握完手); +/// 2. 设备**主动推送**文件列表——多数硬件在「录音停止」后推一次, +/// 这是「刚录完立刻出现在列表里」的唯一及时来源; +/// 3. 用户在语音纪要页手动下拉/点同步([importNow])。 +/// +/// **导入成功并确认已上传服务端之后,会把设备上的原件删掉**([autoDeleteAfterImport])。 +/// +/// ⚠️ 这一步是必须的,不是可选的优化:协议里**没有任何自动回收/循环覆盖机制** +/// (EaiRec_protocol.md §5.3 有 `NO_SPACE = 0x08`,§5.10 的 `FILE_DELETE` 是 +/// 唯一的单文件清理手段且**只能 App 主动发**)。不删,卡就一直涨到满, +/// 然后设备直接录不进去。 +/// +/// ⚠️ **删除的门槛是「已经传到服务端」,不是「已经落到手机上」**: +/// 判据是本地库里这条记录的 `audiourl` 非空([MeetingUploadService] 上传成功后写的)。 +/// 所以删除通常发生在**后面某一轮**同步,不是导入的那一刻。 +/// 断网、上传失败、上传队列还没轮到 —— 这些情况下设备原件一律不动, +/// 这是刻意选的失败方向:宁可卡满要人工清,也不能把用户唯一那份录音销毁掉。 +class DeviceFileImportService extends GetxService { + static const String _tag = 'DeviceFileImport'; + + static DeviceFileImportService get to => Get.find(); + + /// 已导入的文件指纹(`设备id|文件名|字节数`)→ 语音纪要里的记录 id。 + /// + /// ⚠️ 指纹带上字节数是有意的:8.3 短文件名会**回绕复用**(`MIC0001.OGG` 删掉后 + /// 下次录音可能又叫这个名),只按文件名记会把新录音当成已导入而永远跳过。 + /// + /// 记 id 而不只是记「导过了」,是因为删除设备原件前要回查这条记录传上去没有。 + static const String _doneKey = 'device_files_imported'; + + /// 导入并确认上传后,删掉设备上的原件。默认开,理由见类文档。 + static const String _autoDeleteKey = 'device_files_auto_delete'; + + bool get autoDeleteAfterImport => + _storage.read(_autoDeleteKey) ?? true; + + set autoDeleteAfterImport(bool v) => _storage.write(_autoDeleteKey, v); + + /// 本轮清理掉的设备文件数,UI 可用来提示「已释放空间」 + final RxInt deletedCount = 0.obs; + + final GetStorage _storage = GetStorage(); + + /// 正在导入 + final RxBool isImporting = false.obs; + + /// 当前正在拉的文件名(没有则空串) + final RxString currentFile = ''.obs; + + /// 当前文件的进度 0~1;设备没给总长度时为 -1(不确定态) + final RxDouble progress = 0.0.obs; + + /// 本轮还剩几个没拉 + final RxInt pending = 0.obs; + + /// 最近一次失败原因,成功时清空。UI 可以拿它提示,但**不要弹窗**—— + /// 这是后台同步,失败下次连上还会再来。 + final RxString lastError = ''.obs; + + /// 本进程内累计导入成功的条数,UI 用它做「同步完成」提示 + final RxInt importedCount = 0.obs; + + Worker? _sessionsWorker; + StreamSubscription>? _pushSub; + Timer? _debounce; + DeviceFileCancelToken? _cancel; + bool _running = false; + + /// 已经挂上推送订阅的那个 session 的 deviceId,避免重复订阅 + String _boundDeviceId = ''; + + @override + void onInit() { + super.onInit(); + _sessionsWorker = ever>( + DeviceHub.to.sessions, + (_) => _onSessionsChanged(), + ); + _onSessionsChanged(); + } + + @override + void onClose() { + _sessionsWorker?.dispose(); + _pushSub?.cancel(); + _debounce?.cancel(); + _cancel?.cancel(); + super.onClose(); + } + + // ---------------- 触发 ---------------- + + void _onSessionsChanged() { + final s = DeviceHub.to.sessionWith(DeviceCapability.fileStore); + final store = s?.fileStore(); + if (s == null || store == null) { + _pushSub?.cancel(); + _pushSub = null; + _boundDeviceId = ''; + // 设备走了就把在途传输掐掉,不然会在超时里卡好几十秒 + _cancel?.cancel(); + return; + } + if (_boundDeviceId == s.deviceId) return; + _boundDeviceId = s.deviceId; + _pushSub?.cancel(); + _pushSub = store.listPushes.listen( + (_) { + Logger.i(_tag, '设备推送了文件列表,安排一次同步'); + _schedule(const Duration(seconds: 1)); + }, + onError: (Object e) => Logger.w(_tag, '文件列表推送流错误: $e'), + ); + // ⚠️ 连上后不能立刻拉:厂商插件那边通道还在握手(支架要对时 + 查状态), + // 这几秒省不掉,抢在前面只会拿到一个「通道不可用」。 + _schedule(const Duration(seconds: 5)); + } + + void _schedule(Duration delay) { + _debounce?.cancel(); + _debounce = Timer(delay, () => unawaited(importNow())); + } + + /// 「导完了但还没删掉」时的回扫次数上限。 + /// + /// ⚠️ 刚导完那一轮基本删不掉任何东西:上传还在 [MeetingUploadService] 的队列里, + /// 而删除的门槛是「已上传」。所以要过几分钟再回来收一次。 + /// **必须有上限**:上传一直失败(没网/额度用尽)的话,无上限就是每 3 分钟 + /// 白拉一次 FILE_LIST,永远停不下来。删掉东西或导入新文件会把计数清零。 + static const int _maxCleanupRetries = 5; + static const Duration _cleanupRetryDelay = Duration(minutes: 3); + int _cleanupRetries = 0; + + /// 本轮导入成功的条数([importedCount] 是进程累计值,两者别混) + int _importedThisSweep = 0; + + /// 设备上还有「导过、但还没删」的文件时,安排一次回扫。 + void _scheduleCleanupRetry({required bool madeProgress}) { + if (!autoDeleteAfterImport) return; + if (madeProgress) _cleanupRetries = 0; + if (_doneMap().isEmpty) return; // 设备上没有我们导过的文件了 + if (_cleanupRetries >= _maxCleanupRetries) { + Logger.i(_tag, '回扫 $_cleanupRetries 次仍无可删文件(多半是上传没完成),暂停'); + return; + } + _cleanupRetries++; + Logger.i(_tag, '安排第 $_cleanupRetries 次清理回扫(${_cleanupRetryDelay.inMinutes} 分钟后)'); + _schedule(_cleanupRetryDelay); + } + + /// 手动触发一次同步。已在跑就直接返回,不排队。 + Future importNow() async { + if (_running) return; + final session = DeviceHub.to.sessionWith(DeviceCapability.fileStore); + final store = session?.fileStore(); + if (session == null || store == null) return; + + _running = true; + isImporting.value = true; + lastError.value = ''; + deletedCount.value = 0; + _importedThisSweep = 0; + final cancel = DeviceFileCancelToken(); + _cancel = cancel; + try { + await _sweep(session, store, cancel); + } catch (e) { + lastError.value = '$e'; + Logger.w(_tag, '同步失败: $e'); + } finally { + _running = false; + isImporting.value = false; + currentFile.value = ''; + progress.value = 0; + pending.value = 0; + _cancel = null; + // ⚠️ 这里要用**本轮**的计数。importedCount 是进程累计值, + // 拿它判「有进展」会让重试计数永远清零,退化成无限回扫。 + _scheduleCleanupRetry( + madeProgress: deletedCount.value > 0 || _importedThisSweep > 0); + } + } + + /// 取消正在进行的同步(用户离开页面 / 主动断开设备) + void cancel() => _cancel?.cancel(); + + // ---------------- 主流程 ---------------- + + Future _sweep( + DeviceSession session, + DeviceFileStore store, + DeviceFileCancelToken cancel, + ) async { + // 设备正在录音时整轮都别做:通道 B 是单事务的,插一条文件传输进去 + // 会和录音抢链路(协议 §7.1)。等它录完自然会推列表,那时再来。 + if (store.isDeviceRecording) { + Logger.i(_tag, '设备正在录音,本轮跳过'); + return; + } + + var files = await store.list(); + + // 先清理再导入:先腾空间再往卡里写,卡快满时只有这个顺序救得回来。 + // 清完重新拉一次列表,免得拿着已删的文件去下载。 + final before = files.length; + await _cleanup(session, store, files, cancel); + if (cancel.isCancelled) return; + if (deletedCount.value > 0) { + files = await store.list(); + Logger.i(_tag, '清理后设备上剩 ${files.length} 个文件(清理前 $before)'); + } + + final done = _doneMap(); + final todo = []; + for (final f in files) { + // 0 字节的多半是刚建还没写的占位,拉下来是个空文件 + if (f.size <= 0) continue; + if (done.containsKey(_fingerprint(session.deviceId, f))) continue; + todo.add(f); + } + Logger.i(_tag, '设备上 ${files.length} 个文件,需要导入 ${todo.length} 个'); + if (todo.isEmpty) return; + + // 旧的先导,用户的时间线才是顺的 + todo.sort((a, b) { + final ta = a.modifiedAt; + final tb = b.modifiedAt; + if (ta == null || tb == null) return a.name.compareTo(b.name); + return ta.compareTo(tb); + }); + + pending.value = todo.length; + final tmpDir = Directory( + '${(await getApplicationDocumentsDirectory()).path}/DeviceImport'); + if (!await tmpDir.exists()) await tmpDir.create(recursive: true); + + for (final f in todo) { + if (cancel.isCancelled) { + Logger.i(_tag, '同步被取消,剩 ${pending.value} 个未导入'); + return; + } + // 每个文件都重新问一次:用户可能中途按了设备上的录音键 + if (store.isDeviceRecording) { + Logger.i(_tag, '设备开始录音,本轮中止'); + return; + } + await _importOne(session, store, f, tmpDir, cancel); + pending.value = pending.value - 1; + } + } + + Future _importOne( + DeviceSession session, + DeviceFileStore store, + DeviceFileEntry f, + Directory tmpDir, + DeviceFileCancelToken cancel, + ) async { + currentFile.value = f.name; + progress.value = 0; + final localName = _localName(session, f); + final destPath = '${tmpDir.path}/$localName'; + + try { + // ⚠️ 同名残留会被 SDK 当成断点续传的半成品接着写。**这正是要的行为**: + // 上一次没拉完的下次接着拉,不用从头来(BLE 上一个 10 分钟的录音要好几分钟)。 + await store.download( + f.name, + destPath: destPath, + cancelToken: cancel, + onProgress: (received, total) { + progress.value = total > 0 ? received / total : -1; + }, + ); + } on DeviceException catch (e) { + if (e.code == DeviceErrorCode.cancelled) return; // 取消不是错误 + lastError.value = '${f.name}: ${e.message ?? e.code}'; + Logger.w(_tag, '拉取失败 ${f.name}: $e'); + return; + } + + if (cancel.isCancelled) return; + + final seconds = await _probeSeconds(destPath, f.size); + final id = await RecordingArchive.archive( + path: destPath, + seconds: seconds, + tag: _tag, + // 后台批量同步,一条弹一次会把屏幕刷满 + notify: false, + // 列表要按「什么时候录的」排,不是「什么时候同步的」 + createdAt: f.modifiedAt, + ); + if (id == null) { + // 归档失败:文件还在暂存目录,**不记已导入**,下次连上重来。 + Logger.w(_tag, '归档失败,保留 $destPath 待下次重试'); + lastError.value = '${f.name}: 归档失败'; + return; + } + // 记下记录 id:删设备原件前要靠它回查这条传上去没有 + _markDone(session.deviceId, f, id); + importedCount.value = importedCount.value + 1; + _importedThisSweep++; + Logger.i(_tag, '已导入 ${f.name} → 语音纪要 id=$id (${seconds}s)'); + } + + // ---------------- 辅助 ---------------- + + /// 导入后在语音纪要里显示的名字。 + /// + /// 设备上是 8.3 短名(`MIC0016.OGG`),直接拿来当标题既看不出是什么时候录的, + /// 又会因为名字回绕而重复。所以拼成 `holder_20260910_203015_MIC0016.ogg`: + /// 前缀沿用 [RecordingArchive] 的约定,中间是设备记的录制时间。 + String _localName(DeviceSession session, DeviceFileEntry f) { + final t = f.modifiedAt ?? DateTime.now(); + String two(int v) => v.toString().padLeft(2, '0'); + final stamp = '${t.year}${two(t.month)}${two(t.day)}_' + '${two(t.hour)}${two(t.minute)}${two(t.second)}'; + final base = p.basenameWithoutExtension(f.name); + final ext = p.extension(f.name).toLowerCase(); + return '${session.vendor}_${stamp}_$base${ext.isEmpty ? '.ogg' : ext}'; + } + + /// 读音频时长(秒)。 + /// + /// 走 Ogg 容器的 granule position,见 [oggOpusSeconds] 里的说明 + /// (不解码、不依赖播放器,因为播放器解不了这种裸 Ogg Opus)。 + Future _probeSeconds(String path, int sizeHint) async { + try { + final secs = await oggOpusSeconds(File(path)); + if (secs != null && secs > 0) return secs.round(); + } catch (e) { + Logger.w(_tag, '解析 Ogg 时长失败,退回按码率估: $e'); + } + // 兜底:非 Ogg 或文件损坏。16kbps = 2000 B/s,是支架当前固件的规格。 + // ⚠️ 这个估值会偏出一倍(真机实测),只是不得已时不至于显示 0。 + final est = sizeHint ~/ 2000; + return est > 0 ? est : 1; + } + + String _fingerprint(String deviceId, DeviceFileEntry f) => + '$deviceId|${f.name}|${f.size}'; + + /// 指纹 → 语音纪要记录 id。 + /// + /// ⚠️ 兼容旧格式:这个键早先存的是 `List`(只有指纹、没有 id)。 + /// 那些条目读成 id=0,含义是「导过了,但不知道是哪条记录」—— + /// **id=0 的永远不会被自动删除**,宁可留在卡上让人工清。 + Map _doneMap() { + final raw = _storage.read(_doneKey); + if (raw is Map) { + return raw.map((k, v) => MapEntry('$k', v is int ? v : 0)); + } + if (raw is List) { + return {for (final e in raw.whereType()) e: 0}; + } + return {}; + } + + void _writeDone(Map m) { + // 无上限地长会让每次启动都读一坨;设备卡上撑死几百个文件,留 2000 条足够。 + // 超了从最早的开始丢(丢了最坏情况是重导一次,不会丢数据)。 + var out = m; + if (out.length > 2000) { + final keys = out.keys.toList().sublist(out.length - 2000); + out = {for (final k in keys) k: out[k]!}; + } + _storage.write(_doneKey, out); + } + + void _markDone(String deviceId, DeviceFileEntry f, int meetingId) { + _writeDone(_doneMap()..[_fingerprint(deviceId, f)] = meetingId); + } + + /// 已经确认传到服务端的录音:标题(大写)→ 本机音频路径。 + /// + /// 上传成功时 [MeetingUploadService] 把 audiourl 写回本地库 + /// (`SqfliteApi.editMeetingTitle(id, {'audiourl': ...})`),所以读本地库就够了。 + /// + /// ⚠️ **按标题反查而不是只认那张指纹表**,是为了自愈:指纹表可能是旧格式、 + /// 也可能因为超长被截断过,而标题里带着设备原文件名。 + /// + /// 读不到就返回空表:这一轮谁都不删,失败方向是「不删」。 + Future> _uploadedRecords() async { + try { + final list = await SqfliteApi.getMeetingList(); + final out = {}; + for (final row in (list as List?) ?? const []) { + if (row is! Map) continue; + if ((row['audiourl'] ?? '').toString().isEmpty) continue; + final title = (row['title'] ?? '').toString(); + final path = (row['filepath'] ?? '').toString(); + if (title.isEmpty || path.isEmpty) continue; + out[title.toUpperCase()] = path; + } + return out; + } catch (e) { + Logger.w(_tag, '读本地记录失败,本轮不清理设备文件: $e'); + return const {}; + } + } + + /// 这个设备文件是不是「已上传,且本机那份与它逐字节等长」。 + Future _safeToDelete( + Map uploaded, DeviceFileEntry f) async { + final path = uploadedLocalPathFor(uploaded, f.name); + if (path == null) return false; + try { + final local = File(path); + if (!await local.exists()) return false; + final len = await local.length(); + if (len != f.size) { + Logger.w(_tag, + '${f.name} 本机 $len B 与设备 ${f.size} B 不符,不删(可能是同名的新录音)'); + return false; + } + return true; + } catch (e) { + Logger.w(_tag, '校验本机文件失败 ${f.name},不删: $e'); + return false; + } + } + + /// 把「已导入且已上传」的设备原件删掉。 + /// + /// 在导入之前先跑:先腾空间再往里写,卡快满时这个顺序才救得回来。 + Future _cleanup( + DeviceSession session, + DeviceFileStore store, + List files, + DeviceFileCancelToken cancel, + ) async { + if (!autoDeleteAfterImport) return; + if (files.isEmpty) return; + final uploaded = await _uploadedRecords(); + if (uploaded.isEmpty) return; + + final done = _doneMap(); + var changed = false; + for (final f in files) { + if (cancel.isCancelled) break; + // 设备一开始录音就停手:协议 §5.10 规定录音/传输中删除会回 BUSY, + // 而且正在写的那个文件绝对不能碰。 + if (store.isDeviceRecording) { + Logger.i(_tag, '设备开始录音,停止清理'); + break; + } + if (!await _safeToDelete(uploaded, f)) continue; + try { + await store.delete(f.name); + // 文件没了,指纹也不用留(名字回绕后同名新文件才不会被当成已导入) + if (done.remove(_fingerprint(session.deviceId, f)) != null) { + changed = true; + } + deletedCount.value = deletedCount.value + 1; + Logger.i(_tag, '设备原件已删除 ${f.name}(${f.size} B,已确认上传)'); + } catch (e) { + // 删不掉不是灾难:下一轮还会再试。指纹保留着,别丢。 + Logger.w(_tag, '删除设备文件失败 ${f.name}: $e'); + } + } + if (changed) _writeDone(done); + if (deletedCount.value > 0) { + Logger.i(_tag, '本轮清理了 ${deletedCount.value} 个设备文件'); + } + } +} diff --git a/apps/client/lib/data/services/device_recording_service.dart b/apps/client/lib/data/services/device_recording_service.dart new file mode 100644 index 00000000..11534350 --- /dev/null +++ b/apps/client/lib/data/services/device_recording_service.dart @@ -0,0 +1,284 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:get/get.dart'; +import 'package:intl/intl.dart'; +import 'package:path_provider/path_provider.dart'; + +import '../../core/utils/logger.dart'; +import '../../devices/device_hub.dart'; +import 'recording_archive.dart'; +import 'wav_writer.dart'; + +/// 设备主麦录音(现场录音)的全局采集与归档服务——**厂商无关**。 +/// +/// 替代原先各写一份的 BesRecordingService / HolderRecordingService: +/// 谁声明了 [DeviceCapability.micRecording] 就能录, +/// 设备按键起停走 `record.started` / `record.stopped` feature 事件, +/// 音频走 `openMic(mic)`(插件负责让设备开始上行、解码成 16k PCM、挑帧)。 +/// +/// 常驻:设备端按键在任意页面(含页面未打开)都要生效。 +class DeviceRecordingService extends GetxService { + static const String _tag = 'DeviceRecording'; + static DeviceRecordingService get to => Get.find(); + + /// 当前是否正在录(由设备端状态驱动) + final RxBool isRecording = false.obs; + + /// 已录毫秒数 + final RxInt elapsedMs = 0.obs; + + /// 当前电平 0~1,供波形使用 + final RxDouble level = 0.0.obs; + + /// 波形采样序列(固定 [sampleIntervalMs] 一格) + final RxList waveform = [].obs; + static const int sampleIntervalMs = 100; + static const int _maxSamples = 600; + + StreamSubscription? _hubSub; + DeviceSession? _session; + DeviceAudioSource? _src; + StreamSubscription? _audioSub; + WavWriter? _wav; + String? _path; + Timer? _tick; + Timer? _sampleTimer; + final Stopwatch _stopwatch = Stopwatch(); + bool _firstPcmLogged = false; + DateTime? _cmdSentAt; + bool _busy = false; + + @override + void onInit() { + super.onInit(); + _hubSub = DeviceHub.to.sessionEvents.listen(_onSessionEvent); + } + + @override + void onClose() { + _hubSub?.cancel(); + _audioSub?.cancel(); + _tick?.cancel(); + _sampleTimer?.cancel(); + super.onClose(); + } + + void _onSessionEvent(DeviceSessionEvent e) async { + switch (e.type) { + case DeviceSessionEventType.feature: + final key = e.feature?.key; + if (_busy) return; + // 通话中的录音键归通话录音管(DeviceCallRecordingService) + if (key == DeviceFeatureKeys.recordStarted && + !isRecording.value && + !DeviceHub.to.inCall.value) { + Logger.i(_tag, '设备端开始录音,启动本地采集'); + await start(deviceId: e.deviceId); + } else if (key == DeviceFeatureKeys.recordStopped && isRecording.value) { + Logger.i(_tag, '设备端结束录音,落盘并归档'); + await stop(); + } + break; + case DeviceSessionEventType.connectionStateChanged: + if (e.connectionState == DeviceConnectionState.disconnected && + isRecording.value && + _session?.deviceId == e.deviceId) { + Logger.w(_tag, '设备断开,结束当前录音'); + stop(); + } + break; + default: + break; + } + } + + /// 开始本地采集。[sendCommand] = true 时同时下发设备开始指令(App 主动发起)。 + Future start({bool sendCommand = false, String? deviceId}) async { + if (isRecording.value || _busy) return isRecording.value; + _busy = true; + try { + return await _start(sendCommand, deviceId); + } finally { + _busy = false; + } + } + + Future _start(bool sendCommand, String? deviceId) async { + final hub = DeviceHub.to; + final session = (deviceId == null + ? null + : hub.sessions.firstWhereOrNull((s) => s.deviceId == deviceId)) ?? + hub.sessionWith(DeviceCapability.micRecording); + if (session == null) return false; + _session = session; + + try { + final docs = await getApplicationDocumentsDirectory(); + final dir = Directory('${docs.path}/field_recordings'); + if (!await dir.exists()) await dir.create(recursive: true); + final ts = DateFormat('yyyyMMdd_HHmmss').format(DateTime.now()); + _path = '${dir.path}/${session.vendor}_$ts.wav'; + _wav = await WavWriter.open(_path!, channels: 1); + + _firstPcmLogged = false; + _cmdSentAt = null; + + if (sendCommand) { + // 顺序:先让设备进录音态,再开上行(支架的编码器必须在切状态之后开, + // 否则会被 toggle 顺手关掉;恒玄的 AA 59 与订阅先后无关)。 + final t0 = DateTime.now(); + final r = await session.invokeFeature(DeviceFeatures.recordStart); + _cmdSentAt = DateTime.now(); + if (r['ok'] == false) { + await _closeFile(save: false); + return false; + } + Logger.i(_tag, + '已下发 record.start,写入耗时 ${_cmdSentAt!.difference(t0).inMilliseconds}ms'); + } + + _src = await session.openMic(route: AudioRoute.mic); + _audioSub = _src!.pcm.listen(_onPcm); + + isRecording.value = true; + elapsedMs.value = 0; + level.value = 0; + waveform.clear(); + _stopwatch.reset(); + // 时长按**已写入的数据量**算,不用墙钟:显示值与文件实际播放长度永远一致 + // (恒玄收到 AA 59 后要 1.8~6.2s 才开始上行,还会把等待期缓存的音频补推)。 + final bytesPerMs = _src!.format.bytesPerMs; + _tick = Timer.periodic(const Duration(milliseconds: 200), (_) { + elapsedMs.value = _wav == null ? 0 : _wav!.dataBytes ~/ bytesPerMs; + }); + _sampleTimer = Timer.periodic( + const Duration(milliseconds: sampleIntervalMs), + (_) => _sample(), + ); + Logger.i(_tag, '开始录制: $_path (${session.vendor})'); + return true; + } catch (e) { + Logger.e(_tag, '启动本地采集失败: $e'); + await _closeFile(save: false); + return false; + } + } + + /// 停止。[sendCommand] = true 时同时下发设备停止指令。 + Future stop({bool sendCommand = false}) async { + if (!isRecording.value || _busy) return; + _busy = true; + try { + await _stop(sendCommand); + } finally { + _busy = false; + } + } + + Future _stop(bool sendCommand) async { + _tick?.cancel(); + _sampleTimer?.cancel(); + _stopwatch.stop(); + + await _audioSub?.cancel(); + _audioSub = null; + await _src?.close(); + _src = null; + // 等队列写完再关文件,否则最后几帧会丢、WAV 头长度也对不上 + await _wav?.drain(); + + final int dataBytes = _wav?.dataBytes ?? 0; + final int seconds = elapsedMs.value ~/ 1000; + final String? path = _path; + final wallMs = _stopwatch.elapsedMilliseconds; + Logger.i( + _tag, + '录音统计: 音频${(dataBytes / 32000).toStringAsFixed(2)}s 数据${dataBytes}B ' + '墙钟${(wallMs / 1000).toStringAsFixed(2)}s ' + '写入${_wav?.writtenFrames}帧 丢${_wav?.droppedFrames}帧'); + + final session = _session; + if (sendCommand && + session != null && + session.state == DeviceConnectionState.ready) { + try { + await session.invokeFeature(DeviceFeatures.recordStop, { + if (path != null) + 'fileName': path.split('/').last.replaceAll('.wav', ''), + }); + } catch (e) { + Logger.e(_tag, '下发停止指令失败: $e'); + } + } + + await _closeFile(save: true); + isRecording.value = false; + elapsedMs.value = 0; + level.value = 0; + waveform.clear(); + _session = null; + + if (path != null && dataBytes > 0) { + await RecordingArchive.archive(path: path, seconds: seconds, tag: _tag); + } else { + Logger.w(_tag, '本次没有收到音频数据,删除空文件'); + if (path != null) { + try { + final f = File(path); + if (await f.exists()) await f.delete(); + } catch (e) { + Logger.e(_tag, '删除空录音文件失败: $e'); + } + } + } + _path = null; + } + + void _onPcm(Uint8List pcm) { + final w = _wav; + if (w == null || pcm.isEmpty) return; + if (!_firstPcmLogged) { + _firstPcmLogged = true; + if (!_stopwatch.isRunning) _stopwatch.start(); + final sent = _cmdSentAt; + Logger.i( + _tag, + '首帧音频到达' + '${sent != null ? ",距 record.start ${DateTime.now().difference(sent).inMilliseconds}ms" : ""}' + ',计时从此刻开始'); + } + // 串行写,绝不在回调里直接 await 文件(见 WavWriter);电平只是显示,不能挡写入 + w.write(pcm, onWritten: () { + try { + _updateLevel(pcm); + } catch (_) {} + }); + } + + void _sample() { + final list = waveform.toList(); + list.add(level.value); + if (list.length > _maxSamples) { + list.removeRange(0, list.length - _maxSamples); + } + waveform.assignAll(list); + } + + void _updateLevel(Uint8List pcm) { + level.value = WavWriter.rmsLevel(pcm); + } + + Future _closeFile({required bool save}) async { + await _audioSub?.cancel(); + _audioSub = null; + await _src?.close(); + _src = null; + final w = _wav; + _wav = null; + if (w == null) return; + await w.close(save: save); + } +} diff --git a/apps/client/lib/data/services/device_stereo_recorder.dart b/apps/client/lib/data/services/device_stereo_recorder.dart new file mode 100644 index 00000000..eaf8eb81 --- /dev/null +++ b/apps/client/lib/data/services/device_stereo_recorder.dart @@ -0,0 +1,103 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; + +import '../../core/utils/logger.dart'; +import '../../devices/device_hub.dart'; +import 'wav_writer.dart'; + +/// 把设备的通话双路(本端 / 对端)录成一个**双声道 WAV** 的小工具, +/// 给「语音纪要 → 通话录音」这类要自己指定文件路径的页面用。 +/// +/// 与常驻的 DeviceCallRecordingService 的区别:这个是页面持有的一次性对象, +/// 文件放哪、什么时候停都由调用方决定,不归档。 +/// 左声道=本端麦克风,右声道=对端声音。 +class DeviceStereoRecorder { + DeviceStereoRecorder({this.onWavePcm}); + + static const String _tag = 'DeviceStereoRecorder'; + + /// 每写一对帧回调一次本端 PCM(驱动波形) + final void Function(Uint8List pcm)? onWavePcm; + + DeviceSession? _session; + DeviceAudioSource? _local; + DeviceAudioSource? _peer; + StreamSubscription? _localSub; + StreamSubscription? _peerSub; + WavWriter? _wav; + Uint8List? _pendingPeer; + bool _paused = false; + + bool get isRunning => _wav != null; + + /// 开始。没有具备通话双路抓音能力的设备返回 false。 + Future start(String filePath) async { + if (isRunning) return true; + final session = DeviceHub.to.sessionWith(DeviceCapability.callAudioTap); + if (session == null) { + Logger.w(_tag, '没有具备通话双路抓音能力的设备'); + return false; + } + try { + _session = session; + _wav = await WavWriter.open(filePath, channels: 2); + _pendingPeer = null; + _paused = false; + _peer = await session.openMic(route: AudioRoute.callPeer); + _local = await session.openMic(route: AudioRoute.callLocal); + _peerSub = _peer!.pcm.listen((pcm) { + if (_paused || pcm.isEmpty) return; + _pendingPeer = pcm; + }); + _localSub = _local!.pcm.listen((pcm) { + if (_paused || pcm.isEmpty) return; + final peer = _pendingPeer; + _pendingPeer = null; + if (peer == null) return; + _wav?.write(WavWriter.interleave(pcm, peer), + onWritten: () => onWavePcm?.call(pcm)); + }); + await session.invokeFeature(DeviceFeatures.callStart); + return true; + } catch (e) { + Logger.e(_tag, '启动失败: $e'); + await _shutdown(saveFile: false); + return false; + } + } + + void pause() => _paused = true; + + void resume() => _paused = false; + + Future stop({required bool save}) async { + if (!isRunning) return true; + await _shutdown(saveFile: save); + return true; + } + + Future _shutdown({required bool saveFile}) async { + await _localSub?.cancel(); + await _peerSub?.cancel(); + _localSub = null; + _peerSub = null; + await _local?.close(); + await _peer?.close(); + _local = null; + _peer = null; + final s = _session; + _session = null; + if (s != null && s.state == DeviceConnectionState.ready) { + try { + await s.invokeFeature(DeviceFeatures.callStop); + } catch (e) { + Logger.w(_tag, 'call.stop 失败: $e'); + } + } + final w = _wav; + _wav = null; + await w?.close(save: saveFile); + } +} diff --git a/apps/client/lib/data/services/network/api.dart b/apps/client/lib/data/services/network/api.dart index c4a43644..0d1bde60 100644 --- a/apps/client/lib/data/services/network/api.dart +++ b/apps/client/lib/data/services/network/api.dart @@ -345,15 +345,6 @@ class Api { ); } - //绑定设备 - static bindauthcode([params]) { - return DioManager().request( - NWMethod.post, - '/api/home/user_bindauthcode', - params: params, - ); - } - //创建支付订单 static paycreateorder([params]) { return DioManager().request( @@ -473,6 +464,19 @@ class Api { ); } + /// 会员与算力状态(`/api/home/user_getcompute`)。 + /// + /// 一次拿齐:`vip{level, exptime, selfexptime, devices[]}`(自购与设备赋予合并后的有效值)、 + /// `compute{deviceleft, userbalance, totalused, monthused}`、`rates{translate, meeting, aichat, gate}`。 + /// 客户端**不做任何换算**,展示服务端给的数;`rates` 只用于本地预估文案。 + static getCompute([params]) { + return DioManager().request( + NWMethod.post, + '/api/home/user_getcompute', + params: params ?? {}, + ); + } + static getwakeupvoices([params]) { return DioManager().request( NWMethod.post, diff --git a/apps/client/lib/data/services/network/auth_interceptor.dart b/apps/client/lib/data/services/network/auth_interceptor.dart index 47ed97b9..16be3fe9 100644 --- a/apps/client/lib/data/services/network/auth_interceptor.dart +++ b/apps/client/lib/data/services/network/auth_interceptor.dart @@ -1,4 +1,5 @@ import 'package:dio/dio.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart' hide Response; import 'dart:convert'; @@ -7,10 +8,16 @@ import 'package:crypto/crypto.dart'; import 'package:get_storage/get_storage.dart'; import '../../../core/utils/logger.dart'; import 'entity/base_entity.dart'; +import '../../../routes/app_routes.dart'; class AuthInterceptor extends Interceptor { final GetStorage _storage = GetStorage(); - final String _signKey = '@214%67g15q4*67m17#4l67!'; // 替换为实际的密钥 + /// 请求签名密钥。优先读 .env 的 API_SIGN_KEY,没配时用内置默认值 + /// (与 Go 端保持一致,改这里要同步服务端)。 + static String get _signKey => + (dotenv.env['API_SIGN_KEY'] ?? '').trim().isNotEmpty + ? dotenv.env['API_SIGN_KEY']!.trim() + : '@214%67g15q4*67m17#4l67!'; bool _shouldSuppressErrorSnackbar(DioException err) { final path = err.requestOptions.path; @@ -84,8 +91,8 @@ class AuthInterceptor extends Interceptor { String _generateSign(String timestamp) { // 按照“MD5(私钥 + 时间戳)”生成签名,与 Go 端保持一致 + // ⚠️ 别把 signStr 打进日志:里面是明文密钥 final signStr = 'ts=${timestamp}key=${_signKey}'; - print("signStr: $signStr"); return md5.convert(utf8.encode(signStr)).toString(); } @@ -107,6 +114,13 @@ class AuthInterceptor extends Interceptor { if (_isNotLoggedInMessage(rawMessage)) { return; } + // 5302 VipRequired:翻译 / 会议纪要在 VIP 过期后受限。这不是「错误」,是引导—— + // 弹开通窗而不是红色错误条,并且要同时给「续费」与「绑定带会员的设备」两条路, + // 设备也能带来 VIP,只说充值会漏掉一半用户。 + if (entity.code == _codeVipRequired) { + _showVipRequired(rawMessage); + return; + } final lowerMessage = rawMessage.toLowerCase(); final displayMessage = lowerMessage.contains('record not found') ? 'requestedResourceNotFound'.tr @@ -123,6 +137,36 @@ class AuthInterceptor extends Interceptor { } } + /// 服务端 pb.ErrorCode_VipRequired。 + static const int _codeVipRequired = 5302; + static bool _vipDialogShowing = false; + + void _showVipRequired(String message) { + // 同一屏可能连着几个请求都被拒(同传里 ASR 每句话一次翻译),只弹一次 + if (_vipDialogShowing) return; + _vipDialogShowing = true; + Get.dialog( + AlertDialog( + title: Text('vipRequiredTitle'.tr), + content: Text(message.isNotEmpty ? message : 'vipRequiredDesc'.tr), + actions: [ + TextButton( + onPressed: () => Get.back(), + child: Text('cancel'.tr), + ), + TextButton( + onPressed: () { + Get.back(); + Get.toNamed(Routes.goodsvip); + }, + child: Text('vipRequiredGo'.tr), + ), + ], + ), + barrierDismissible: true, + ).whenComplete(() => _vipDialogShowing = false); + } + @override void onError(DioException err, ErrorInterceptorHandler handler) { switch (err.type) { diff --git a/apps/client/lib/data/services/ota_check_service.dart b/apps/client/lib/data/services/ota_check_service.dart index 13a5f09d..d1cfd3dd 100644 --- a/apps/client/lib/data/services/ota_check_service.dart +++ b/apps/client/lib/data/services/ota_check_service.dart @@ -1,149 +1,100 @@ +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; + import '../../core/utils/logger.dart'; +import '../../core/utils/version_compare.dart'; +import '../../devices/device_hub.dart'; import '../../routes/app_routes.dart'; -import '../../modules/ota_upgrade/controllers/ota_core_contropller.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; +import '../models/appconfig.dart'; +import '../models/appconfig_model.dart'; -/// OTA检查服务 -/// 负责管理全局OTA检查状态,确保在应用生命周期内只检查一次 +/// 连上设备后的固件升级检查(一次会话只提醒一次)——厂商无关。 +/// +/// 当前版本来自在线会话的 [DeviceInfo.firmwareVersion],最新版本来自 +/// `user_getappconfig` 下发的产品配置(按设备名匹配)。 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(); - @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; - } + bool shouldCheckOta() => !_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; - Logger.d(_tag, '当前路由: $currentRoute, 是否在Home页面: $isOnHome'); - return isOnHome; + return currentRoute == Routes.home || currentRoute == Routes.initial; } - /// 执行OTA升级检查 - /// [isFullyConnected] 设备是否完全连接 - /// 返回是否成功执行了检查 + DBProduct? _findProduct(String name) { + if (!AppConfig.isInitialized()) return null; + final n = name.trim().toUpperCase(); + if (n.isEmpty) return null; + for (final p in AppConfig.config.products) { + final pn = p.devicename.trim().toUpperCase(); + if (pn.isEmpty) continue; + if (pn.contains(n) || n.contains(pn)) return p; + } + return null; + } + + /// 执行一次检查。[isFullyConnected] 为 false 直接跳过。返回是否真的检查了。 Future performOtaCheck(bool isFullyConnected) async { bool isForceUpdate = false; try { - // 检查是否应该进行OTA检查 - if (!shouldCheckOta()) { - Logger.d(_tag, '跳过OTA检查 - 已检查过或正在检查中'); - return false; - } - - // 检查设备连接状态 - if (!isFullyConnected) { - Logger.d(_tag, '设备未完全连接,跳过OTA检查'); - return false; - } - - // 检查当前页面 - if (!_isCurrentlyOnHomePage()) { - Logger.d(_tag, '当前不在Home页面,跳过OTA检查'); - return false; - } + if (!shouldCheckOta()) return false; + if (!isFullyConnected) return false; + if (!_isCurrentlyOnHomePage()) return false; - // 标记为检查中 + final session = DeviceHub.to.sessionWith(DeviceCapability.ota); + if (session == null) 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; + final currentVersion = session.info.firmwareVersion ?? ''; + final product = _findProduct(session.info.name); + final latestVersion = product?.version?.split('+').first.trim() ?? ''; Logger.d(_tag, '当前版本: $currentVersion, 最新版本: $latestVersion'); - // 检查是否有更新 - final hasUpdate = - _otaCoreService.isNewVersionAvailable(currentVersion, latestVersion); - + final hasUpdate = latestVersion.isNotEmpty && + (currentVersion.isEmpty || + VersionCompare.isNewer(latestVersion, currentVersion)); if (hasUpdate) { - isForceUpdate = latestInfo['isForceUpdate'] as bool? ?? false; - if (isForceUpdate) { - Logger.d(_tag, '发现强制更新版本,准备显示升级提醒'); - } else { - Logger.d(_tag, '发现新版本,准备显示升级提醒'); - } - - // 再次确认当前在Home页面(防止异步执行期间页面切换) + isForceUpdate = product?.isforceupdate ?? false; if (_isCurrentlyOnHomePage()) { - _showOtaUpgradeDialog( - latestVersion, latestInfo['updateDescription'] as String?); - } else { - Logger.d(_tag, '检查完成时已不在Home页面,取消显示弹窗'); + _showOtaUpgradeDialog(latestVersion); } } else { Logger.d(_tag, '当前已是最新版本'); } - // 标记为已检查(无论是否有更新都标记为已检查) - if (!isForceUpdate) { - _markAsChecked(); - } + if (!isForceUpdate) _markAsChecked(); _isCheckingInProgress = false; return true; } catch (e) { Logger.e(_tag, '检查OTA升级失败: $e'); - // 即使检查失败,也标记为已检查,避免重复尝试 - if (!isForceUpdate) { - _markAsChecked(); - } + if (!isForceUpdate) _markAsChecked(); _isCheckingInProgress = false; return false; } } - /// 显示OTA升级提醒对话框 - /// [latestVersion] 最新版本号 - /// [updateDescription] 更新描述 - void _showOtaUpgradeDialog(String latestVersion, String? updateDescription) { - // 最后一次确认当前页面状态 - if (!_isCurrentlyOnHomePage()) { - Logger.d(_tag, '显示弹窗时发现不在Home页面,取消显示'); - return; - } + void _showOtaUpgradeDialog(String latestVersion) { + if (!_isCurrentlyOnHomePage()) return; final isDarkMode = Get.isDarkMode; - - Logger.d(_tag, '显示OTA升级提醒对话框'); - Get.dialog( AlertDialog( title: Row( @@ -154,18 +105,16 @@ class OtaCheckService extends GetxService { size: 24.sp, ), SizedBox(width: 8.w), - // 使用Flexible确保标题文本能够自适应不同语言长度,避免溢出 Flexible( child: Text( - 'ota_newVersionFound'.tr, // 发现新版本 + 'ota_newVersionFound'.tr, style: TextStyle( color: isDarkMode ? Colors.white : Colors.blue[700], fontWeight: FontWeight.w600, - fontSize: 20.sp, // 设置合适的字体大小 + fontSize: 20.sp, ), - softWrap: true, // 启用软换行 - overflow: TextOverflow.visible, // 确保文本完全显示 - maxLines: 2, // 最多显示两行 + softWrap: true, + maxLines: 2, ), ), ], @@ -188,12 +137,8 @@ class OtaCheckService extends GetxService { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - // 稍后再说 (靠左) TextButton( - onPressed: () { - Logger.d(_tag, '用户取消OTA升级'); - Get.back(); - }, + onPressed: () => Get.back(), child: Text( 'talkLater'.tr, style: TextStyle( @@ -201,12 +146,10 @@ class OtaCheckService extends GetxService { ), ), ), - // 立即升级 (靠右) ElevatedButton( onPressed: () { - Logger.d(_tag, '用户确认OTA升级,跳转到升级页面'); Get.back(); - Get.toNamed(Routes.OTA_UPGRADE); + Get.toNamed(Routes.otaUpgrade); }, style: ElevatedButton.styleFrom( backgroundColor: @@ -219,30 +162,22 @@ class OtaCheckService extends GetxService { ? BorderSide(color: Colors.grey[800]!, width: 1) : BorderSide.none, ), - child: Text( - 'ota_updateNow'.tr, - style: TextStyle(fontSize: 14.sp), - ), + child: Text('ota_updateNow'.tr, style: TextStyle(fontSize: 14.sp)), ), ], ), ], - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.sp), - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.sp)), backgroundColor: isDarkMode ? const Color(0xFF1A1A1A) : Colors.white, ), - barrierDismissible: true, // 允许点击外部关闭 + barrierDismissible: true, ); } - /// 获取当前检查状态(用于调试) - Map getCheckStatus() { - return { - 'hasCheckedInCurrentSession': _hasCheckedInCurrentSession, - 'isCheckingInProgress': _isCheckingInProgress, - 'currentRoute': Get.currentRoute, - 'isOnHomePage': _isCurrentlyOnHomePage(), - }; - } + Map getCheckStatus() => { + 'hasCheckedInCurrentSession': _hasCheckedInCurrentSession, + 'isCheckingInProgress': _isCheckingInProgress, + 'currentRoute': Get.currentRoute, + 'isOnHomePage': _isCurrentlyOnHomePage(), + }; } diff --git a/apps/client/lib/data/services/recording_archive.dart b/apps/client/lib/data/services/recording_archive.dart index 123a59ec..d47a5f37 100644 --- a/apps/client/lib/data/services/recording_archive.dart +++ b/apps/client/lib/data/services/recording_archive.dart @@ -5,7 +5,9 @@ import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import '../../core/utils/logger.dart'; +import '../utils/recording_time.dart'; import 'db/sqflite_api.dart'; +import 'meeting/meeting_task_service.dart'; import 'meeting/meeting_upload_service.dart'; import 'network/api.dart'; @@ -29,11 +31,15 @@ class RecordingArchive { /// /// 返回服务端记录 id;失败返回 null(文件会原地保留,不会丢)。 /// [notify] 为 true 时弹一条「已存入语音记录助手」的提示。 + /// [createdAt] 这段录音**实际录制**的时刻。边录边存的四条链路不用传(就是现在), + /// 但从设备存储同步进来的历史录音必须传 —— 否则列表上一条 8 月 15 日录的东西 + /// 会显示成「刚刚」,用户按时间根本找不到它。 static Future archive({ required String path, required int seconds, String tag = 'RecordingArchive', bool notify = true, + DateTime? createdAt, }) async { try { final file = File(path); @@ -70,7 +76,7 @@ class RecordingArchive { 'filepath': newPath, 'audiourl': '', 'tasktype': 0, - 'creationtime': DateTime.now().millisecondsSinceEpoch, + 'creationtime': resolveRecordingCreationTime(createdAt), }; final resp = await Api.addRecordEchomeet({ 'rtype': 'LOCAL', @@ -87,6 +93,12 @@ class RecordingArchive { Get.find() .addUpload(meetingId, newPath, 'LocalAudio'); } + // 让语音纪要首页立刻重画。**不是可选的**:MeetingHomeController 只在 + // `updateListState` 变化时才重查本地库,不捅它就得退出页面再进来才看得到, + // 表现成「录完了/同步完了但列表里没有」。四条归档链路统一在这里捅一次。 + if (Get.isRegistered()) { + Get.find().updateListState.value++; + } Logger.i(tag, '已归档到语音记录助手 id=$meetingId title=$fileName'); if (notify) { Get.snackbar('recordingSavedTitle'.tr, 'recordingSavedDesc'.tr, diff --git a/apps/client/lib/data/services/wav_writer.dart b/apps/client/lib/data/services/wav_writer.dart new file mode 100644 index 00000000..09fbf0e8 --- /dev/null +++ b/apps/client/lib/data/services/wav_writer.dart @@ -0,0 +1,136 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:math' as math; +import 'dart:typed_data'; + +import '../../core/utils/logger.dart'; + +/// 串行写入的 WAV 文件(16k / 16bit)。 +/// +/// ⚠️ **必须串行写**:Stream.listen 的回调即使标了 async 也不会被等待, +/// 音频每秒上百帧,多次 writeFrom 必然重叠;Dart 的 RandomAccessFile 同一时刻 +/// 只允许一个异步操作,重叠调用会抛 "An async operation is currently pending", +/// 那一帧就丢了(实测等效采样率只剩 1587~5331Hz,播放又快又糊)。 +/// 用 Future 链把写入排成队列:既不丢帧,也保证顺序。 +class WavWriter { + WavWriter._(this._raf, this.path, this.channels, this.sampleRate); + + static const String _tag = 'WavWriter'; + + final RandomAccessFile _raf; + final String path; + final int channels; + final int sampleRate; + + int dataBytes = 0; + int writtenFrames = 0; + int droppedFrames = 0; + Future _chain = Future.value(); + bool _closed = false; + + static Future open(String path, + {int channels = 1, int sampleRate = 16000}) async { + final raf = await File(path).open(mode: FileMode.write); + final w = WavWriter._(raf, path, channels, sampleRate); + await raf.writeFrom(w._header(0)); + return w; + } + + /// 入队写一块 PCM。[onWritten] 在这一块真正落盘后回调(电平等只读用途)。 + void write(Uint8List pcm, {void Function()? onWritten}) { + if (_closed) return; + _chain = _chain.then((_) async { + if (_closed) return; + try { + await _raf.writeFrom(pcm); + dataBytes += pcm.length; + writtenFrames++; + onWritten?.call(); + } catch (e) { + droppedFrames++; + Logger.e(_tag, '写入 PCM 失败(已丢帧 $droppedFrames): $e'); + } + }); + } + + /// 等队列里的帧全部落盘。 + Future drain() async { + try { + await _chain; + } catch (_) {} + } + + /// 关闭;[save] = true 时回填 WAV 头的长度。 + Future close({required bool save}) async { + if (_closed) return; + await drain(); + _closed = true; + try { + if (save) { + await _raf.setPosition(0); + await _raf.writeFrom(_header(dataBytes)); + } + await _raf.close(); + } catch (e) { + Logger.e(_tag, '关闭录音文件失败: $e'); + } + } + + Uint8List _header(int dataLength) { + const bits = 16; + final byteRate = sampleRate * channels * (bits ~/ 8); + final h = ByteData(44); + void ascii(int off, String s) { + for (var i = 0; i < s.length; i++) { + h.setUint8(off + i, s.codeUnitAt(i)); + } + } + + ascii(0, 'RIFF'); + h.setUint32(4, 36 + dataLength, Endian.little); + ascii(8, 'WAVE'); + ascii(12, 'fmt '); + h.setUint32(16, 16, Endian.little); + h.setUint16(20, 1, Endian.little); + h.setUint16(22, channels, Endian.little); + h.setUint32(24, sampleRate, Endian.little); + h.setUint32(28, byteRate, Endian.little); + h.setUint16(32, channels * (bits ~/ 8), Endian.little); + h.setUint16(34, bits, Endian.little); + ascii(36, 'data'); + h.setUint32(40, dataLength, Endian.little); + return h.buffer.asUint8List(); + } + + /// PCM16 小端的 RMS 电平(0~1,开过根让波形更有跳动感)。 + /// + /// ⚠️ 不能用 `buffer.asInt16List(offsetInBytes, …)`:原生过来的 Uint8List 是 + /// 带 offset 的视图,偏移是奇数时直接抛 RangeError。按字节手工拼。 + static double rmsLevel(Uint8List pcm) { + final count = pcm.lengthInBytes ~/ 2; + if (count == 0) return 0; + var sum = 0.0; + for (var i = 0; i < count; i++) { + var v = (pcm[i * 2 + 1] << 8) | pcm[i * 2]; + if (v >= 0x8000) v -= 0x10000; + final n = v / 32768.0; + sum += n * n; + } + final rms = math.sqrt(sum / count); + return math.sqrt(rms).clamp(0.0, 1.0); + } + + /// 把两路单声道按字节交织成双声道(左=[left],右=[right])。 + static Uint8List interleave(Uint8List left, Uint8List right) { + final samples = (left.length < right.length ? left.length : right.length) ~/ 2; + final out = Uint8List(samples * 4); + for (var i = 0; i < samples; i++) { + final si = i * 2, di = i * 4; + out[di] = left[si]; + out[di + 1] = left[si + 1]; + out[di + 2] = right[si]; + out[di + 3] = right[si + 1]; + } + return out; + } +} diff --git a/apps/client/lib/data/utils/device_file_match.dart b/apps/client/lib/data/utils/device_file_match.dart new file mode 100644 index 00000000..a045da17 --- /dev/null +++ b/apps/client/lib/data/utils/device_file_match.dart @@ -0,0 +1,27 @@ +/// 「设备上这个文件,是不是已经安全落袋了」—— +/// **这是删除设备原件的唯一判据**,改它等于改一个不可逆操作的闸门。 +library; + +/// 归档标题形如 `_<时间戳>_<设备文件名>` +/// (`holder_20260907_181224_MIC0049.ogg` ← 设备上的 `MIC0049.OGG`)。 +/// +/// 在「已上传」的记录里按这个后缀找对应的那条,返回它在本机的音频路径; +/// 找不到返回 null。[uploadedByTitle] 的 key 必须已大写。 +/// +/// ⚠️ **只匹配到名字还不够,调用方必须再比一次字节数**:设备用的是 8.3 短 +/// 文件名,删掉后会**回绕复用**(`MIC0001.OGG` 下次录音可能又叫这个名)。 +/// 只认名字的话,一条同名的新录音会被当成「已上传」直接删掉 —— 永久丢数据。 +/// 字节数的来源刻意选了「本机那份音频的实际长度」而不是数据库里的字段: +/// `meeting` 表**根本没有 size 列**(schema 见 database_helper.dart), +/// 而且比文件长度顺带证明了本机这份没被截断、确实是同一个文件。 +String? uploadedLocalPathFor( + Map uploadedByTitle, + String deviceFileName, +) { + if (deviceFileName.isEmpty) return null; + final suffix = '_${deviceFileName.toUpperCase()}'; + for (final e in uploadedByTitle.entries) { + if (e.key.endsWith(suffix) && e.value.isNotEmpty) return e.value; + } + return null; +} diff --git a/apps/client/lib/data/utils/ogg_opus_duration.dart b/apps/client/lib/data/utils/ogg_opus_duration.dart new file mode 100644 index 00000000..912090ff --- /dev/null +++ b/apps/client/lib/data/utils/ogg_opus_duration.dart @@ -0,0 +1,93 @@ +/// Ogg Opus 时长解析 —— **不解码、不依赖播放器**。 +/// +/// Opus 的 granule position 恒以 **48kHz** 计样本(RFC 7845 §4,与音频本身的 +/// 采样率无关),所以「最后一个 Ogg page 的 granulepos 减去 OpusHead 里的 +/// pre-skip,再除以 48000」就是精确时长。 +/// +/// 为什么不用现成的播放器: +/// - ⚠️ `just_audio` 的 `setFilePath` 对支架录的这种裸 Ogg Opus **两端都报 +/// `Source error`**(Android/iOS 真机实测),拿不到时长; +/// - ⚠️ 按码率估会明显失真:真机那条 38400 字节的录音实际 9.16s, +/// 按 16kbps 估是 19.2s,差一倍,列表上一眼就看得出来。 +library; + +import 'dart:io'; + +const List _oggS = [0x4F, 0x67, 0x67, 0x53]; // 'OggS' +const List _opusHead = [ + 0x4F, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64 // 'OpusHead' +]; + +/// Opus 的 granulepos 单位,**恒为 48000**,不是音频采样率。 +/// 写成 16000 会把时长算成 3 倍。 +const int _opusGranuleRate = 48000; + +/// 从「文件头若干字节」和「文件尾若干字节」解出时长(秒)。 +/// +/// [head] 至少要覆盖第一个 page(含 OpusHead);[tail] 至少要覆盖最后一个 +/// page 的头部。不是 Ogg、或没有可用的 granulepos 时返回 null。 +double? oggOpusSecondsFrom(List head, List tail) { + if (head.length < 4 || _indexOf(head, _oggS) != 0) return null; // 不是 'OggS' + + final hi = _indexOf(head, _opusHead); + // OpusHead 布局:magic(8) version(1) channels(1) pre-skip(2, LE) + final preSkip = + hi >= 0 && hi + 12 <= head.length ? head[hi + 10] | (head[hi + 11] << 8) : 0; + + final ti = _lastIndexOf(tail, _oggS); + if (ti < 0 || ti + 14 > tail.length) return null; + + // page 头偏移 6 起的 8 字节小端就是 granulepos + var granule = 0; + for (var b = 7; b >= 0; b--) { + granule = (granule << 8) | tail[ti + 6 + b]; + } + if (granule <= preSkip) return null; + return (granule - preSkip) / _opusGranuleRate; +} + +/// 读文件解时长。不是 Ogg Opus 返回 null。 +/// +/// 只读头 4KB 和尾 128KB —— Ogg page 最大 65307 字节,128KB 必然覆盖到 +/// 最后一个 page,不用把整个文件读进内存(录音可能几十兆)。 +Future oggOpusSeconds(File file) async { + final raf = await file.open(); + try { + final len = await raf.length(); + if (len < 47) return null; // 连一个 OpusHead page 都放不下 + + await raf.setPosition(0); + final head = await raf.read(len < 4096 ? len : 4096); + + const tailLen = 128 * 1024; + final from = len > tailLen ? len - tailLen : 0; + await raf.setPosition(from); + final tail = await raf.read(len - from); + + return oggOpusSecondsFrom(head, tail); + } finally { + await raf.close(); + } +} + +int _indexOf(List hay, List needle) { + outer: + for (var i = 0; i + needle.length <= hay.length; i++) { + for (var j = 0; j < needle.length; j++) { + if (hay[i + j] != needle[j]) continue outer; + } + return i; + } + return -1; +} + +int _lastIndexOf(List hay, List needle) { + outer: + for (var i = hay.length - needle.length; i >= 0; i--) { + for (var j = 0; j < needle.length; j++) { + if (hay[i + j] != needle[j]) continue outer; + } + return i; + } + return -1; +} diff --git a/apps/client/lib/data/utils/recording_time.dart b/apps/client/lib/data/utils/recording_time.dart new file mode 100644 index 00000000..ad422fdd --- /dev/null +++ b/apps/client/lib/data/utils/recording_time.dart @@ -0,0 +1,28 @@ +/// 一条录音在列表里该显示的「录制时间」。 +/// +/// [deviceTime] 是设备自己记的时间(如 EaiRec 支架 TF 卡文件的 FAT 时间戳)。 +/// +/// ⚠️ **设备给的时间不能无条件相信**:支架在 RTC 对时之前写的文件,时间戳是 +/// 1980 / 2018 这类垃圾值(2026-09-10 真机那张卡上就有一批 `2018-08-10`)。 +/// 直接采信的话,这些记录会沉到列表最底下,用户按时间根本找不到。 +/// +/// 所以只接受「2020 年之后、且不超过明天」的值,其余退回当前时刻: +/// 显示成「刚导入」是次优但可用,显示成 2018 年是直接丢失。 +/// +/// ⚠️ **当前这个值在列表上还看不到效果,别以为这段是死代码把它删了。** +/// 服务端 `echomeet_addrecord` 把 `Creationtime` 写死成 `time.Now().Unix()` +/// (`EchomeetAddRecordReq` 里压根没有这个字段),而 `Synchrodata._synchrodata()` +/// 会拿服务端的值**整行 update** 覆盖本地库 —— 于是列表上显示的永远是「导入时刻」。 +/// 录制时间目前只活在标题里(`holder_20260907_181224_MIC0049.ogg`)。 +/// 要让它真正生效,服务端要做两件事:`EchomeetAddRecordReq` 加 `creationtime` +/// 字段,`AddRecord` 在传了合法值时用它而不是 `time.Now()`。 +/// 客户端这一侧已经按「服务端接受」的形状送上去了,接口一改就自动生效。 +int resolveRecordingCreationTime(DateTime? deviceTime, {DateTime? now}) { + final n = now ?? DateTime.now(); + if (deviceTime == null) return n.millisecondsSinceEpoch; + if (deviceTime.year < 2020) return n.millisecondsSinceEpoch; + if (deviceTime.isAfter(n.add(const Duration(days: 1)))) { + return n.millisecondsSinceEpoch; + } + return deviceTime.millisecondsSinceEpoch; +} diff --git a/apps/client/lib/devices/bes/bes_bluetooth_service.dart b/apps/client/lib/devices/bes/bes_bluetooth_service.dart index 0ebe305d..c3d9f9c3 100644 --- a/apps/client/lib/devices/bes/bes_bluetooth_service.dart +++ b/apps/client/lib/devices/bes/bes_bluetooth_service.dart @@ -8,9 +8,9 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import '../../core/utils/logger.dart'; -import 'agent_module_defaults.dart'; -import 'background_launch_consent.dart'; +import '../../data/services/background_launch_consent.dart'; import 'bes_device_auth.dart'; +import 'bes_protocol.dart'; /// 恒玄(BES/Bestechnic)芯片经典蓝牙连接服务。 /// @@ -28,6 +28,12 @@ class BesBluetoothService extends GetxService { final _manager = bes.BluetoothManager(); final _storage = GetStorage(); + /// 原生插件句柄。只给同目录的 [BesDevicePlugin] 用(AI 通道、下行编码)。 + bes.BluetoothManager get manager => _manager; + + /// 确权闸门(按 MAC 向服务端登记),由插件注入;null = 不确权。 + BesDeviceAuth? auth; + StreamSubscription? _statusSubscription; StreamSubscription? _cmdEventSubscription; @@ -216,7 +222,8 @@ class BesBluetoothService extends GetxService { // // 只有 denied 会中止:unknown(断网/未登录/产品表没下发)一律放行, // 理由见 BesDeviceAuth 的类注释。 - final auth = await BesDeviceAuth.verifyConnected(); + final auth = await (this.auth?.verifyConnected() ?? + Future.value(BesAuthResult.unknown)); if (auth == BesAuthResult.denied) { // 断开与提示已由 BesDeviceAuth 就地做完(此时 connectedDeviceId // 已被清空,别再拿它打日志),这里只是不再往下走 @@ -225,13 +232,10 @@ class BesBluetoothService extends GetxService { } if (deviceStatus.value != 2) return; // 确权期间掉线了 - // 首次连上耳机 → AI 页铺开耳机的默认功能编排 - AgentDefaults.onEarphoneConnected(); - // 数据通道就绪后再发 0x06 获取固件版本 await Future.delayed(const Duration(milliseconds: 500)); if (deviceStatus.value == 2) { - await sendData([0xAA, 0x06]); + await sendData(BesCmd.frame(BesCmd.firmwareVersion)); await queryBattery(); _scheduleBatteryRetry(); // App 可能是在耳机已经通话中时才连上/重启回连的——0xD1/0xD2/0x02/0x03 @@ -368,11 +372,11 @@ class BesBluetoothService extends GetxService { Future refreshDeviceState() async { if (!isConnected) return; try { - await sendData([0xAA, 0x06]); + await sendData(BesCmd.frame(BesCmd.firmwareVersion)); await Future.delayed(const Duration(milliseconds: 120)); - await sendData([0xAA, 0x0C]); + await sendData(BesCmd.frame(BesCmd.keyConfig)); await Future.delayed(const Duration(milliseconds: 120)); - await sendData([0xAA, 0x10]); + await sendData(BesCmd.frame(BesCmd.eqConfig)); await Future.delayed(const Duration(milliseconds: 120)); // 电量会随时间掉,进功能页时重查一次,别只依赖连接那一刻的值 await queryBattery(); @@ -452,7 +456,7 @@ class BesBluetoothService extends GetxService { Future queryBattery() async { try { - await sendData([0xAA, 0x09]); + await sendData(BesCmd.frame(BesCmd.status)); } catch (e) { Logger.e(_tag, '查询电量失败: $e'); } @@ -499,7 +503,7 @@ class BesBluetoothService extends GetxService { /// 这条查询命令是唯一能补的办法,见连接握手和 [refreshDeviceState]。 Future queryCallState() async { try { - await sendData([0xAA, 0x0E]); + await sendData(BesCmd.frame(BesCmd.callState)); } catch (e) { Logger.e(_tag, '查询通话状态失败: $e'); } @@ -568,67 +572,38 @@ class BesBluetoothService extends GetxService { /// 3. **电量字节最高位是充电指示位**,必须 `& 0x7F` 取百分比。 /// 直接用原字节,充电时会得到 128~228 的假电量。 void _parseBattery(List data) { - var p = 3; // 跳过 SOF + CMD + 1 字节长度 - var hit = false; - while (p + 2 < data.length) { - final blockLen = data[p]; - if (blockLen < 2 || p + blockLen >= data.length) break; - final attr = data[p + 1]; - final raw = data[p + 2]; - final level = raw & 0x7F; // 低 7 位是百分比 - final charging = (raw & 0x80) != 0; // 最高位是充电指示 - if (level <= 100) { - switch (attr) { - case 0x01: - batteryLeft.value = level; - chargingLeft.value = charging; - hit = true; - break; - case 0x02: - batteryRight.value = level; - chargingRight.value = charging; - hit = true; - break; - case 0x03: - batteryCase.value = level; - chargingCase.value = charging; - hit = true; - break; - } - } - // 属性 7 = 耳机蓝牙地址(6 字节)。这是**耳机自己报上来的**真 MAC, - // 不经过系统蓝牙 API,所以 iOS 上也拿得到——iOS 的 connectedDeviceId - // 是 CoreBluetooth 的 peripheral UUID(每台手机看同一只耳机都不一样), - // 设备页显示 MAC 和设备确权都指望这个值。 - // 实测(Echo-one 0.0.3)解出 11:11:22:33:33:A4,与 Android 上 - // connectedDeviceId 逐字节一致,也正是后台 license 表登记的那个。 - // ⚠️ 别改用属性 6:那 12 字节里虽然也嵌着一个 MAC - //(布局 `00 01 01 | <6字节> | 00 00 00`,实测 70:B3:B1:4D:33:DC), - // 但它既不是耳机主地址也不是手机地址,含义至今未知,拿去确权必然对不上。 - if (attr == 0x07 && blockLen >= 7 && p + 7 < data.length) { - final mac = data - .sublist(p + 2, p + 8) - .map((e) => e.toRadixString(16).padLeft(2, '0').toUpperCase()) - .join(':'); - if (mac != deviceMac.value) { - deviceMac.value = mac; - Logger.i(_tag, '耳机上报蓝牙地址: $mac'); - } - // 按本地设备标识记下来,下次连同一台时同步命中,不用再等一帧 BB 0A - _rememberDeviceMac(mac); - } - p += blockLen + 1; + final st = BesProtocol.parseStatus(data); + if (st.batteryLeft != null) { + batteryLeft.value = st.batteryLeft!; + chargingLeft.value = st.chargingLeft; } - if (!hit) return; - final levels = - [batteryLeft.value, batteryRight.value].where((v) => v >= 0).toList(); - if (levels.isNotEmpty) { - // 左右耳取较低的一侧——用户关心的是「还能用多久」 - batteryLevel.value = levels.reduce((a, b) => a < b ? a : b); - } else if (batteryCase.value >= 0) { - // 只有盒子上报时(两只耳机都在盒内)退而显示盒电量 - batteryLevel.value = batteryCase.value; + if (st.batteryRight != null) { + batteryRight.value = st.batteryRight!; + chargingRight.value = st.chargingRight; } + if (st.batteryCase != null) { + batteryCase.value = st.batteryCase!; + chargingCase.value = st.chargingCase; + } + // 属性 7 = 耳机蓝牙地址(6 字节)。这是**耳机自己报上来的**真 MAC, + // 不经过系统蓝牙 API,所以 iOS 上也拿得到——iOS 的 connectedDeviceId + // 是 CoreBluetooth 的 peripheral UUID(每台手机看同一只耳机都不一样), + // 设备页显示 MAC 和设备确权都指望这个值。 + // 实测(Echo-one 0.0.3)解出 11:11:22:33:33:A4,与 Android 上 + // connectedDeviceId 逐字节一致,也正是后台 license 表登记的那个。 + // ⚠️ 别改用属性 6:那 12 字节里虽然也嵌着一个 MAC,含义至今未知。 + final mac = st.mac; + if (mac != null) { + if (mac != deviceMac.value) { + deviceMac.value = mac; + Logger.i(_tag, '耳机上报蓝牙地址: $mac'); + } + // 按本地设备标识记下来,下次连同一台时同步命中,不用再等一帧 BB 0A + _rememberDeviceMac(mac); + } + if (!st.hasBattery) return; + final summary = st.summaryBattery; + if (summary != null) batteryLevel.value = summary; Logger.w( _tag, '恒玄耳机电量: ${batteryLevel.value}%' @@ -671,30 +646,7 @@ class BesBluetoothService extends GetxService { /// 固件版本回包:BB CMD len(2) + 若干版本块 [len, 属性, 8字节版本], /// 属性 0x01左 / 0x02右 / 0x04盒;版本取版本块后 3 字节,优先左耳。 void _parseFirmwareVersion(List data) { - String? left, right, box; - var p = 4; // 跳过 SOF + CMD + 2 字节长度 - while (p + 1 < data.length) { - final blockLen = data[p]; - if (blockLen < 2 || p + blockLen >= data.length) break; - final attr = data[p + 1]; - final version = data.sublist(p + 2, p + 1 + blockLen); - if (version.length >= 8) { - final v = '${version[5]}.${version[6]}.${version[7]}'; - switch (attr) { - case 0x01: - left = v; - break; - case 0x02: - right = v; - break; - case 0x04: - box = v; - break; - } - } - p += blockLen + 1; - } - final parsed = left ?? right ?? box; + final parsed = BesProtocol.parseFirmware(data).preferred; if (parsed != null) { deviceVersion.value = parsed; // 固件版本决定这台机器该用哪套命令号(0.0.2 与 0.0.3 的电量命令不同), @@ -756,30 +708,30 @@ class BesBluetoothService extends GetxService { /// 进入通话模式(`AA 51`):耳机开始双路上行(对端 + 本端), /// mode=0x03 交织,原生解码后走 [audioStream]。通话录音/通话翻译都用它。 - Future startCallMode() => sendData([0xAA, 0x51]); + Future startCallMode() => sendData(BesCmd.frame(BesCmd.callModeStart)); /// 退出通话模式(`AA 52`) - Future stopCallMode() => sendData([0xAA, 0x52]); + Future stopCallMode() => sendData(BesCmd.frame(BesCmd.callModeStop)); /// 通知耳机「ASR 已开启」(`AA 57`),收到 0xD1 之后发 - Future notifyAsrStarted() => sendData([0xAA, 0x57]); + Future notifyAsrStarted() => sendData(BesCmd.frame(BesCmd.asrStarted)); /// 通知耳机「ASR 已关闭」(`AA 58`) - Future notifyAsrStopped() => sendData([0xAA, 0x58]); + Future notifyAsrStopped() => sendData(BesCmd.frame(BesCmd.asrStopped)); /// 开始面对面翻译(`AA 66`)。耳机就绪后回 `0xE6`; /// 耳机按键触发时也会主动上报 `0xE6`。 - Future startFaceToFace() => sendData([0xAA, 0x66]); + Future startFaceToFace() => sendData(BesCmd.frame(BesCmd.faceToFaceStart)); /// 结束面对面翻译(`AA 67`),设备回 `0xE7` - Future stopFaceToFace() => sendData([0xAA, 0x67]); + Future stopFaceToFace() => sendData(BesCmd.frame(BesCmd.faceToFaceStop)); /// 开始设备端主麦录音(`AA 59`)。设备就绪后会回 `0xD9`, /// 音频以 mSBC 帧上行,由原生解码后走 [audioStream]。 - Future startMicRecording() => sendData([0xAA, 0x59]); + Future startMicRecording() => sendData(BesCmd.frame(BesCmd.micRecordStart)); /// 停止设备端主麦录音(`AA 5A`),设备回 `0xDA` - Future stopMicRecording() => sendData([0xAA, 0x5A]); + Future stopMicRecording() => sendData(BesCmd.frame(BesCmd.micRecordStop)); /// 系统已配对的经典蓝牙设备列表(不做 BLE 扫描)。 Future>> getBondedDevices() { diff --git a/apps/client/lib/devices/bes/bes_device_auth.dart b/apps/client/lib/devices/bes/bes_device_auth.dart index c8262d1e..332b1520 100644 --- a/apps/client/lib/devices/bes/bes_device_auth.dart +++ b/apps/client/lib/devices/bes/bes_device_auth.dart @@ -4,9 +4,9 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import '../../core/utils/logger.dart'; -import '../models/user_Info.dart'; +import '../../data/models/user_Info.dart'; +import '../../data/services/network/api.dart'; import 'bes_bluetooth_service.dart'; -import 'network/api.dart'; /// 恒玄耳机的确权结论。 enum BesAuthResult { @@ -62,7 +62,9 @@ enum BesAuthResult { /// iOS 用耳机在 `BB 0A` 状态帧属性 7 里**自报**的蓝牙地址(不经过系统 API,两端一致; /// 实测与 Android 拿到的逐字节吻合)。取不到时照旧返回 [BesAuthResult.unknown] 放行。 class BesDeviceAuth { - BesDeviceAuth._(); + BesDeviceAuth(this._bes); + + final BesBluetoothService _bes; static const String _tag = 'BesDeviceAuth'; @@ -127,9 +129,8 @@ class BesDeviceAuth { /// /// 判定为 [BesAuthResult.denied] 时会**就地断开连接并提示用户**,调用方只需 /// 据返回值决定要不要继续后续握手。 - static Future verifyConnected() async { - if (!Get.isRegistered()) return BesAuthResult.unknown; - final bes = BesBluetoothService.to; + Future verifyConnected() async { + final bes = _bes; if (!bes.isConnected) return BesAuthResult.unknown; // iOS 上 connectedDeviceId 是 peripheral UUID,不能拿去校验; @@ -159,7 +160,7 @@ class BesDeviceAuth { } } - static Future _verifyRemote({ + Future _verifyRemote({ required String mac, required String name, }) async { @@ -235,12 +236,12 @@ class BesDeviceAuth { /// /// ⚠️ **必须移出 pairedDevices**,否则冷启动的 `tryAutoConnect` 和原生 ACL /// 广播会立刻把它连回来,变成「连上→弹窗→断开→连上」的死循环。 - static Future _reject(String address) async { + Future _reject(String address) async { try { // removePairedDevice 内部在地址匹配时会顺带 disconnectDevice - await BesBluetoothService.to.removePairedDevice(address); - if (BesBluetoothService.to.isConnected) { - await BesBluetoothService.to.disconnectDevice(); + await _bes.removePairedDevice(address); + if (_bes.isConnected) { + await _bes.disconnectDevice(); } } catch (e) { Logger.e(_tag, '断开未确权设备失败: $e'); diff --git a/apps/client/lib/devices/bes/bes_device_plugin.dart b/apps/client/lib/devices/bes/bes_device_plugin.dart new file mode 100644 index 00000000..2cf27a67 --- /dev/null +++ b/apps/client/lib/devices/bes/bes_device_plugin.dart @@ -0,0 +1,637 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:get/get.dart'; + +import '../../core/utils/logger.dart'; +import '../device_vendors.dart'; +import 'bes_bluetooth_service.dart'; +import 'bes_ota_port.dart'; +import 'bes_protocol.dart'; + +/// 恒玄(BES) 耳机的厂商插件——把 [BesBluetoothService](协议实现,冻结) +/// 适配成 [DevicePlugin] / [DeviceSession]。 +/// +/// **这一层只做映射,不碰字节。** feature key → 命令字节的对应表在 +/// [BesDeviceSession.invokeFeature],由 `test/devices/bes_session_test.dart` +/// 逐条断言发出的字节。 +class BesDevicePlugin implements DevicePlugin { + static const String _tag = 'BesDevicePlugin'; + + /// 协议实现。仍注册进 GetX 只是为了走 GetxService 的生命周期; + /// 业务层不允许 import 它(见 device_hub_boundary_test)。 + final BesBluetoothService link; + + BesDevicePlugin({BesBluetoothService? link}) + : link = link ?? BesBluetoothService(); + + final StreamController _ctrl = + StreamController.broadcast(); + BesDeviceSession? _session; + Worker? _statusWorker; + bool _initialized = false; + bool _disposed = false; + + @override + String get vendorKey => DeviceVendors.bes; + + @override + String get displayName => 'BES (恒玄)'; + + @override + Set get capabilities => BesDeviceSession.caps; + + @override + DevicePluginConfigSchema get configSchema => DevicePluginConfigSchema.empty; + + @override + DeviceSession? get activeSession => _session; + + @override + Stream get eventStream => _ctrl.stream; + + @override + Future initialize(DevicePluginConfig config) async { + _checkAlive(); + if (_initialized) return; + _initialized = true; + if (!Get.isRegistered()) { + Get.put(link, permanent: true); + } + _statusWorker = ever(link.deviceStatus, _onStatus); + if (link.deviceStatus.value == 2) _onStatus(2); + _emit(const DevicePluginEvent(type: DevicePluginEventType.pluginReady)); + } + + void _onStatus(int v) { + switch (v) { + case 2: + if (_session != null) return; + final s = BesDeviceSession._(link); + _session = s; + _emit(DevicePluginEvent( + type: DevicePluginEventType.connectionStateChanged, + deviceId: s.deviceId, + connectionState: DeviceConnectionState.ready, + )); + break; + case 1: + _emit(DevicePluginEvent( + type: DevicePluginEventType.connectionStateChanged, + deviceId: link.connectedDeviceId.value, + connectionState: DeviceConnectionState.connecting, + )); + break; + default: + final s = _session; + _session = null; + s?._markDisconnected(); + _emit(DevicePluginEvent( + type: DevicePluginEventType.connectionStateChanged, + deviceId: s?.deviceId, + connectionState: DeviceConnectionState.disconnected, + )); + } + } + + void _emit(DevicePluginEvent e) { + if (!_ctrl.isClosed) _ctrl.add(e); + } + + // ---------- 扫描(恒玄没有扫描:只从系统配对列表里挑) ---------- + + @override + Future startScan({DeviceScanFilter? filter, Duration? timeout}) async { + _emit(const DevicePluginEvent(type: DevicePluginEventType.scanStarted)); + for (final d in await bondedDevices()) { + _emit(DevicePluginEvent( + type: DevicePluginEventType.deviceDiscovered, + deviceId: d.id, + discovered: d)); + } + _emit(const DevicePluginEvent(type: DevicePluginEventType.scanStopped)); + } + + @override + Future stopScan() async {} + + @override + Future isScanning() async => false; + + @override + Future> bondedDevices() async { + final list = await link.getBondedDevices(); + return list + .map((d) => DiscoveredDevice( + id: (d['address'] ?? '') as String, + name: (d['name'] ?? '') as String, + vendor: vendorKey, + )) + .where((d) => d.id.isNotEmpty) + .toList(growable: false); + } + + @override + Future ensureReady() async { + try { + return await link.initialize(); + } catch (e) { + Logger.e(_tag, '恒玄蓝牙初始化失败: $e'); + return false; + } + } + + // ---------- 连接 ---------- + + /// 连接并等到「已连接」。 + /// + /// 进过「连接中」又掉回 0 就提前判失败(原生 connectBlocking 失败会推 0); + /// 但仍要保留超时兜底:原生若把这次 connect 丢弃了(isConnecting 门禁), + /// 状态会停在 connectToDevice 自己写的 1,等不到 0。 + @override + Future connect(String deviceId, + {DeviceConnectOptions? options}) async { + _checkAlive(); + final name = (options?.extra['name'] as String?) ?? ''; + final timeout = options?.timeout ?? const Duration(seconds: 8); + await link.connectToDevice(deviceId, name); + final end = DateTime.now().add(timeout); + var sawConnecting = false; + while (DateTime.now().isBefore(end)) { + final s = link.deviceStatus.value; + if (s == 2) break; + if (s == 1) sawConnecting = true; + if (sawConnecting && s == 0) { + throw DeviceException(DeviceErrorCode.connectFailed, deviceId); + } + await Future.delayed(const Duration(milliseconds: 300)); + } + if (link.deviceStatus.value != 2) { + throw DeviceException(DeviceErrorCode.connectTimeout, deviceId); + } + // 状态流回调与这里是同一个事件循环,session 已经建好 + _onStatus(2); + return _session!; + } + + @override + List get rememberedDevices => link + .getPairedDevices() + .map((d) => DiscoveredDevice( + id: (d['address'] ?? '') as String, + name: (d['name'] ?? '') as String, + vendor: vendorKey, + )) + .where((d) => d.id.isNotEmpty) + .toList(growable: false); + + @override + DiscoveredDevice? get lastKnownDevice { + final n = link.lastDeviceName; + final a = link.lastDeviceAddress; + if (n.isEmpty && a.isEmpty) return null; + return DiscoveredDevice(id: a, name: n, vendor: vendorKey); + } + + @override + Future rememberDevice(DiscoveredDevice device) => + link.savePairedDevice({'address': device.id, 'name': device.name}); + + @override + Future tryAutoConnect() => link.tryAutoConnect(); + + @override + Future forgetDevice(String deviceId) => + link.removePairedDevice(deviceId); + + @override + Future dispose() async { + _disposed = true; + _statusWorker?.dispose(); + _session?._markDisconnected(); + _session = null; + await _ctrl.close(); + } + + void _checkAlive() { + if (_disposed) throw StateError('BesDevicePlugin disposed'); + } +} + +/// 恒玄耳机会话。 +class BesDeviceSession extends DeviceSession { + BesDeviceSession._(this._link) { + _bind(); + } + + static const String _tag = 'BesSession'; + + static const Set caps = { + DeviceCapability.connect, + DeviceCapability.bond, + DeviceCapability.battery, + DeviceCapability.macAddress, + DeviceCapability.micUplink, + DeviceCapability.speakerDownlink, + DeviceCapability.micRecording, + DeviceCapability.callAudioTap, + DeviceCapability.callState, + DeviceCapability.aiWake, + DeviceCapability.translationDownlink, + DeviceCapability.faceToFace, + DeviceCapability.ota, + DeviceCapability.customCommand, + }; + + final BesBluetoothService _link; + final StreamController _events = + StreamController.broadcast(); + final StreamController _wake = + StreamController.broadcast(); + final List _workers = []; + StreamSubscription? _aiSub; + DeviceConnectionState _state = DeviceConnectionState.ready; + + /// 通话翻译下行的引用计数:A/B 两路都关了才 stopCallDownlink + int _callSinks = 0; + BesOtaPort? _ota; + + void _bind() { + _workers.add(ever(_link.lastCmdType, (type) { + switch (type) { + case 'startMicRecording': + _feature(DeviceFeatureKeys.recordStarted); + break; + case 'stopMicRecording': + _feature(DeviceFeatureKeys.recordStopped); + break; + } + })); + _workers.add(ever(_link.isCallOngoing, (on) { + _feature(on ? DeviceFeatureKeys.callStarted : DeviceFeatureKeys.callEnded); + })); + void infoChanged(dynamic _) => _infoUpdated(); + _workers.add(ever(_link.batteryLevel, (_) { + _feature(DeviceFeatureKeys.batteryUpdated); + _infoUpdated(); + })); + _workers.add(ever(_link.batteryCase, infoChanged)); + _workers.add(ever(_link.chargingLeft, infoChanged)); + _workers.add(ever(_link.chargingRight, infoChanged)); + _workers.add(ever(_link.chargingCase, infoChanged)); + _workers.add(ever(_link.deviceVersion, (_) { + _feature(DeviceFeatureKeys.firmwareUpdated); + _infoUpdated(); + })); + _workers.add(ever(_link.deviceMac, (_) { + _feature(DeviceFeatureKeys.macUpdated); + _infoUpdated(); + })); + _workers.add(ever(_link.connectedDeviceName, infoChanged)); + + // AI 通道:BB 64 唤醒 / BB E5 结束。应答 AA 6A 由业务层通过 ai.accept 发, + // 与原先 BesAiSessionService 的判断顺序一致(未配置时不应答、发 ai.exit)。 + _aiSub = _link.manager.onDeviceAiEvent().listen((event) { + switch (event['type']) { + case 'startAI': + _wake.add(DeviceWakeEvent(deviceId: deviceId, reason: WakeReason.ptt)); + break; + case 'stopAI': + _wake.add( + DeviceWakeEvent(deviceId: deviceId, reason: WakeReason.hangup)); + break; + } + }, onError: (e) => Logger.e(_tag, 'AI 事件流错误: $e')); + } + + void _feature(String key, [Map data = const {}]) { + if (_events.isClosed) return; + _events.add(DeviceSessionEvent( + type: DeviceSessionEventType.feature, + deviceId: deviceId, + feature: DeviceFeatureEvent(key: key, data: data), + )); + } + + void _infoUpdated() { + if (_events.isClosed) return; + _events.add(DeviceSessionEvent( + type: DeviceSessionEventType.deviceInfoUpdated, + deviceId: deviceId, + deviceInfo: info, + )); + } + + void _markDisconnected() { + if (_state == DeviceConnectionState.disconnected) return; + _state = DeviceConnectionState.disconnected; + for (final w in _workers) { + w.dispose(); + } + _workers.clear(); + _aiSub?.cancel(); + _aiSub = null; + _ota?.onSessionGone(); + if (!_events.isClosed) { + _events.add(DeviceSessionEvent( + type: DeviceSessionEventType.connectionStateChanged, + deviceId: deviceId, + connectionState: DeviceConnectionState.disconnected, + )); + _events.close(); + } + if (!_wake.isClosed) _wake.close(); + } + + void _requireReady() { + if (_state != DeviceConnectionState.ready) { + throw DeviceException(DeviceErrorCode.noActiveSession, 'bes'); + } + } + + // ---------- DeviceSession ---------- + + @override + String get deviceId => _link.connectedDeviceId.value; + + @override + String get vendor => DeviceVendors.bes; + + @override + DeviceConnectionState get state => _state; + + @override + Set get capabilities => caps; + + @override + Stream get eventStream => _events.stream; + + @override + Stream get wakeEvents => _wake.stream; + + static int? _nz(int v) => v >= 0 ? v : null; + + /// 真实 MAC:Android 系统给的就是;iOS 只能靠耳机自报(`BB 0A` 属性 7)。 + String? get macAddress { + if (Platform.isAndroid) { + final id = _link.connectedDeviceId.value; + return id.isEmpty ? null : id.toUpperCase(); + } + final m = _link.deviceMac.value; + return m.isEmpty ? null : m; + } + + @override + DeviceInfo get info { + final battery = DeviceBattery( + left: _nz(_link.batteryLeft.value), + right: _nz(_link.batteryRight.value), + caseBox: _nz(_link.batteryCase.value), + single: _nz(_link.batteryLevel.value), + chargingLeft: _link.chargingLeft.value, + chargingRight: _link.chargingRight.value, + chargingCase: _link.chargingCase.value, + ); + final fw = _link.deviceVersion.value; + return DeviceInfo( + id: deviceId, + name: _link.connectedDeviceName.value, + vendor: vendor, + firmwareVersion: fw.isEmpty ? null : fw, + batteryPercent: battery.summary, + battery: battery, + macAddress: macAddress, + metadata: { + 'inCall': _link.isCallOngoing.value, + 'localId': _link.connectedDeviceId.value, + }, + ); + } + + @override + Future readRssi() => + throw DeviceException(DeviceErrorCode.notSupported, 'rssi'); + + @override + Future readBattery() async { + _requireReady(); + await _link.queryBattery(); + return info.battery.summary; + } + + @override + Future refreshInfo() async { + _requireReady(); + await _link.refreshDeviceState(); + return info; + } + + /// 取真实 MAC,iOS 上会主动发一次查询并等最多 [timeout]。 + Future resolveMac({Duration timeout = const Duration(seconds: 3)}) => + _link.resolveDeviceMac(timeout: timeout); + + // ---------- 音频 ---------- + + @override + Future openMic({AudioRoute route = AudioRoute.mic}) async { + _requireReady(); + switch (route) { + case AudioRoute.mic: + // 现场录音:主麦与前馈麦交替上行,隔帧取主麦 + return _BesSource(route, _alternate(_link.audioStream)); + case AudioRoute.callLocal: + return _BesSource(route, _link.micPcmStream); + case AudioRoute.callPeer: + return _BesSource(route, _link.spkPcmStream); + case AudioRoute.ai: + return _BesSource( + route, + _link.manager + .onDeviceAiEvent() + .where((e) => e['type'] == 'micData' && e['data'] is Uint8List) + .map((e) => e['data'] as Uint8List) + .where((d) => d.isNotEmpty)); + default: + throw DeviceException(DeviceErrorCode.notSupported, 'openMic($route)'); + } + } + + static Stream _alternate(Stream raw) { + var take = true; + return raw.where((_) { + final t = take; + take = !take; + return t; + }); + } + + @override + Future openSpeaker( + {AudioRoute route = AudioRoute.ai}) async { + _requireReady(); + switch (route) { + case AudioRoute.ai: + await _link.manager.startAiDownlink(); + return _BesAiSink(_link); + case AudioRoute.callLegA: + case AudioRoute.callLegB: + if (_callSinks == 0) await _link.startTranslationDownlink(); + _callSinks++; + return _BesCallSink(_link, route, () async { + _callSinks--; + if (_callSinks <= 0) { + _callSinks = 0; + await _link.stopTranslationDownlink(); + } + }); + default: + throw DeviceException( + DeviceErrorCode.notSupported, 'openSpeaker($route)'); + } + } + + // ---------- feature ---------- + + /// feature → 字节的对应表。**冻结**,改动看金测试。 + static const Map featureCommands = { + DeviceFeatures.recordStart: BesCmd.micRecordStart, + DeviceFeatures.recordStop: BesCmd.micRecordStop, + DeviceFeatures.callStart: BesCmd.callModeStart, + DeviceFeatures.callStop: BesCmd.callModeStop, + DeviceFeatures.callQuery: BesCmd.callState, + DeviceFeatures.asrStarted: BesCmd.asrStarted, + DeviceFeatures.asrStopped: BesCmd.asrStopped, + DeviceFeatures.aiAccept: BesCmd.aiAccept, + DeviceFeatures.aiExit: BesCmd.aiExit, + DeviceFeatures.f2fStart: BesCmd.faceToFaceStart, + DeviceFeatures.f2fStop: BesCmd.faceToFaceStop, + DeviceFeatures.batteryQuery: BesCmd.status, + 'bes.firmware.query': BesCmd.firmwareVersion, + }; + + @override + Future> invokeFeature(String featureKey, + [Map args = const {}]) async { + _requireReady(); + final cmd = featureCommands[featureKey]; + if (cmd != null) { + await _link.sendData(BesCmd.frame(cmd)); + return {'sent': BesCmd.frame(cmd)}; + } + switch (featureKey) { + case DeviceFeatures.stateRefresh: + await _link.refreshDeviceState(); + return const {}; + case 'bes.probe': + await _link.probeCommands( + from: (args['from'] as int?) ?? 0x21, + to: (args['to'] as int?) ?? 0x7F, + ); + return const {}; + case 'bes.send': + final bytes = (args['bytes'] as List?)?.cast() ?? const []; + if (bytes.isEmpty) { + throw DeviceException(DeviceErrorCode.invalidArgument, 'bytes'); + } + await _link.sendData(bytes); + return {'sent': bytes}; + default: + throw DeviceException(DeviceErrorCode.notSupported, featureKey); + } + } + + @override + DeviceOtaPort? otaPort() => _ota ??= BesOtaPort(this, _link); + + @override + Future disconnect() => _link.disconnectDevice(); +} + +class _BesSource implements DeviceAudioSource { + _BesSource(this.route, Stream src) { + _sub = src.listen(_ctrl.add, onError: _ctrl.addError); + } + + @override + final AudioRoute route; + final StreamController _ctrl = StreamController.broadcast(); + StreamSubscription? _sub; + + @override + AudioFormat get format => AudioFormat.pcm16kMono; + + @override + Stream get pcm => _ctrl.stream; + + @override + Future close() async { + await _sub?.cancel(); + _sub = null; + await _ctrl.close(); + } +} + +/// AI 下行:G.722 编码与 60ms 组包、0xD6/0xE9 调速全在原生 `AiAudioDownlink`。 +class _BesAiSink implements DeviceAudioSink { + _BesAiSink(this._link); + final BesBluetoothService _link; + bool _closed = false; + + @override + AudioRoute get route => AudioRoute.ai; + + @override + AudioFormat get format => AudioFormat.pcm16kMono; + + @override + Future write(Uint8List pcm) async { + if (_closed) return; + await _link.manager.pushAiPcm(pcm); + } + + @override + Future discardPending() async { + if (_closed) return; + await _link.manager.flushAiDownlink(); + } + + @override + Future close() async { + if (_closed) return; + _closed = true; + await _link.manager.stopAiDownlink(); + } +} + +/// 通话翻译下行:`AA 56` 84 字节包,G.722 + 20ms 节流在原生 `CallTranslationDownlink`。 +class _BesCallSink implements DeviceAudioSink { + _BesCallSink(this._link, this.route, this._onClose); + final BesBluetoothService _link; + @override + final AudioRoute route; + final Future Function() _onClose; + bool _closed = false; + + String get _leg => route == AudioRoute.callLegA ? 'A' : 'B'; + + @override + AudioFormat get format => AudioFormat.pcm16kMono; + + @override + Future write(Uint8List pcm) async { + if (_closed) return; + await _link.pushTranslationTtsPcm(_leg, pcm); + } + + @override + Future discardPending() async {} + + @override + Future close() async { + if (_closed) return; + _closed = true; + await _onClose(); + } +} diff --git a/apps/client/lib/devices/bes/bes_ota_port.dart b/apps/client/lib/devices/bes/bes_ota_port.dart new file mode 100644 index 00000000..7fdf6202 --- /dev/null +++ b/apps/client/lib/devices/bes/bes_ota_port.dart @@ -0,0 +1,203 @@ +import 'dart:async'; + +import 'package:bes_ota_manager/bes_ota_manager.dart'; +import 'package:device_plugin_interface/device_plugin_interface.dart'; + +import '../../core/utils/logger.dart'; +import 'bes_bluetooth_service.dart'; +import 'bes_device_plugin.dart'; + +/// 恒玄 SPP OTA 2.0 端口。 +/// +/// 恒玄的固件推送由 `bes_ota_manager` 插件**自管**一条 SPP 链路,多数固件同时 +/// 只接受一条 SPP,所以: +/// 1. [start] 先断开 app 层连接、留 2s 让耳机拆完旧链路,再让插件连; +/// 2. 升级中 app 层的「已断开」是我们自己断的,**不能**当成 OTA 掉线; +/// 3. [close](退出升级页)先 stopOta 释放插件链路,再延时把 app 层连回来 +/// (成功 5s:设备在重启;其余 2s:等耳机拆链路)。 +/// +/// 看门狗、下载、屏幕常亮这些与厂商无关的事在通用 `OtaUpgradeController` 里。 +class BesOtaPort implements DeviceOtaPort { + BesOtaPort(this._session, this._link); + + static const String _tag = 'BesOtaPort'; + + final BesDeviceSession _session; + final BesBluetoothService _link; + final BesOtaManager _ota = BesOtaManager(); + final StreamController _progress = + StreamController.broadcast(); + + StreamSubscription? _sub; + bool _running = false; + bool _terminal = false; + bool _succeeded = false; + + /// 我们自己为了 OTA 断开了 app 层连接 + bool _handover = false; + String _address = ''; + String _name = ''; + int _lastPercent = -1; + + @override + bool get isRunning => _running; + + @override + Stream get progressStream => _progress.stream; + + @override + Future start(DeviceOtaRequest request) async { + if (_running) throw DeviceException(DeviceErrorCode.otaBusy); + if (request is! DeviceOtaFileRequest) { + throw DeviceException( + DeviceErrorCode.notSupported, '${request.runtimeType}'); + } + // 断开前先抓住设备标识(disconnect 会清空服务字段) + final id = _link.connectedDeviceId.value; + _address = id.isNotEmpty ? id : _address; + final n = _link.connectedDeviceName.value; + _name = n.isNotEmpty ? n : _name; + if (_address.isEmpty) { + throw DeviceException(DeviceErrorCode.noActiveSession, 'no address'); + } + + _running = true; + _terminal = false; + _succeeded = false; + _lastPercent = -1; + _emit(DeviceOtaState.entering, 0); + + // 1) 释放 app 层 SPP,让插件自管 OTA 连接。 + _handover = true; + await _link.disconnectDevice(); + // disconnect 返回只代表本端 socket 已关,耳机侧链路拆除还要在空中传播, + // 立刻连 OTA 会被拒;留 2s 缓冲。 + await Future.delayed(const Duration(seconds: 2)); + if (!_running) return; // 期间被 cancel 了 + + // 2) 初始化原生 OTA 环境并订阅事件。 + await _ota.init(); + _sub ??= _ota.events.listen(_onEvent, onError: (Object e) { + _fail(DeviceErrorCode.otaTransferFailed, e.toString()); + }); + + // 3) 启动 SPP OTA 2.0。 + _emit(DeviceOtaState.transferring, 0); + await _ota.startOta( + address: _address, + name: _name, + filePath: request.filePath, + protocol: 'SPP', + userFlag: 1, + upgradeType: 1, + user: 1, + ); + } + + void _onEvent(BesOtaEvent e) { + // 进入终态即锁定:迟到的进度/Canceled/Error 一律忽略, + // 否则成功会被迟到的 Canceled 覆盖成失败。 + if (_terminal) return; + switch (e.event) { + case 'onProgress': + _emitPercent(((e.progress ?? 0) * 100).round()); + break; + case 'onStatus': + // OTA_SEND_DATA_PROGRESS 状态消息带原始浮点百分比,其余状态文本只记日志 + final numeric = double.tryParse(e.message ?? ''); + if (numeric != null && numeric > 0) { + _emitPercent(numeric.clamp(0, 100).round()); + } else { + Logger.d(_tag, 'OTA 状态: ${e.message}'); + } + break; + case 'onSuccess': + _terminal = true; + _succeeded = true; + _running = false; + _emit(DeviceOtaState.done, 100); + _ota.stopOta(); + break; + case 'onError': + _fail(DeviceErrorCode.otaTransferFailed, + e.message?.isNotEmpty == true ? e.message! : 'code=${e.code}'); + break; + } + } + + /// 进度只在单调递增时上报,避免两个来源(整数 onProgress / 浮点 onStatus) + /// 高频交替导致数字来回跳。 + void _emitPercent(int p) { + if (p <= _lastPercent) return; + _lastPercent = p; + _emit(DeviceOtaState.transferring, p); + } + + void _fail(String code, String message) { + if (_terminal) return; + _terminal = true; + _running = false; + _emit(DeviceOtaState.failed, -1, errorCode: code, errorMessage: message); + // 失败即释放原生会话与 SPP 链路,否则它还占着唯一的 SPP + _ota.stopOta(); + } + + void _emit(DeviceOtaState st, int percent, + {String? errorCode, String? errorMessage}) { + if (_progress.isClosed) return; + _progress.add(DeviceOtaProgress( + state: st, + sentBytes: 0, + totalBytes: 0, + percent: percent, + tsMs: DateTime.now().millisecondsSinceEpoch, + errorCode: errorCode, + errorMessage: errorMessage, + )); + } + + @override + Future cancel() async { + if (!_running) return; + _running = false; + _terminal = true; + await _ota.stopOta(); + _emit(DeviceOtaState.cancelled, -1); + } + + /// 会话没了(app 层断开)。升级中那次断开是我们自己发起的,忽略。 + void onSessionGone() { + if (_handover) return; + if (_running) _fail(DeviceErrorCode.disconnectedRemote, '设备断开'); + } + + @override + Future close() async { + _running = false; + await _sub?.cancel(); + _sub = null; + // 先停 OTA 会话释放插件占用的 SPP,再回连 app 层,避免两条连接打架。 + try { + await _ota.stopOta(); + } catch (_) {} + _ota.dispose(); + if (!_progress.isClosed) await _progress.close(); + + if (!_handover || _address.isEmpty) return; + _handover = false; + final delay = _succeeded + ? const Duration(seconds: 5) // 设备正在重启 + : const Duration(seconds: 2); // 等耳机拆完 OTA 链路再回连 + final addr = _address; + final name = _name; + Future.delayed(delay, () { + // 期间可能已(自动/手动)连上,避免重复发起 + if (_link.deviceStatus.value != 2) { + _link.connectToDevice(addr, name); + } + }); + } + + /// 供插件在会话对象被替换时判断归属。 + bool belongsTo(BesDeviceSession s) => identical(s, _session); +} diff --git a/apps/client/lib/devices/bes/bes_protocol.dart b/apps/client/lib/devices/bes/bes_protocol.dart new file mode 100644 index 00000000..f0cd1080 --- /dev/null +++ b/apps/client/lib/devices/bes/bes_protocol.dart @@ -0,0 +1,278 @@ +/// 恒玄(BES) 私有协议的**纯函数**编解码。 +/// +/// ⚠️ **协议冻结**:这里的每一个字节都对应已量产固件(Echo-one 0.0.2 / 0.0.3) +/// 的真实行为,由 `test/devices/bes_protocol_test.dart` 用真机抓的帧做金测试。 +/// 改任何一个常量、任何一处偏移,先看测试为什么红。 +/// +/// 这个文件不依赖 Flutter / GetX / 原生插件,只做 `List` ↔ 结构体。 +library; + +/// App → 耳机 的命令(`AA xx`)。 +/// +/// 来源:厂商协议 + 真机实测(见各条注释)。请求码与响应码的关系**没有** +/// 统一规律:多数是 `响应 = 请求 | 0x80`(06→86、0E→8E),但电量是 09→0A。 +class BesCmd { + BesCmd._(); + + static const int sof = 0xAA; + + /// 固件版本查询,回 `BB 86`(或主动上报 `BB 07`) + static const int firmwareVersion = 0x06; + + /// 耳机状态(电量/位置/连接/MAC),回 `BB 0A` + ack `BB 89`。 + /// 实测扫出来的请求码,文档里那个「响应命令 20」两种进制都无回包。 + /// ⚠️ 固件 0.0.3 上此命令已不回 `BB 0A`。 + static const int status = 0x09; + + /// 按键配置查询,回 `BB 8C` + static const int keyConfig = 0x0C; + + /// 通话状态查询,回 `BB 8E`(data[6] 0x01=来电 / 0x02=通话中 / 0x03=结束) + static const int callState = 0x0E; + + /// EQ 配置查询,回 `BB 90` + static const int eqConfig = 0x10; + + /// 进入通话模式:耳机开始 G.722 mode=0x03 双路交织上行 + static const int callModeStart = 0x51; + + /// 退出通话模式 + static const int callModeStop = 0x52; + + /// 通话翻译下行 TTS 包(84 字节,由原生 `CallTranslationDownlink` 组包) + static const int translationTts = 0x56; + + /// 通知耳机 ASR 已开启 + static const int asrStarted = 0x57; + + /// 通知耳机 ASR 已关闭 + static const int asrStopped = 0x58; + + /// 开始设备端主麦录音(mSBC 上行),设备回 `BB D9` + static const int micRecordStart = 0x59; + + /// 停止设备端主麦录音,设备回 `BB DA` + static const int micRecordStop = 0x5A; + + /// 请求退出 AI 模式,耳机回 `BB E5` + static const int aiExit = 0x65; + + /// 开始面对面翻译,耳机回 `BB E6` + static const int faceToFaceStart = 0x66; + + /// 结束面对面翻译,耳机回 `BB E7` + static const int faceToFaceStop = 0x67; + + /// 应答 AI 唤醒(收到 `BB 64` 后 **3 秒内**必须发) + static const int aiAccept = 0x6A; + + /// 这一段会切换耳机工作模式(进通话/录音/AI),探测时一律不碰 + static bool switchesMode(int cmd) => cmd >= 0x51 && cmd <= 0x6A; + + static List frame(int cmd) => [sof, cmd & 0xFF]; +} + +/// 耳机 → App 的响应/上报(`BB xx`)。 +class BesResp { + BesResp._(); + + static const int sof = 0xBB; + + /// 主动上报固件版本 + static const int firmwarePush = 0x07; + + /// 响应 `AA 06` + static const int firmwareVersion = 0x86; + + /// 耳机状态帧(电量/位置/连接/MAC) + static const int status = 0x0A; + + /// `AA 09` 的 ack(`BB 89 04 00`),无数据 + static const int statusAck = 0x89; + + /// 周期上报的另一种状态帧,`[len,attr,value]×2`,值 0/1,含义未定 + static const int unknown18 = 0x18; +} + +/// `BB 0A` 状态帧里的属性号。 +class BesStatusAttr { + BesStatusAttr._(); + + static const int batteryLeft = 0x01; + static const int batteryRight = 0x02; + static const int batteryCase = 0x03; + + /// 耳机位置(是否在盒内),值常 >100,**不是电量** + static const int position = 0x04; + + /// 连接状态,值常 >100 + static const int connection = 0x05; + + /// 预留 12 字节,里面嵌着一个含义未知的 MAC,**不要拿去确权** + static const int reserved = 0x06; + + /// 耳机蓝牙地址 6 字节——耳机自报的真 MAC,iOS 上唯一可靠来源 + static const int macAddress = 0x07; +} + +/// `BB 0A` 解析结果。没出现的字段为 null。 +class BesStatus { + const BesStatus({ + this.batteryLeft, + this.batteryRight, + this.batteryCase, + this.chargingLeft = false, + this.chargingRight = false, + this.chargingCase = false, + this.mac, + }); + + final int? batteryLeft; + final int? batteryRight; + final int? batteryCase; + final bool chargingLeft; + final bool chargingRight; + final bool chargingCase; + + /// 大写、冒号分隔,如 `11:11:22:33:33:A4` + final String? mac; + + bool get hasBattery => + batteryLeft != null || batteryRight != null || batteryCase != null; + + /// 「只显示一个数」时用:左右取较低一侧;两只都在盒里只有盒电量时退回盒。 + int? get summaryBattery { + final lr = [batteryLeft, batteryRight].whereType().toList(); + if (lr.isNotEmpty) return lr.reduce((a, b) => a < b ? a : b); + return batteryCase; + } + + @override + String toString() => + 'BesStatus(L=$batteryLeft${chargingLeft ? '⚡' : ''} ' + 'R=$batteryRight${chargingRight ? '⚡' : ''} ' + 'C=$batteryCase${chargingCase ? '⚡' : ''} mac=$mac)'; +} + +/// 固件版本帧解析结果。 +class BesFirmware { + const BesFirmware({this.left, this.right, this.box}); + + final String? left; + final String? right; + final String? box; + + /// 优先左耳。 + String? get preferred => left ?? right ?? box; +} + +class BesProtocol { + BesProtocol._(); + + static String hex(Iterable b) => b + .map((e) => (e & 0xFF).toRadixString(16).padLeft(2, '0').toUpperCase()) + .join(' '); + + static String macOf(Iterable b) => b + .map((e) => (e & 0xFF).toRadixString(16).padLeft(2, '0').toUpperCase()) + .join(':'); + + /// 是不是一个 `BB` 开头、至少带命令号的帧。 + static bool isResponse(List data) => + data.length >= 2 && (data[0] & 0xFF) == BesResp.sof; + + /// 解析 `BB 0A` 状态帧。 + /// + /// 帧格式 `BB | 0A | CMD Length(1) | 块… | checksum`, + /// 块是 `[len, 属性, 数据…]`,**len 计的是「属性 + 数据」的字节数**。 + /// + /// 三个踩过的坑(都会让电量永远显示不出来、且不报错): + /// 1. 起点是 **3** 不是 4:长度字段只有 1 字节,照抄固件版本帧的 `p = 4` + /// 会整体错位一格,第一个块长度读成 0x01 < 2 直接 break; + /// 2. 充电盒是属性 **0x03** 不是 0x04(0x04 是耳机位置,值常 >100); + /// 3. 电量字节最高位是充电指示位,必须 `& 0x7F`。 + /// + /// 属性 3(盒电量)**可选**:耳机不在盒内时这帧没有它。 + static BesStatus parseStatus(List data) { + int? l, r, c; + var cl = false, cr = false, cc = false; + String? mac; + var p = 3; + while (p + 2 < data.length) { + final blockLen = data[p] & 0xFF; + if (blockLen < 2 || p + blockLen >= data.length) break; + final attr = data[p + 1] & 0xFF; + final raw = data[p + 2] & 0xFF; + final level = raw & 0x7F; + final charging = (raw & 0x80) != 0; + if (level <= 100) { + switch (attr) { + case BesStatusAttr.batteryLeft: + l = level; + cl = charging; + break; + case BesStatusAttr.batteryRight: + r = level; + cr = charging; + break; + case BesStatusAttr.batteryCase: + c = level; + cc = charging; + break; + } + } + if (attr == BesStatusAttr.macAddress && + blockLen >= 7 && + p + 7 < data.length) { + mac = macOf(data.sublist(p + 2, p + 8)); + } + p += blockLen + 1; + } + return BesStatus( + batteryLeft: l, + batteryRight: r, + batteryCase: c, + chargingLeft: cl, + chargingRight: cr, + chargingCase: cc, + mac: mac, + ); + } + + /// 解析固件版本帧(`BB 86` / `BB 07`): + /// `BB CMD len(2) + 若干版本块 [len, 属性, 8字节版本]`, + /// 属性 0x01左 / 0x02右 / 0x04盒;版本取版本块后 3 字节。 + static BesFirmware parseFirmware(List data) { + String? left, right, box; + var p = 4; + while (p + 1 < data.length) { + final blockLen = data[p] & 0xFF; + if (blockLen < 2 || p + blockLen >= data.length) break; + final attr = data[p + 1] & 0xFF; + final version = data.sublist(p + 2, p + 1 + blockLen); + if (version.length >= 8) { + final v = '${version[5]}.${version[6]}.${version[7]}'; + switch (attr) { + case 0x01: + left = v; + break; + case 0x02: + right = v; + break; + case 0x04: + box = v; + break; + } + } + p += blockLen + 1; + } + return BesFirmware(left: left, right: right, box: box); + } + + /// 通话状态查询 `BB 8E` 的 data[6]:0x01=来电 0x02=通话中 0x03=结束。 + /// 原生已经把 0x02/0x03 翻成 startMakeCall/stopMakeCall 事件,这里只作备查。 + static int? parseCallState(List data) { + if (data.length < 7 || (data[1] & 0xFF) != 0x8E) return null; + return data[6] & 0xFF; + } +} diff --git a/apps/client/lib/devices/device_auth.dart b/apps/client/lib/devices/device_auth.dart new file mode 100644 index 00000000..3b30707a --- /dev/null +++ b/apps/client/lib/devices/device_auth.dart @@ -0,0 +1,71 @@ +import 'package:device_plugin_interface/device_plugin_interface.dart'; + +import 'bes/bes_device_auth.dart'; +import 'bes/bes_device_plugin.dart'; +import 'device_hub.dart'; +import 'smartcar/smartcar_device_auth.dart'; +import 'smartcar/smartcar_device_plugin.dart'; + +/// 确权结论(厂商无关)。 +/// +/// ⚠️ [unknown] 的语义是**放行**,不是"失败"。判不出来时放行是刻意选的失败方向: +/// 判严的代价是合法用户一断网就用不了自己的设备;判宽只是未登记设备离线时 +/// 能用一会儿,联网第一次确权就会被拦下。 +enum DeviceAuthResult { + /// 白名单命中 / 服务端确认 / 已在 User.devices 里 + authorized, + + /// 服务端明确拒绝(这台 MAC 没登记) + denied, + + /// 未登录 / 断网 / 拿不到 MAC —— **放行** + unknown, +} + +/// 设备确权的业务层入口(登出重置、解绑清白名单、补校当前设备)。 +/// +/// 确权本身是各厂商插件在连接时就地做的(恒玄见 [BesDeviceAuth]),这里只把 +/// 需要从业务层触发的几个动作聚在一起,业务层不用知道是哪家的实现。 +class DeviceAuth { + DeviceAuth._(); + + /// 登出:换账号后同一台设备要重新登记到新账号名下。**白名单不清**。 + static void reset() { + BesDeviceAuth.reset(); + SmartcarDeviceAuth.reset(); + } + + /// 解绑:移出白名单,下次连上重新走服务端确权。 + /// + /// 两家都调:调用方只有一个 MAC,不知道它属于哪个厂商, + /// 而各家白名单是按 MAC 存的、互不相干,多清一次无副作用。 + static Future forget(String mac) async { + await BesDeviceAuth.forget(mac); + await SmartcarDeviceAuth.forget(mac); + } + + /// 【调试/售后】清空白名单 + static Future clearWhitelist() async { + await BesDeviceAuth.clearWhitelist(); + await SmartcarDeviceAuth.clearWhitelist(); + } + + /// 补校当前连着的、需要确权的设备(顺带完成绑定登记)。 + /// 「先连耳机后登录」时连接事件里的登记会因未登录跳过,设备管理页进来补一次。 + static Future verifyConnected() async { + final hub = DeviceHub.to; + for (final s in hub.sessions.toList()) { + if (!s.supports(DeviceCapability.macAddress)) continue; + final p = hub.plugin(s.vendor); + if (p is BesDevicePlugin) { + await p.link.auth?.verifyConnected(); + } else if (p is SmartcarDevicePlugin) { + // Smartcar 的 MAC 来自广播,两端都拿得到(不像恒玄 iOS 只有 UUID) + await SmartcarDeviceAuth.verify( + mac: s.info.macAddress, + name: s.info.name, + ); + } + } + } +} diff --git a/apps/client/lib/devices/device_bootstrap.dart b/apps/client/lib/devices/device_bootstrap.dart new file mode 100644 index 00000000..68ba6d20 --- /dev/null +++ b/apps/client/lib/devices/device_bootstrap.dart @@ -0,0 +1,41 @@ +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:get/get.dart'; + +import '../core/utils/logger.dart'; +import 'bes/bes_device_auth.dart'; +import 'bes/bes_device_plugin.dart'; +import 'device_hub.dart'; +import 'holder/holder_device_plugin.dart'; +import 'smartcar/smartcar_device_plugin.dart'; + +/// 装配设备中枢:注册所有厂商插件并初始化。由 InitialBinding 调用一次。 +/// +/// 新接一种芯片 = 在这里多 `registerPlugin` 一行 + `lib/devices//` 一个目录, +/// 业务层零改动。 +/// +/// 两个插件的 `initialize` 都是轻量的:恒玄在 iOS 上必须无条件建 CBCentralManager +/// 才能被动接管系统层连接,Android 只在绑过设备时申请权限;支架只在记住过设备时 +/// 注册后台扫连。所以这里不做「按绑定记录挑插件」,行为与改造前一致。 +void installDeviceHub() { + if (Get.isRegistered()) return; + final hub = Get.put(DeviceHub(), permanent: true); + + final bes = BesDevicePlugin(); + bes.link.auth = BesDeviceAuth(bes.link); + _register(hub, bes); + + _register(hub, HolderDevicePlugin()); + + // Smartcar 车载香薰。BLE 走 flutter_blue_plus(纯 Dart,无原生插件)。 + // initialize 里不申请权限也不起扫描,冷启动零副作用。 + _register(hub, SmartcarDevicePlugin()); +} + +void _register(DeviceHub hub, DevicePlugin p) { + try { + hub.registerPlugin(p); + p.initialize(const DevicePluginConfig()); + } catch (e) { + Logger.e('DeviceBootstrap', '初始化厂商插件 ${p.vendorKey} 失败: $e'); + } +} diff --git a/apps/client/lib/devices/device_hub.dart b/apps/client/lib/devices/device_hub.dart new file mode 100644 index 00000000..da8d1d90 --- /dev/null +++ b/apps/client/lib/devices/device_hub.dart @@ -0,0 +1,265 @@ +import 'dart:async'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:get/get.dart'; + +import '../core/utils/logger.dart'; + +/// 设备中枢——**业务层唯一的设备入口**。 +/// +/// 业务层(`lib/modules`、`lib/core`)只能 import 这个文件和 +/// `device_plugin_interface`,不能 import 任何 `lib/devices//` 下的东西, +/// `test/devices/device_hub_boundary_test.dart` 守着这条线。 +/// +/// 职责: +/// - 持有各厂商插件(恒玄 / EaiRec 支架 / 以后接的每一种芯片各一个); +/// - 汇总所有 `ready` 会话成一份可观测状态(连没连、能力集、电量、通话中…); +/// - 合流唤醒事件与会话事件,供常驻服务订阅; +/// - 「最近连过的设备」这类展示用信息也从这里拿。 +/// +/// 多设备模型:耳机和支架可以同时在线,所以是 `sessions` 列表而不是单个 +/// active。要「一台能录音的设备」就问 [sessionWith]。 +class DeviceHub extends GetxService { + static const String _tag = 'DeviceHub'; + static DeviceHub get to => Get.find(); + + final Map _plugins = {}; + final Map _pluginSubs = {}; + final Map _sessionSubs = {}; + final Map _wakeSubs = {}; + + /// 当前 `ready` 的会话,按连上的先后排。 + final RxList sessions = [].obs; + + /// 任一设备在线。 + final RxBool anyConnected = false.obs; + + /// 所有在线设备能力的并集。UI 显隐一律问它,不问厂商。 + final RxSet capabilities = {}.obs; + + /// 正在通话中(由声明了 [DeviceCapability.callState] 的设备上报)。 + final RxBool inCall = false.obs; + + /// 主设备(第一台在线的)的信息快照;没有设备时为 null。 + final Rxn primaryInfo = Rxn(); + + /// 主设备名;没有设备时为空串。 + final RxString primaryName = ''.obs; + + /// 每当任何会话的 info / 状态变了就 +1,给只想「重画一下」的 UI 用。 + final RxInt revision = 0.obs; + + final StreamController _wake = + StreamController.broadcast(); + final StreamController _events = + StreamController.broadcast(); + + /// 所有在线设备的唤醒事件合流。 + Stream get wakeEvents => _wake.stream; + + /// 所有在线设备的会话事件合流。 + Stream get sessionEvents => _events.stream; + + // ---------------- 插件管理 ---------------- + + Iterable get plugins => _plugins.values; + + DevicePlugin? plugin(String vendorKey) => _plugins[vendorKey]; + + /// 注册一个厂商插件。重复 key 直接覆盖并报警(正常不该发生)。 + void registerPlugin(DevicePlugin p) { + if (_plugins.containsKey(p.vendorKey)) { + Logger.w(_tag, '重复注册厂商插件 ${p.vendorKey},覆盖旧实例'); + _pluginSubs.remove(p.vendorKey)?.cancel(); + } + _plugins[p.vendorKey] = p; + _pluginSubs[p.vendorKey] = p.eventStream.listen( + (e) => _onPluginEvent(p, e), + onError: (e) => Logger.e(_tag, '${p.vendorKey} 事件流错误: $e'), + ); + // 插件可能在注册前就已经连上了(比如原生被动回连),补一次快照 + final s = p.activeSession; + if (s != null && s.state == DeviceConnectionState.ready) _attach(s); + Logger.i(_tag, '已注册厂商插件 ${p.vendorKey}(${p.displayName})'); + } + + // ---------------- 查询 ---------------- + + bool has(DeviceCapability c) => capabilities.contains(c); + + /// 第一台具备该能力的在线设备;没有为 null。 + DeviceSession? sessionWith(DeviceCapability c) { + for (final s in sessions) { + if (s.supports(c)) return s; + } + return null; + } + + /// 主音频设备:第一台能上行麦克风的。 + DeviceSession? get primaryAudio => sessionWith(DeviceCapability.micUplink); + + /// 主设备 = **最近上线**的那台([_attach] 把新会话插在最前)。 + DeviceSession? get primary => sessions.isEmpty ? null : sessions.first; + + DeviceSession? sessionOf(String vendorKey) { + for (final s in sessions) { + if (s.vendor == vendorKey) return s; + } + return null; + } + + /// 最近连过(或正连着)的设备名,用于断连后仍显示「我的那台设备」。 + /// 从没连过任何设备返回空串。 + String get lastKnownName { + if (primaryName.value.isNotEmpty) return primaryName.value; + for (final p in _plugins.values) { + final d = p.lastKnownDevice; + if (d != null && d.name.isNotEmpty) return d.name; + } + return ''; + } + + bool get hasKnownDevice => lastKnownName.isNotEmpty; + + // ---------------- 动作 ---------------- + + /// 冷启动/前台恢复时让每个插件各自回连记住的设备。 + Future tryAutoConnectAll() async { + for (final p in _plugins.values) { + try { + await p.tryAutoConnect(); + } catch (e) { + Logger.e(_tag, '${p.vendorKey} 自动回连失败: $e'); + } + } + } + + Future disconnectAll() async { + for (final s in sessions.toList()) { + try { + await s.disconnect(); + } catch (e) { + Logger.e(_tag, '${s.vendor} 断开失败: $e'); + } + } + } + + /// 进功能页时刷一遍所有在线设备的状态(电量会掉、配置会变)。 + Future refreshAll() async { + for (final s in sessions.toList()) { + try { + await s.refreshInfo(); + } catch (e) { + Logger.w(_tag, '${s.vendor} 刷新状态失败: $e'); + } + } + } + + // ---------------- 内部 ---------------- + + void _onPluginEvent(DevicePlugin p, DevicePluginEvent e) { + switch (e.type) { + case DevicePluginEventType.connectionStateChanged: + final s = p.activeSession; + if (e.connectionState == DeviceConnectionState.ready && s != null) { + _attach(s); + } else if (e.connectionState == DeviceConnectionState.disconnected) { + _detachVendor(p.vendorKey); + } + break; + case DevicePluginEventType.error: + Logger.w(_tag, '${p.vendorKey} 错误: ${e.errorCode} ${e.errorMessage}'); + break; + default: + break; + } + } + + void _attach(DeviceSession s) { + if (sessions.any((x) => identical(x, s))) return; + // 同一厂商只保留最新的会话 + _detachVendor(s.vendor, silent: true); + // ★ 单活动设备:用户从车载香薰切到耳机(反之亦然),旧设备的链路要断掉, + // 不能两台同时在线——设备页只有一张图、一个电量,两台并存时展示和音频路由都会打架。 + // 新上线的设备**排在最前**成为主设备,设备页的图/名字/电量跟着它走。 + // (2026-09-10 用户反馈:切到耳机后香薰 BLE 没断、设备页图片也没换。) + // ⚠️ 被动回连(系统 ACL 把耳机连回来)同样会走到这里并顶掉当前设备,这是刻意的: + // "最近连上的那台就是用户此刻想用的那台"。 + for (final other in sessions.where((x) => x.vendor != s.vendor).toList()) { + Logger.i(_tag, '切换设备:${s.vendor} 上线,断开 ${other.vendor} ${other.info.name}'); + _detachVendor(other.vendor, silent: true); + other.disconnect().catchError((Object e) { + Logger.w(_tag, '${other.vendor} 断开失败: $e'); + }); + } + sessions.insert(0, s); + _sessionSubs[s.vendor] = s.eventStream.listen((e) { + _events.add(e); + _onSessionEvent(s, e); + }); + _wakeSubs[s.vendor] = s.wakeEvents.listen(_wake.add); + Logger.i(_tag, '设备上线: ${s.vendor} ${s.info.name} caps=${s.capabilities.map((c) => c.name).join(',')}'); + _recompute(); + } + + void _detachVendor(String vendor, {bool silent = false}) { + _sessionSubs.remove(vendor)?.cancel(); + _wakeSubs.remove(vendor)?.cancel(); + final before = sessions.length; + sessions.removeWhere((x) => x.vendor == vendor); + if (sessions.length != before && !silent) { + Logger.i(_tag, '设备下线: $vendor'); + } + _recompute(); + } + + void _onSessionEvent(DeviceSession s, DeviceSessionEvent e) { + switch (e.type) { + case DeviceSessionEventType.connectionStateChanged: + if (e.connectionState == DeviceConnectionState.disconnected) { + _detachVendor(s.vendor); + } + break; + case DeviceSessionEventType.deviceInfoUpdated: + _recompute(); + break; + case DeviceSessionEventType.feature: + final key = e.feature?.key; + if (key == DeviceFeatureKeys.callStarted) inCall.value = true; + if (key == DeviceFeatureKeys.callEnded) inCall.value = false; + break; + default: + break; + } + } + + void _recompute() { + anyConnected.value = sessions.isNotEmpty; + final caps = {}; + for (final s in sessions) { + caps.addAll(s.capabilities); + } + capabilities.assignAll(caps); + final p = primary; + primaryInfo.value = p?.info; + primaryName.value = p?.info.name ?? ''; + if (p == null) inCall.value = false; + revision.value++; + } + + @override + void onClose() { + for (final s in _pluginSubs.values) { + s.cancel(); + } + for (final s in _sessionSubs.values) { + s.cancel(); + } + for (final s in _wakeSubs.values) { + s.cancel(); + } + _wake.close(); + _events.close(); + super.onClose(); + } +} diff --git a/apps/client/lib/devices/device_vendors.dart b/apps/client/lib/devices/device_vendors.dart new file mode 100644 index 00000000..4b5ffd09 --- /dev/null +++ b/apps/client/lib/devices/device_vendors.dart @@ -0,0 +1,14 @@ +/// 厂商插件的 key。业务层只在「选品类 → 进哪个连接页」这类地方用到, +/// 其余判断一律走 [DeviceCapability]。 +class DeviceVendors { + DeviceVendors._(); + + /// 恒玄 BES 耳机(Echo-one),经典蓝牙 SPP / iOS GATT 桥 + static const String bes = 'bes'; + + /// EaiRec 录音支架,BLE + Opus + static const String holder = 'holder'; + + /// Smartcar 车载香薰(协议待接) + static const String smartcar = 'smartcar'; +} diff --git a/apps/client/lib/devices/holder/holder_device_plugin.dart b/apps/client/lib/devices/holder/holder_device_plugin.dart new file mode 100644 index 00000000..97f3ff36 --- /dev/null +++ b/apps/client/lib/devices/holder/holder_device_plugin.dart @@ -0,0 +1,437 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:echomeet_device_sdk/echomeet_device_sdk.dart'; +import 'package:get/get.dart'; + +import '../../core/utils/logger.dart'; +import '../device_vendors.dart'; +import 'holder_device_service.dart'; +import 'holder_file_store.dart'; +import 'holder_ota_port.dart'; + +/// EaiRec 录音支架的厂商插件——把 [HolderDeviceService](协议在 `recorder_holder` +/// 插件里,冻结)适配成 [DevicePlugin] / [DeviceSession]。 +/// +/// 与恒玄的差异全在这一层吸收:BLE 扫描而不是系统配对列表、Opus 而不是 G.722、 +/// 录音是「切状态 + 开编码器」两步而不是一条 `AA 59`。业务层看到的是同一套 +/// `openMic(mic)` / `record.start`。 +class HolderDevicePlugin implements DevicePlugin { + final HolderDeviceService link; + + HolderDevicePlugin({HolderDeviceService? link}) + : link = link ?? HolderDeviceService(); + + final StreamController _ctrl = + StreamController.broadcast(); + HolderDeviceSession? _session; + final List _workers = []; + bool _initialized = false; + bool _disposed = false; + + @override + String get vendorKey => DeviceVendors.holder; + + @override + String get displayName => 'EaiRec (录音支架)'; + + @override + Set get capabilities => HolderDeviceSession.caps; + + @override + DevicePluginConfigSchema get configSchema => DevicePluginConfigSchema.empty; + + @override + DeviceSession? get activeSession => _session; + + @override + Stream get eventStream => _ctrl.stream; + + @override + Future initialize(DevicePluginConfig config) async { + _checkAlive(); + if (_initialized) return; + _initialized = true; + if (!Get.isRegistered()) { + Get.put(link, permanent: true); + } + _workers.add(ever(link.connection, _onConn)); + _workers.add(ever>(link.scanned, (list) { + for (final d in list) { + _emit(DevicePluginEvent( + type: DevicePluginEventType.deviceDiscovered, + deviceId: d.address, + discovered: _discovered(d), + )); + } + })); + _workers.add(ever(link.isScanning, (on) { + _emit(DevicePluginEvent( + type: on + ? DevicePluginEventType.scanStarted + : DevicePluginEventType.scanStopped)); + })); + if (link.isConnected) _onConn(EchoMeetConnectionState.connected); + _emit(const DevicePluginEvent(type: DevicePluginEventType.pluginReady)); + } + + DiscoveredDevice _discovered(EchoMeetScannedDevice d) => DiscoveredDevice( + id: d.address.isNotEmpty ? d.address : d.id, + name: d.name, + vendor: vendorKey, + metadata: {'advertisementHex': d.advertisementHex, 'sdkId': d.id}, + ); + + void _onConn(EchoMeetConnectionState s) { + switch (s) { + case EchoMeetConnectionState.connected: + if (_session != null) return; + final sess = HolderDeviceSession._(link); + _session = sess; + _emit(DevicePluginEvent( + type: DevicePluginEventType.connectionStateChanged, + deviceId: sess.deviceId, + connectionState: DeviceConnectionState.ready, + )); + break; + case EchoMeetConnectionState.connecting: + _emit(DevicePluginEvent( + type: DevicePluginEventType.connectionStateChanged, + deviceId: link.connectedAddress, + connectionState: DeviceConnectionState.connecting, + )); + break; + default: + final sess = _session; + _session = null; + sess?._markDisconnected(); + _emit(DevicePluginEvent( + type: DevicePluginEventType.connectionStateChanged, + deviceId: sess?.deviceId, + connectionState: DeviceConnectionState.disconnected, + )); + } + } + + void _emit(DevicePluginEvent e) { + if (!_ctrl.isClosed) _ctrl.add(e); + } + + // ---------- 扫描 / 连接 ---------- + + @override + Future ensureReady() async { + if (link.isPermissionCoolingDown) return false; + // 用户主动进连接页:允许再申请一次系统蓝牙权限 + link.resetPermissionDenied(); + return link.requestPermission(); + } + + /// 用户拒绝过蓝牙权限且仍在冷却期——UI 据此置灰入口 + bool get isPermissionCoolingDown => link.isPermissionCoolingDown; + + @override + Future startScan({DeviceScanFilter? filter, Duration? timeout}) => + link.startScan(); + + @override + Future stopScan() => link.stopScan(); + + @override + Future isScanning() async => link.isScanning.value; + + @override + Future> bondedDevices() async => + link.scanned.map(_discovered).toList(growable: false); + + @override + Future connect(String deviceId, + {DeviceConnectOptions? options}) async { + _checkAlive(); + final d = link.scanned.firstWhereOrNull( + (x) => x.address.toUpperCase() == deviceId.toUpperCase() || x.id == deviceId); + if (d == null) { + throw DeviceException(DeviceErrorCode.connectFailed, '未扫描到 $deviceId'); + } + final registered = await link.connect(d); + if (!registered) { + throw DeviceException(DeviceErrorCode.connectFailed, deviceId); + } + final ok = await link.waitConnected( + timeout: options?.timeout ?? const Duration(seconds: 25)); + if (!ok) throw DeviceException(DeviceErrorCode.connectTimeout, deviceId); + _onConn(EchoMeetConnectionState.connected); + return _session!; + } + + @override + List get rememberedDevices => link.pairedDevices + .map((e) => DiscoveredDevice( + id: (e['address'] ?? '').toString(), + name: (e['name'] ?? '').toString(), + vendor: vendorKey, + )) + .where((d) => d.id.isNotEmpty) + .toList(growable: false); + + @override + DiscoveredDevice? get lastKnownDevice { + final n = link.lastDeviceName; + if (n.isEmpty) return null; + return DiscoveredDevice(id: link.connectedAddress, name: n, vendor: vendorKey); + } + + @override + Future rememberDevice(DiscoveredDevice device) async { + // 支架在 connect 成功时自己会记;这里保持幂等 + } + + @override + Future tryAutoConnect() => link.tryAutoConnect(); + + @override + Future forgetDevice(String deviceId) async { + link.removePaired(deviceId); + if (link.isConnected && + link.connectedAddress.toUpperCase() == deviceId.toUpperCase()) { + await link.disconnect(); + } + } + + @override + Future dispose() async { + _disposed = true; + for (final w in _workers) { + w.dispose(); + } + _session?._markDisconnected(); + _session = null; + await _ctrl.close(); + } + + void _checkAlive() { + if (_disposed) throw StateError('HolderDevicePlugin disposed'); + } +} + +class HolderDeviceSession extends DeviceSession { + HolderDeviceSession._(this._link) { + _bind(); + } + + static const String _tag = 'HolderSession'; + + static const Set caps = { + DeviceCapability.scan, + DeviceCapability.connect, + DeviceCapability.battery, + DeviceCapability.macAddress, + DeviceCapability.micUplink, + DeviceCapability.micRecording, + // AB FOT 固件升级(协议实现在 recorder_holder/lib/src/ota/),见 [HolderOtaPort] + DeviceCapability.ota, + // 通道 B:TF 卡录音文件,见 [HolderFileStore]。 + // ⚠️ 这台硬件**只有**这条录音路径可用(没有 ae00 实时音频服务)。 + DeviceCapability.fileStore, + DeviceCapability.customCommand, + }; + + final HolderDeviceService _link; + final StreamController _events = + StreamController.broadcast(); + final List _workers = []; + DeviceConnectionState _state = DeviceConnectionState.ready; + bool _lastRecording = false; + + void _bind() { + _lastRecording = _link.recording.value.isRecording; + _workers.add(ever(_link.recording, (st) { + if (st.isRecording == _lastRecording) return; + _lastRecording = st.isRecording; + _feature(st.isRecording + ? DeviceFeatureKeys.recordStarted + : DeviceFeatureKeys.recordStopped); + })); + _workers.add(ever(_link.deviceInfo, (_) { + _feature(DeviceFeatureKeys.batteryUpdated); + _infoUpdated(); + })); + _workers.add(ever(_link.connectedNameRx, (_) => _infoUpdated())); + } + + void _feature(String key, [Map data = const {}]) { + if (_events.isClosed) return; + _events.add(DeviceSessionEvent( + type: DeviceSessionEventType.feature, + deviceId: deviceId, + feature: DeviceFeatureEvent(key: key, data: data), + )); + } + + void _infoUpdated() { + if (_events.isClosed) return; + _events.add(DeviceSessionEvent( + type: DeviceSessionEventType.deviceInfoUpdated, + deviceId: deviceId, + deviceInfo: info, + )); + } + + void _markDisconnected() { + if (_state == DeviceConnectionState.disconnected) return; + _state = DeviceConnectionState.disconnected; + for (final w in _workers) { + w.dispose(); + } + _workers.clear(); + _ota?.onSessionGone(); + if (!_events.isClosed) { + _events.add(DeviceSessionEvent( + type: DeviceSessionEventType.connectionStateChanged, + deviceId: deviceId, + connectionState: DeviceConnectionState.disconnected, + )); + _events.close(); + } + } + + void _requireReady() { + if (_state != DeviceConnectionState.ready) { + throw DeviceException(DeviceErrorCode.noActiveSession, 'holder'); + } + } + + @override + String get deviceId => _link.connectedAddress; + + @override + String get vendor => DeviceVendors.holder; + + @override + DeviceConnectionState get state => _state; + + @override + Set get capabilities => caps; + + @override + Stream get eventStream => _events.stream; + + static final RegExp _macRe = RegExp(r'^([0-9A-F]{2}:){5}[0-9A-F]{2}$'); + + @override + DeviceInfo get info { + final i = _link.deviceInfo.value; + final lvl = i?.batteryLevel; + final addr = _link.connectedAddress.toUpperCase(); + return DeviceInfo( + id: deviceId, + name: _link.connectedName, + vendor: vendor, + firmwareVersion: i?.firmwareVersion, + batteryPercent: lvl, + battery: DeviceBattery(single: lvl, chargingSingle: i?.isCharging ?? false), + // iOS 上拿到的是 peripheral UUID,只有长得像 MAC 才当 MAC + macAddress: Platform.isAndroid || _macRe.hasMatch(addr) ? addr : null, + metadata: {'productId': i?.productId, 'deviceIsRecording': _link.deviceIsRecording}, + ); + } + + @override + Future readRssi() => + throw DeviceException(DeviceErrorCode.notSupported, 'rssi'); + + @override + Future readBattery() async { + _requireReady(); + await _link.refreshBattery(); + return info.battery.single; + } + + @override + Future refreshInfo() async { + _requireReady(); + await _link.refreshBattery(); + return info; + } + + /// 主麦上行。**必须**打开设备编码器,否则设备不往手机推 Opus 流 + /// (设备按键发起的录音只切本地录音态、不开编码器,所以无条件补一条)。 + @override + Future openMic({AudioRoute route = AudioRoute.mic}) async { + _requireReady(); + if (route != AudioRoute.mic) { + throw DeviceException(DeviceErrorCode.notSupported, 'openMic($route)'); + } + final ok = await _link.openEncoder(); + if (!ok) Logger.w(_tag, 'openEncoder 返回 false,可能收不到音频流'); + return _HolderSource(_link.audioFrames.map((f) => f.pcm)); + } + + @override + Future> invokeFeature(String featureKey, + [Map args = const {}]) async { + _requireReady(); + switch (featureKey) { + case DeviceFeatures.recordStart: + // toggle 语义:设备已在录时再切一次会把它关掉,先看设备状态 + if (_link.deviceIsRecording) return const {'ok': true, 'already': true}; + final ok = await _link.startRecording(); + return {'ok': ok}; + case DeviceFeatures.recordStop: + if (!_link.deviceIsRecording) return const {'ok': true, 'already': true}; + final ok = await _link.stopRecording( + fileName: args['fileName'] as String?); + return {'ok': ok}; + case 'holder.toggle': + case 'record.toggle': + return {'ok': await _link.toggleRecording()}; + case DeviceFeatures.batteryQuery: + return {'ok': await _link.refreshBattery()}; + case DeviceFeatures.stateRefresh: + await _link.refreshBattery(); + return const {}; + default: + throw DeviceException(DeviceErrorCode.notSupported, featureKey); + } + } + + /// 主动断开 = 「不要它了」:支架 SDK 的 disconnect 会一并清掉自动回连记忆。 + HolderOtaPort? _ota; + HolderFileStore? _files; + + @override + DeviceFileStore? fileStore() => _files ??= HolderFileStore(_link); + + @override + DeviceOtaPort? otaPort() => _ota ??= HolderOtaPort(_link); + + @override + Future disconnect() => _link.disconnect(); +} + +class _HolderSource implements DeviceAudioSource { + _HolderSource(Stream src) { + _sub = src.listen(_ctrl.add, onError: _ctrl.addError); + } + + final StreamController _ctrl = StreamController.broadcast(); + StreamSubscription? _sub; + + @override + AudioRoute get route => AudioRoute.mic; + + @override + AudioFormat get format => AudioFormat.pcm16kMono; + + @override + Stream get pcm => _ctrl.stream; + + @override + Future close() async { + await _sub?.cancel(); + _sub = null; + await _ctrl.close(); + } +} diff --git a/apps/client/lib/devices/holder/holder_device_service.dart b/apps/client/lib/devices/holder/holder_device_service.dart index ff097c93..9096bb87 100644 --- a/apps/client/lib/devices/holder/holder_device_service.dart +++ b/apps/client/lib/devices/holder/holder_device_service.dart @@ -4,23 +4,26 @@ import 'dart:io'; import 'package:echomeet_device_sdk/echomeet_device_sdk.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; import '../../core/utils/logger.dart'; import '../../core/utils/permission_util.dart'; -import 'background_launch_consent.dart'; -import 'agent_module_defaults.dart'; -import '../models/user_Info.dart'; -import 'network/api.dart'; +import '../../data/models/user_Info.dart'; +import '../../data/services/background_launch_consent.dart'; +import '../../data/services/network/api.dart'; -/// 蓝讯方案设备(AI手机支架 / AI Pencil)的接入层。 +/// EaiRec 录音支架(AI手机支架)的接入层。 /// -/// 底层协议实现全部来自 echomeet 项目的 `recorder_holder` 插件,本类只是把 -/// [EchoMeetDeviceSdk] 的流封装成 GetX 可观测状态,不重写任何蓝牙/Opus 逻辑。 +/// 底层协议在 `recorder_holder` 插件里,本类只是把 [EchoMeetDeviceSdk] 的流 +/// 封装成 GetX 可观测状态,不重写任何蓝牙/Opus 逻辑。设备的两条通道: +/// - 通道 A:控制命令 + 实时 Opus 音频流(录音走这条) +/// - 通道 B:TF 卡文件(列表/下载/删除),见本类下半部分 +/// 协议规范见 local_plugins/recorder_holder/EaiRec_protocol.md。 /// /// 与项目原有的 [BleManager](杰理耳机链路)是两套独立的设备通路,互不影响: /// - 杰理耳机 → BleManager -/// - 蓝讯支架 → 本服务 +/// - EaiRec 支架 → 本服务 class HolderDeviceService extends GetxService { static const String _tag = 'HolderDeviceService'; @@ -198,6 +201,138 @@ class HolderDeviceService extends GetxService { /// 录音的 PCM 帧流(16kHz / 16bit / 单声道,Opus 已在原生侧解码) Stream get audioFrames => _sdk.audioFrames; + // ==================== 通道 B:TF 卡文件 ==================== + // + // 协议见 local_plugins/recorder_holder/EaiRec_protocol.md §5。 + // 这里只做「连上之后对时 + 拉一次状态」和几个供上层调用的入口; + // 帧格式与状态机都在插件的 RecClient 里,本类不碰字节。 + + /// 设备 TF 卡与录音状态。设备主动上报(录音起停)也会刷新它。 + final Rxn recInfo = Rxn(); + + /// 通道 B 是否可用。设备没有 TF 卡能力时为 false,此时通道 A 照常工作。 + final RxBool recChannelReady = false.obs; + + StreamSubscription? _recInfoSub; + StreamSubscription>? _recListSub; + + /// 设备端录音停止后会主动推一次完整文件列表,落在这里。 + final RxList recFiles = [].obs; + + /// 同一份推送的事件流版本。RxList 只表达「当前是什么」, + /// 而导入服务要的是「又推了一次」这个**事件**(内容可能一模一样)。 + final StreamController> _recFilesPushes = + StreamController>.broadcast(); + Stream> get recFilesPushes => _recFilesPushes.stream; + + /// 连上之后的通道 B 握手。 + /// + /// 顺序按协议文档 §8.1:先对时再查状态 —— 设备是拿 RTC 生成录音文件的 FAT + /// 时间的,对时晚了这一次录的文件时间就是错的。 + /// 通道 B 握手最多试几次。原生的 `connected` 回调在**服务发现之前**就抛出来了 + /// (真机实测差约 700ms),第一次探必然探到「没有 0xFDA5」。 + /// ⚠️ 这里失败就直接 return 的老写法后果比看上去严重:不只是这次没握上手, + /// 而是**对时没做(录音文件时间全错)、文件列表推送没订阅(录完不会自动同步)、 + /// 设备状态没拉**,而 `ensureRecChannel()` 本身是每次重新探的, + /// 于是「列表能拉、但录完不会自动出现」——一个非常难查的半死状态。 + static const int _maxRecChannelTries = 6; + + Future _initRecChannel() async { + for (var i = 1; i <= _maxRecChannelTries; i++) { + if (!isConnected) return; // 中途断了就别再试 + try { + if (await _sdk.ensureRecChannel()) { + // 订阅要在对时之前挂上:设备可能在握手过程中就推东西上来。 + // `??=` 保证重试时不会重复订阅。 + _recInfoSub ??= _sdk.recorder.onRecInfo.listen((info) { + recInfo.value = info; + Logger.i(_tag, '设备状态: $info'); + }); + _recListSub ??= _sdk.recorder.onFileListPushed.listen((list) { + Logger.i(_tag, '设备主动推送文件列表,共 ${list.length} 个'); + recFiles.assignAll(list); + if (!_recFilesPushes.isClosed) _recFilesPushes.add(list); + }); + + await _sdk.recorder.syncRtc(); + recInfo.value = await _sdk.recorder.queryInfo(); + recChannelReady.value = true; + Logger.i(_tag, '通道 B 就绪(第 $i 次): ${recInfo.value}'); + return; + } + } catch (e) { + // 通道 B 失败不能影响连接本身,只记不抛 + Logger.i(_tag, '通道 B 握手第 $i 次失败,重试: $e'); + } + await Future.delayed(const Duration(milliseconds: 800)); + } + recChannelReady.value = false; + Logger.w(_tag, '通道 B 握手 $_maxRecChannelTries 次都没成,TF 卡录音无法同步'); + } + + /// 拉取 TF 卡上的完整录音列表。 + Future> listRecordings() async { + if (!await _sdk.ensureRecChannel()) { + throw RecException('通道 B 不可用'); + } + final list = await _sdk.recorder.listFiles(); + recFiles.assignAll(list); + return list; + } + + /// 把 TF 卡上的一个录音下载到本地。 + /// + /// 落在 `/EaiRec/<文件名>`,**同名文件会被当作断点续传的半成品接着写** + /// —— 这正是要的行为(下载中断后重进接着下)。要重下得先删掉本地文件。 + Future downloadRecording( + String name, { + void Function(int received, int total)? onProgress, + RecCancelToken? cancelToken, + }) async { + if (!await _sdk.ensureRecChannel()) { + throw RecException('通道 B 不可用'); + } + final docs = await getApplicationDocumentsDirectory(); + final sink = FileRecSink(File('${docs.path}/EaiRec/$name')); + await sink.open(); + return _sdk.recorder.download( + name: name, + sink: sink, + onProgress: onProgress, + cancelToken: cancelToken, + ); + } + + /// 把 TF 卡上的一个录音拉到调用方给的 sink 里。 + /// + /// 与 [downloadRecording] 的区别是**落点由调用方决定**——通用的 + /// [DeviceFileStore] 端口要把文件放进自己的暂存目录,不能被这里写死。 + Future downloadTo({ + required String name, + required RecFileSink sink, + void Function(int received, int total)? onProgress, + RecCancelToken? cancelToken, + }) async { + if (!await _sdk.ensureRecChannel()) { + throw RecException('通道 B 不可用'); + } + return _sdk.recorder.download( + name: name, + sink: sink, + onProgress: onProgress, + cancelToken: cancelToken, + ); + } + + /// 删除设备上的一个录音。**调用前 UI 必须已二次确认。** + Future deleteRecording(String name) async { + if (!await _sdk.ensureRecChannel()) { + throw RecException('通道 B 不可用'); + } + await _sdk.recorder.deleteFile(name); + recFiles.removeWhere((e) => e.name == name); + } + @override void onInit() { super.onInit(); @@ -217,12 +352,29 @@ class HolderDeviceService extends GetxService { if (s == EchoMeetConnectionState.connected) { _autoConnectTimer?.cancel(); _autoAttempt = 0; - _rememberDevice('Echomeet', connectedAddressRx.value); - // 首次连上支架 → AI 页铺开支架的默认功能编排 - AgentDefaults.onHolderConnected(); + // 名字用本次实际连上的那台。原来这里写死 'Echomeet',换成 EaiRec 之后 + // 记下来的名字会是错的,设备页据 lastDeviceName 选主图就会选错。 + _rememberDevice( + // 兜底名要跟当前固件的广播名一致,否则设备页按名字取产品图会落空。 + // 切换设备名见 EchoMeetDeviceSdk.defaultNameFilters。 + connectedNameRx.value.isNotEmpty ? connectedNameRx.value : 'Echomeet', + connectedAddressRx.value, + ); + // 协议 §8.1 第 7 步:连上后主动查一次电量。 + // ⚠️ 不能只靠 waitConnected() 里那次——**自动回连不走 waitConnected** + // (`tryAutoConnect` 直接调 SDK.connect),于是设备页电量一直空着。 + // 设备侧电量是「请求/响应 + 主动上报」双模式,不问就可能永远等不到。 + _kickBatteryQuery(); + // ⚠️ 绑定登记同样不能只挂在 connect():**自动回连不走 connect()**。 + // 设备一旦记住了,之后每次都是原生回连上线,绑定接口一次都不会打, + // 设备管理页就永远空着(换账号/后台补录 MAC 之后尤其明显)。 + unawaited(bindConnectedToServer()); + // 通道 B(TF 卡文件)握手,失败不影响录音等通道 A 的功能 + unawaited(_initRecChannel()); } else if (s == EchoMeetConnectionState.disconnected && hasPairedDevice) { // 设备关机/走远导致的断连:重新挂上后台扫连,等它再开机 + _batteryRetry?.cancel(); Logger.i(_tag, '连接断开,重新注册后台扫连等待设备上线'); Future.delayed(const Duration(seconds: 3), () => tryAutoConnect()); } @@ -239,7 +391,11 @@ class HolderDeviceService extends GetxService { _connSub?.cancel(); _recSub?.cancel(); _infoSub?.cancel(); + _recInfoSub?.cancel(); + _recListSub?.cancel(); + _recFilesPushes.close(); _autoConnectTimer?.cancel(); + _batteryRetry?.cancel(); super.onClose(); } @@ -289,7 +445,18 @@ class HolderDeviceService extends GetxService { _byAddress.clear(); scanned.clear(); isScanning.value = true; - await _sdk.startScan(); + // ⚠️ 原生 `startScan` 会返回 false(蓝牙未就绪 / 权限 / 已在扫描)。 + // 以前这里不看返回值,UI 就一直转「正在搜索」而其实根本没在扫。 + // 现在失败了等蓝牙栈就绪再补一次;两次都不行才如实把 isScanning 放下来。 + var ok = await _sdk.startScan(); + if (!ok) { + await Future.delayed(const Duration(milliseconds: 800)); + ok = await _sdk.startScan(); + } + if (!ok) { + Logger.w(_tag, '原生扫描未能启动(蓝牙未就绪/权限/已在扫描),UI 退回未扫描态'); + isScanning.value = false; + } } Future stopScan() async { @@ -310,28 +477,54 @@ class HolderDeviceService extends GetxService { /// 把支架登记到服务端的已绑定设备列表。 /// - /// 走的是和杰理耳机同一个 user_binddevice 接口。蓝讯广播里没有杰理那套 - /// pid/code 授权字段,所以 pid 用广播里的 hex(服务端可据此识别), - /// code 留空——接口失败不阻断连接,只记日志。 - Future bindToServer(EchoMeetScannedDevice device) async { + /// 走 `user_binddevice`,与恒玄耳机同一个接口、同一套规则:**只按 MAC 校验** + /// (协议 §2.3;服务端 `api_binddevice.go` 拿 devicemac 在全局 `device_mac` + /// 表里查,产品是从命中行的 productid 列读出来的)。 + /// + /// ⚠️ **不要传 pid**:服务端 `UserBindDeviceReq.pid` 是 `int32`,而这里唯一能填的 + /// `advertisementHex` 是十六进制**字符串**(常常还是空串)。传上去必然 + /// `readUint32: unexpected character` → `code:22`,整个请求被拒, + /// 表现为「连上了但设备管理页永远空着」。恒玄那条链路就是不传 pid 的。 + /// code 也留空:支架没有杰理那套广播授权码。 + /// + /// 接口失败不阻断连接和录音,只是设备管理页没有记录。 + Future bindToServer(EchoMeetScannedDevice device) => + _bindMac(device.name, device.address); + + /// 用**当前连着的**这台去登记。自动回连路径专用:那条路不经过 [connect], + /// 所以拿不到 `EchoMeetScannedDevice`,只有连接时记下的名字和 MAC。 + Future bindConnectedToServer() => + _bindMac(connectedNameRx.value, connectedAddressRx.value); + + /// 本进程内已登记成功的 MAC,避免每次回连都打一次接口。 + /// **只记成功的**:失败(如后台还没补录这台 MAC)下次连上要能重试。 + final Set _bound = {}; + + Future _bindMac(String name, String mac) async { + if (mac.isEmpty) return; if (!User.isLoggedIn()) { Logger.w(_tag, '未登录,跳过设备绑定登记'); return; } + final key = mac.toUpperCase(); + if (_bound.contains(key)) return; try { final resp = await Api.binddevice({ - 'pid': device.advertisementHex, 'code': '', - 'devicename': device.name, - 'devicemac': device.address, + 'devicename': name, + 'devicemac': mac, }); Logger.i(_tag, '绑定接口返回: $resp'); final deviceJson = resp?['device']; if (deviceJson is Map) { + _bound.add(key); User.instance.addUserDevice(UserDevice.fromJson(deviceJson)); Logger.i(_tag, '支架已登记到已绑定设备列表'); } else { - Logger.w(_tag, '绑定接口未返回 device 字段,设备管理页可能看不到这台'); + // resp == null 是服务端明确拒绝(AuthInterceptor 在业务码 != 0 时 + // 把 data 置 null 后 resolve,不抛)——最常见的是这台 MAC 还没导入 + // 后台的 device_mac 表,返回 `{"code":2005,"msg":"设备未登记"}`。 + Logger.w(_tag, '绑定接口未返回 device 字段(resp=$resp),设备管理页看不到这台'); } } catch (e) { // 绑定失败不影响本次连接和录音,只是设备管理页没有记录 @@ -360,8 +553,8 @@ class HolderDeviceService extends GetxService { worker = ever(connection, (s) { if (s == EchoMeetConnectionState.connected) { - // 连上后主动拉一次电量,设备页右下角才有数可显示 - refreshBattery(); + // 电量查询不在这里发:onInit 的 connected 分支已经用 _kickBatteryQuery() + // 带重试地问了。在这儿再补一发只会在服务发现完成前多失败一次。 finish(true); } if (s == EchoMeetConnectionState.error) finish(false); @@ -402,4 +595,60 @@ class HolderDeviceService extends GetxService { Future toggleRecording() => _sdk.toggleRecording(); Future refreshBattery() => _sdk.refreshBattery(); + + // ---------------- 电量:连上后必须重试着问 ---------------- + + Timer? _batteryRetry; + int _batteryTries = 0; + + /// 连上后把电量拿到手。**这里必须重试,问一次是不够的。** + /// + /// ⚠️ 原生的 `connected` 回调在**服务发现之前**就抛出来了(真机实测差约 + /// 700ms),那一刻写特征还是 null,`sendCommand` 直接打 + /// `发送命令失败: 设备未连接` 并返回 false —— 命令整条丢在地上,且没有任何 + /// 上层能看见的错。设备侧电量虽然也有主动上报,但不保证会来, + /// 于是表现就是**设备页右下角永远没有电量**(2026-09-10 真机复现)。 + /// + /// 所以:发不出去就隔 800ms 再发,发出去了给 2s 等回包,直到 deviceInfo + /// 里真的有电量值、或者试满 [_maxBatteryTries] 次为止。 + /// 4 次约 3 秒,够覆盖服务发现那 700ms 的窗口了。**不要调大**: + /// 通道 A 缺失时这些重试一次都不会成功,只是白刷日志(见 [_attemptBattery] 的说明)。 + static const int _maxBatteryTries = 4; + + void _kickBatteryQuery() { + _batteryRetry?.cancel(); + _batteryTries = 0; + unawaited(_attemptBattery()); + } + + Future _attemptBattery() async { + if (!isConnected) return; // 断了就别再问 + if (_batteryTries >= _maxBatteryTries) { + // ⚠️ 走到这里最常见的**不是**时序问题,而是设备根本没有通道 A。 + // 2026-09-10 真机(Echomeet 00:0D:01:00:00:41)服务发现只有一个服务: + // `0xFDA5`(FDA6/FDA7) —— 通道 B(TF 卡)。协议 §4.3 的电量在通道 A + // (`abc0`/`abc1`/`abc2`) 上,那个服务压根不存在,于是原生 checkConn() + // 因 writeChar==null 恒 false,每一发都打「发送命令失败: 设备未连接」。 + // **那条错误信息是误导**:链路好好的,缺的是服务。要电量得固件补通道 A。 + Logger.w( + _tag, + '连上后问了 $_batteryTries 次都没拿到电量。' + '若原生一直报「发送命令失败: 设备未连接」,看服务发现清单:' + '这台固件很可能只暴露了 0xFDA5(通道B),没有 abc0(通道A),电量物理上问不到'); + return; + } + _batteryTries++; + final sent = await refreshBattery(); + _batteryRetry = Timer( + Duration(milliseconds: sent ? 2000 : 800), + () { + if (deviceInfo.value?.batteryLevel != null) { + Logger.i(_tag, '电量已拿到: ${deviceInfo.value?.batteryLevel}%' + '(第 $_batteryTries 次尝试)'); + return; + } + unawaited(_attemptBattery()); + }, + ); + } } diff --git a/apps/client/lib/devices/holder/holder_file_store.dart b/apps/client/lib/devices/holder/holder_file_store.dart new file mode 100644 index 00000000..41b41176 --- /dev/null +++ b/apps/client/lib/devices/holder/holder_file_store.dart @@ -0,0 +1,120 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:echomeet_device_sdk/echomeet_device_sdk.dart'; + +import '../../core/utils/logger.dart'; +import 'holder_device_service.dart'; + +/// EaiRec 支架的设备端文件仓库 —— 通道 B(TF 卡,`0xFDA5`)。 +/// +/// **这台硬件唯一可用的录音路径就是这条**:它没有通道 A' 实时音频上行 +/// (真机 GATT 里根本没有 `ae00`,见 CLAUDE.md 支架那节),录音是 +/// 「录到 TF 卡、事后拉」。所以本类不是锦上添花,是支架录音能不能用的关键。 +/// +/// 协议与状态机都在 `recorder_holder` 的 `RecClient` 里,本类只做两件事: +/// 把它接到通用的 [DeviceFileStore] 上,以及把 SDK 的异常翻译成 [DeviceException]。 +class HolderFileStore implements DeviceFileStore { + HolderFileStore(this._link); + + static const String _tag = 'HolderFileStore'; + + final HolderDeviceService _link; + + @override + bool get isDeviceRecording => + _link.deviceIsRecording || (_link.recInfo.value?.recording ?? false); + + @override + Stream> get listPushes => + _link.recFilesPushes.map((list) => list.map(_toEntry).toList()); + + @override + Future> list() async { + try { + final files = await _link.listRecordings(); + return files.map(_toEntry).toList(growable: false); + } on RecException catch (e) { + throw DeviceException(DeviceErrorCode.fileTransferFailed, e.toString()); + } + } + + @override + Future download( + String name, { + required String destPath, + void Function(int received, int total)? onProgress, + DeviceFileCancelToken? cancelToken, + }) async { + // ⚠️ 正在录的那个文件不能拉:设备还在往里写,拉下来是个残片, + // 而且 size 一直在变,断点续传的长度判断也会错。 + if (isDeviceRecording) { + throw DeviceException(DeviceErrorCode.fileBusy, '设备正在录音'); + } + + final dest = File(destPath); + await dest.parent.create(recursive: true); + + // SDK 的取消令牌与通用令牌是两套类型,这里做个桥接 + final tok = RecCancelToken(); + if (cancelToken?.isCancelled ?? false) { + tok.cancel(); + } else { + unawaited(cancelToken?.whenCancelled.then((_) => tok.cancel())); + } + + final sink = FileRecSink(dest); + await sink.open(); + try { + final result = await _link.downloadTo( + name: name, + sink: sink, + onProgress: onProgress, + cancelToken: tok, + ); + if (!result.complete) { + // 没传完只有两种可能:被取消,或链路断了。前者不是故障。 + if (cancelToken?.isCancelled ?? false) { + throw DeviceException(DeviceErrorCode.cancelled, name); + } + throw DeviceException( + DeviceErrorCode.fileTransferFailed, '$name 未传输完整'); + } + // ⚠️ 落盘字节数必须与设备报的文件长度逐字节对上。 + // 这条是**删除设备原件的前置条件**:传输层虽然逐包校验了 checksum + // (RecClient.verifyChecksum 默认开)且 complete 判的是 bytes==fileSize, + // 但那看的是 sink 的计数,不是磁盘上真实的长度。写盘失败/被截断时 + // 两者会不一致,而我们马上要拿这个结果去做不可逆的删除。 + final onDisk = await dest.length(); + if (onDisk != result.fileSize) { + throw DeviceException(DeviceErrorCode.fileTransferFailed, + '$name 落盘 $onDisk B 与设备报的 ${result.fileSize} B 不符'); + } + Logger.i(_tag, + '已拉取 $name → $destPath ($onDisk B,' + '断点续传 ${result.resumes} 次)'); + return destPath; + } on RecException catch (e) { + throw DeviceException(DeviceErrorCode.fileTransferFailed, e.toString()); + } + } + + @override + Future delete(String name) async { + try { + await _link.deleteRecording(name); + } on RecException catch (e) { + throw DeviceException(DeviceErrorCode.featureFailed, e.toString()); + } + } + + DeviceFileEntry _toEntry(RecFileItem f) => DeviceFileEntry( + name: f.name, + size: f.size, + // RecFileItem.time 解不出合法 FAT 日期时就是 null,原样透传: + // 上层会退回「按导入时刻命名」,好过显示 1980 年 + modifiedAt: f.time, + metadata: {'ftime': f.ftime}, + ); +} diff --git a/apps/client/lib/devices/holder/holder_ota_port.dart b/apps/client/lib/devices/holder/holder_ota_port.dart new file mode 100644 index 00000000..c7e3b871 --- /dev/null +++ b/apps/client/lib/devices/holder/holder_ota_port.dart @@ -0,0 +1,222 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:recorder_holder/recorder_holder.dart'; +import 'package:recorder_holder/recorder_holder_ota.dart'; + +import '../../core/utils/logger.dart'; +import 'holder_device_service.dart'; + +/// EaiRec 支架(中科蓝讯方案)的固件 OTA 端口 —— AB FOT 协议。 +/// +/// 协议实现全在 `recorder_holder/lib/src/ota/`(帧格式、CRC、TLV、状态机), +/// 本类只做两件事:把它接到通用的 [DeviceOtaPort] 上,以及处理**连接交接**。 +/// +/// ⚠️ **OTA 期间必须让出常规 BLE 连接**:一部手机对同一个外设只能有一条链路, +/// 而 `FotBleTransport` 自己用 flutter_blue_plus 连 OTA 服务(`0xFF12`, +/// 与常规的 `abc0`/`ae00`/`FDA5` 是不同的 service,设备重启进 OTA 模式后才暴露)。 +/// 所以 [start] 先 `setEnterOta(true)` 让原生放手,[close] 再 `setEnterOta(false)` +/// 把设备交还给常规会话。这与恒玄那条 SPP OTA 的交接思路一致。 +/// +/// ⚠️ 设备进 OTA 模式后**可能换一个蓝牙地址广播**,所以 `knownRemoteId` 只是 +/// Android 上的快路径,失败会自动退回按 service UUID 扫描(两端共用那条路径)。 +class HolderOtaPort implements DeviceOtaPort { + HolderOtaPort(this._link); + + static const String _tag = 'HolderOtaPort'; + + final HolderDeviceService _link; + + /// 原生插件单例。`setEnterOta` 只在插件层暴露(SDK 没转发),直接用它, + /// 少一层转发就少一处会忘记同步的地方。 + final RecorderHolder _plugin = RecorderHolder(); + + final StreamController _progress = + StreamController.broadcast(); + + FotBleTransport? _transport; + FotOtaSession? _session; + StreamSubscription? _sub; + + bool _running = false; + bool _terminal = false; + bool _succeeded = false; + + /// 我们为了 OTA 把常规连接让出去了,[close] 时要还回来 + bool _handover = false; + int _lastPercent = -1; + + @override + bool get isRunning => _running; + + @override + Stream get progressStream => _progress.stream; + + @override + Future start(DeviceOtaRequest request) async { + if (_running) throw DeviceException(DeviceErrorCode.otaBusy); + if (request is! DeviceOtaFileRequest) { + throw DeviceException( + DeviceErrorCode.notSupported, '${request.runtimeType}'); + } + + final file = File(request.filePath); + if (!await file.exists()) { + throw DeviceException(DeviceErrorCode.otaFileInvalid, request.filePath); + } + final bytes = await file.readAsBytes(); + if (bytes.isEmpty) { + throw DeviceException(DeviceErrorCode.otaFileInvalid, '固件为空'); + } + + _running = true; + _terminal = false; + _succeeded = false; + _lastPercent = -1; + _emit(DeviceOtaState.entering, 0); + + // 1) 让出常规连接。原生 setEnterOta(true) 会 disconnect 且不自动重连。 + final mac = _link.connectedAddress; + _handover = true; + await _plugin.setEnterOta(true); + // 设备要重启进 OTA 模式并重新广播,给它一点时间;连太早只会白等超时。 + await Future.delayed(const Duration(seconds: 2)); + if (!_running) return; // 期间被 cancel 了 + + // 2) 建 OTA 链路(自管连接,与原生那条互斥) + final config = FotOtaConfig( + knownRemoteId: Platform.isAndroid && mac.isNotEmpty ? mac : null, + ); + final transport = FotBleTransport(config: config); + _transport = transport; + + final firmware = FotFirmware.fromBytes(bytes); + final session = FotOtaSession( + transport: transport, + firmware: firmware, + config: config, + ); + _session = session; + _sub = session.progress.listen(_onProgress, onError: (Object e) { + _fail(DeviceErrorCode.otaTransferFailed, e.toString()); + }); + + try { + await transport.open(); + if (!_running) return; + await session.start(); + } catch (e) { + _fail(DeviceErrorCode.otaTransferFailed, e.toString()); + } + } + + void _onProgress(FotProgress p) { + // 终态锁定:迟到的事件一律忽略,否则成功会被收尾事件覆盖成失败 + if (_terminal) return; + switch (p.stage) { + case FotStage.connecting: + _emit(DeviceOtaState.entering, 0); + break; + case FotStage.handshaking: + case FotStage.querying: + _emit(DeviceOtaState.inquiring, 0); + break; + case FotStage.transferring: + _emitPercent(p.percent); + break; + case FotStage.finishing: + case FotStage.verifying: + // 压缩包在这一步解压+烧写,可能要几十秒,UI 别当成卡死 + _emit(DeviceOtaState.verifying, 100); + break; + case FotStage.completed: + _terminal = true; + _succeeded = true; + _running = false; + _emit(DeviceOtaState.done, 100); + break; + case FotStage.failed: + _fail(DeviceErrorCode.otaTransferFailed, + p.message ?? p.deviceStatus?.toString() ?? 'failed'); + break; + case FotStage.idle: + break; + } + } + + /// 进度只在单调递增时上报,避免数字来回跳 + void _emitPercent(int p) { + if (p <= _lastPercent) return; + _lastPercent = p; + _emit(DeviceOtaState.transferring, p); + } + + void _fail(String code, String message) { + if (_terminal) return; + _terminal = true; + _running = false; + Logger.w(_tag, 'OTA 失败: $message'); + _emit(DeviceOtaState.failed, -1, errorCode: code, errorMessage: message); + } + + void _emit(DeviceOtaState st, int percent, + {String? errorCode, String? errorMessage}) { + if (_progress.isClosed) return; + _progress.add(DeviceOtaProgress( + state: st, + sentBytes: 0, + totalBytes: 0, + percent: percent, + tsMs: DateTime.now().millisecondsSinceEpoch, + errorCode: errorCode, + errorMessage: errorMessage, + )); + } + + @override + Future cancel() async { + if (!_running) return; + _running = false; + _terminal = true; + await _teardownLink(); + _emit(DeviceOtaState.cancelled, -1); + } + + /// 会话没了(常规连接断开)。升级中那次断开是我们自己让出的,忽略。 + void onSessionGone() { + if (_handover) return; + if (_running) _fail(DeviceErrorCode.disconnectedRemote, '设备断开'); + } + + Future _teardownLink() async { + await _sub?.cancel(); + _sub = null; + try { + _session?.dispose(); + } catch (_) {} + _session = null; + try { + await _transport?.close(); + } catch (_) {} + _transport = null; + } + + @override + Future close() async { + _running = false; + await _teardownLink(); + if (!_progress.isClosed) await _progress.close(); + + if (!_handover) return; + _handover = false; + // 把设备交还给常规会话。升级成功时设备正在重启,多等几秒。 + await _plugin.setEnterOta(false); + final delay = _succeeded + ? const Duration(seconds: 5) + : const Duration(seconds: 2); + Future.delayed(delay, () { + if (!_link.isConnected) _link.tryAutoConnect(); + }); + } +} diff --git a/apps/client/lib/devices/smartcar/smartcar_device_auth.dart b/apps/client/lib/devices/smartcar/smartcar_device_auth.dart new file mode 100644 index 00000000..9a7b3dbf --- /dev/null +++ b/apps/client/lib/devices/smartcar/smartcar_device_auth.dart @@ -0,0 +1,170 @@ +import 'package:get_storage/get_storage.dart'; + +import '../../core/utils/logger.dart'; +import '../../data/models/user_Info.dart'; +import '../../data/services/network/api.dart'; +import '../device_auth.dart'; + +/// 「账号 ↔ Smartcar」的确权 + 绑定登记,走服务端 `user_binddevice`。 +/// +/// 与恒玄那套([BesDeviceAuth])同一个套路,判定口径逐条对齐, +/// 但有**一个关键差别**—— +/// +/// ## MAC 从广播里来,所以 iOS 也能真正确权 +/// +/// 恒玄链路上 iOS 拿不到真 MAC(CoreBluetooth 只给 peripheral UUID, +/// 每台手机看同一只耳机都不一样),所以那边 iOS 一律放行、闸门等于没有。 +/// +/// Smartcar 的**经典蓝牙 MAC 就写在 BLE 广播里**(厂商数据 CID 之后的 6 字节,原样、不异或), +/// 两端解出来完全一致。所以这条链路的确权在 iOS 上是真生效的。 +/// ⚠️ 别照抄恒玄那句「非 Android 直接返回 null」。 +/// +/// ## 服务端不需要改 +/// +/// 设备表 2026-09-04 已合成全局一张 `device_mac`,按 MAC 全局反查、 +/// 产品从命中行的 `productid` 列读出。所以**只报 MAC,不传 pid**—— +/// 2026-09-04 那次「设备连不上」的事故根因就是客户端猜 pid 猜错了。 +/// +/// ## 第一次连才走服务端,之后读本地白名单 +/// +/// 白名单**不按账号分**:确权说的是「这台硬件是不是正品」,是设备属性不是账号属性, +/// 换账号不该让同一台设备重新变可疑。[reset](登出)只清进程内的上报去重集合。 +/// +/// ## 判不出来一律放行 +/// +/// [DeviceAuthResult.unknown] 放行是刻意选的失败方向:判严的代价是 +/// **合法用户一断网就用不了自己的设备**;判宽只是未登记设备离线时能用一会儿, +/// 联网第一次确权就会被拦下。前者严重得多。 +class SmartcarDeviceAuth { + SmartcarDeviceAuth._(); + + static const String _tag = 'SmartcarDeviceAuth'; + + /// 确权通过的 MAC 白名单(持久化,存大写) + static const String _authorizedKey = 'smartcar_authorized_macs'; + + static final GetStorage _storage = GetStorage(); + + /// 本进程已成功登记的 MAC,避免每次回连都打接口。只记成功的。 + static final Set _reported = {}; + + /// 同一台设备的确权正在进行,避免状态抖动时并发打接口 + static final Set _inflight = {}; + + /// 登出时调:换账号后同一台设备要重新登记到新账号名下。 + /// **白名单不清**(理由见类注释)。 + static void reset() => _reported.clear(); + + static List get _whitelist => + (_storage.read(_authorizedKey) ?? const []) + .map((e) => e.toString()) + .toList(); + + static bool isAuthorizedLocally(String mac) => + mac.isNotEmpty && _whitelist.contains(mac.toUpperCase()); + + static Future _remember(String mac) async { + final list = _whitelist; + final m = mac.toUpperCase(); + if (list.contains(m)) return; + list.add(m); + await _storage.write(_authorizedKey, list); + } + + /// 把一台设备移出白名单,下次连上重新走服务端确权。 + /// + /// ⚠️ 用户在设备管理页主动解绑时**必须**调这个:白名单命中会跳过接口, + /// 不清的话解绑之后再连上不会重新登记,设备管理页就永远空着了。 + static Future forget(String mac) async { + if (mac.isEmpty) return; + final m = mac.toUpperCase(); + _reported.remove(m); + final list = _whitelist..remove(m); + await _storage.write(_authorizedKey, list); + } + + /// 【调试/售后】清空白名单 + static Future clearWhitelist() async { + await _storage.remove(_authorizedKey); + _reported.clear(); + } + + /// 校验一台刚连上的 Smartcar。 + /// + /// [mac] 来自广播(CID 之后 6 字节原样)。拿不到就 [DeviceAuthResult.unknown]。 + static Future verify({ + required String? mac, + required String name, + }) async { + if (mac == null || mac.isEmpty) { + Logger.i(_tag, '广播里没解出 MAC,跳过校验(放行)'); + return DeviceAuthResult.unknown; + } + final m = mac.toUpperCase(); + + // ① 本地白名单——第一次之后走这条,不打接口、离线也能连 + if (isAuthorizedLocally(m)) return DeviceAuthResult.authorized; + + if (_inflight.contains(m)) return DeviceAuthResult.unknown; + _inflight.add(m); + try { + return await _verifyRemote(mac: m, name: name); + } finally { + _inflight.remove(m); + } + } + + static Future _verifyRemote({ + required String mac, + required String name, + }) async { + if (!User.isLoggedIn()) { + // 先连设备后登录是常见顺序,不算失败:下次连接或拉设备列表时会再校一次 + Logger.i(_tag, '未登录,暂不校验,放行'); + return DeviceAuthResult.unknown; + } + + // 服务端已经绑过这台了,等于确权通过,省一次往返 + if (User.instance.devices + .any((d) => d.devicemac.toUpperCase() == mac)) { + await _remember(mac); + _reported.add(mac); + return DeviceAuthResult.authorized; + } + + try { + // ⚠️ **不传 pid**:服务端按 MAC 全局反查(device_mac 合表后), + // 产品是从命中行读出来的。客户端猜 pid 出过事故,别加回来。 + // code 传空:C2 的 License 在广播里,但服务端这条链路认的是 MAC。 + // 10s 上限:确权排在握手后、业务可用前,dio 那边 connect/receive 各 30s, + // 弱网不限制会让首连干等一分钟。超时 → catch → unknown → 放行。 + final resp = await Api.binddevice({ + 'code': '', + 'devicename': name, + 'devicemac': mac, + }).timeout(const Duration(seconds: 10)); + + // ⚠️ null 与抛异常含义**完全相反**,绝不能合并处理: + // AuthInterceptor 在业务码 != 0 时把 data 置 null 后 **resolve(不抛)**, + // 网络层出问题才抛 DioException。 + // 所以 null = 服务端明确拒绝 → denied;异常 = 没连上服务端 → unknown。 + // 写成 try{ if(resp==null) ... }catch{ 同样处理 } 等于断网即锁死设备。 + if (resp == null) { + Logger.w( + _tag, + '服务端拒绝: name=$name mac=$mac —— 这个 MAC 不在 device_mac 表里,' + '去后台「设备管理 → 生成MAC」确认是否已生产/导入'); + return DeviceAuthResult.denied; + } + + await _remember(mac); + _reported.add(mac); + Logger.i(_tag, '确权通过并已登记: $mac'); + return DeviceAuthResult.authorized; + } catch (e) { + // 网络层问题:放行。判严会让合法用户断网时用不了自己的设备。 + Logger.w(_tag, '确权请求异常(放行): $e'); + return DeviceAuthResult.unknown; + } + } +} diff --git a/apps/client/lib/devices/smartcar/smartcar_device_plugin.dart b/apps/client/lib/devices/smartcar/smartcar_device_plugin.dart new file mode 100644 index 00000000..0a9e9f85 --- /dev/null +++ b/apps/client/lib/devices/smartcar/smartcar_device_plugin.dart @@ -0,0 +1,959 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:classic_bluetooth/classic_bluetooth.dart'; +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:flutter/services.dart' show Uint8List; +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:permission_handler/permission_handler.dart'; + +import '../../core/utils/logger.dart'; +import '../../data/utils/pcm_stream_player.dart'; +import '../../core/utils/permission_util.dart'; +import '../device_auth.dart'; +import '../device_vendors.dart'; +import 'smartcar_device_auth.dart'; +import 'smartcar_link.dart'; +import 'smartcar_ota_port.dart'; +import 'smartcar_protocol.dart'; + +/// Smartcar(车载香薰)厂商插件。 +/// +/// 把 [SmartcarLink] 的 C2 私有协议适配成 [DevicePlugin] / [DeviceSession] 契约, +/// 业务层看到的只是「一台能读电量、能报 MAC、能发私有命令的设备」。 +/// +/// ## 本期(阶段 1~3)范围 +/// +/// 只做**连接 + 控制 + 绑定确权**。声明的能力集也只有这些—— +/// [DeviceCapability] 是「只增不删」的,先声明再实现会让业务层把不存在的功能画出来。 +/// +/// 还没做、要等后续阶段的: +/// - `micUplink` / `aiWake`:Opus 上行(阶段 6),要在同一条 GATT 上订阅 +/// [SmartcarProtocol.audioNotifyCharUuid],**不能另起连接** +/// - `ota`:阶段 7,搬杰理 OTA SDK +/// - 经典蓝牙 A2DP 音乐(阶段 5),要先给 `classic_bluetooth` 补 `connectDevice` +class SmartcarDevicePlugin implements DevicePlugin { + static const String _tag = 'SmartcarDevicePlugin'; + + /// 记住的设备(自动回连用)。存 `{id, name, mac}`。 + static const String _rememberedKey = 'smartcar_remembered_devices'; + + final SmartcarLink link = SmartcarLink(); + final GetStorage _storage = GetStorage(); + final _events = StreamController.broadcast(); + + /// 扫描诊断事件的 key(业务层按它取 [DevicePluginEvent.customPayload])。 + /// + /// 业务层**不能** import 厂商目录(`device_hub_boundary_test` 守着), + /// 所以诊断信息只能顺着插件事件流出去。 + static const String kScanDiagnosticKey = 'smartcar.scan_diagnostic'; + + SmartcarSession? _session; + StreamSubscription? _connSub; + StreamSubscription>? _diagSub; + bool _disposed = false; + bool _scanning = false; + + @override + String get vendorKey => DeviceVendors.smartcar; + + @override + String get displayName => 'Smartcar (车载香薰)'; + + @override + Set get capabilities => SmartcarSession.caps; + + @override + DevicePluginConfigSchema get configSchema => DevicePluginConfigSchema.empty; + + @override + DeviceSession? get activeSession => _session; + + @override + Stream get eventStream => _events.stream; + + @override + Future initialize(DevicePluginConfig config) async { + _checkAlive(); + // 这里**不申请权限、不起扫描**:initialize 在冷启动就跑, + // 弹权限框会在启动页糊用户一脸(与 bes / holder 同口径)。 + _diagSub?.cancel(); + _diagSub = link.diagnostics.listen((d) { + _emit(DevicePluginEvent( + type: DevicePluginEventType.customEvent, + customKey: kScanDiagnosticKey, + customPayload: d, + )); + }); + + _connSub?.cancel(); + _connSub = link.connected.listen((up) { + if (!up) { + _session?._markDisconnected(); + _session = null; + } + _emit(DevicePluginEvent( + type: DevicePluginEventType.connectionStateChanged, + deviceId: link.deviceId, + connectionState: up + ? DeviceConnectionState.ready + : DeviceConnectionState.disconnected, + )); + }); + _emit(const DevicePluginEvent(type: DevicePluginEventType.pluginReady)); + } + + /// 自持 GATT 要的运行时权限(Android 12+)。iOS 由系统在首次用 CoreBluetooth 时弹框。 + static const List _btPermissions = [ + Permission.bluetoothScan, + Permission.bluetoothConnect, + ]; + + /// 用户拒绝过且仍在冷却期——UI 据此置灰入口(与支架同一套闸) + bool get isPermissionCoolingDown => + Platform.isAndroid && + PermissionUtil.instance.isAnyDenialCoolingDown(_btPermissions); + + @override + Future ensureReady() async { + if (!Platform.isAndroid) return true; + // ⚠️ Android 12+ 起 BLUETOOTH_SCAN / BLUETOOTH_CONNECT 是运行时权限, + // 没授权时原生 startScan 直接抛 SecurityException。我们不走 flutter_blue_plus + // (它自己会申请),所以这一步必须自己做,否则安卓上永远「扫不到设备」且不报错。 + if (isPermissionCoolingDown) { + Logger.i(_tag, '蓝牙权限已被拒绝且在冷却期,本次不再申请'); + return false; + } + final granted = await PermissionUtil.instance.requestPermissions( + permissions: _btPermissions, + permissionName: 'bluetoothPermissions'.tr, + explanationText: 'bluetoothPermissionDetailDesc'.tr, + userInitiated: true, + ); + if (!granted) await PermissionUtil.instance.markDenied(_btPermissions); + return granted; + } + + // ───────────────────────────── 扫描 ───────────────────────────── + + StreamSubscription? _scanSub; + + @override + Future startScan({DeviceScanFilter? filter, Duration? timeout}) async { + _checkAlive(); + await stopScan(); + _scanning = true; + _emit(const DevicePluginEvent(type: DevicePluginEventType.scanStarted)); + + _scanSub = link + .scan(timeout: timeout ?? const Duration(seconds: 15)) + .listen((r) { + _emit(DevicePluginEvent( + type: DevicePluginEventType.deviceDiscovered, + deviceId: r.id, + discovered: DiscoveredDevice( + id: r.id, + name: r.name.isEmpty ? 'Smartcar' : r.name, + rssi: r.rssi, + vendor: vendorKey, + // ⚠️ MAC 与 License 只在广播里有,连上之后就拿不到了。 + // 绑定确权要用,所以在这里就带出去,别等到 connect 之后再找。 + metadata: { + 'mac': r.advertisement?.macAddress, + 'license': r.advertisement?.license, + 'pid': r.advertisement?.pid, + 'classicBtConnected': r.advertisement?.classicBtConnected, + }, + ), + )); + }, onError: (Object e) { + _emit(DevicePluginEvent( + type: DevicePluginEventType.error, + errorCode: DeviceErrorCode.scanFailed, + errorMessage: '$e', + )); + }, onDone: () { + _scanning = false; + _emit(const DevicePluginEvent(type: DevicePluginEventType.scanStopped)); + }); + } + + @override + Future stopScan() async { + await _scanSub?.cancel(); + _scanSub = null; + await link.stopScan(); + if (_scanning) { + _scanning = false; + _emit(const DevicePluginEvent(type: DevicePluginEventType.scanStopped)); + } + } + + @override + Future isScanning() async => _scanning; + + @override + Future> bondedDevices() async => rememberedDevices; + + // ───────────────────────────── 连接 ───────────────────────────── + + @override + Future connect(String deviceId, + {DeviceConnectOptions? options}) async { + _checkAlive(); + await stopScan(); + + final adv = options?.extra['advertisement']; + final macHint = options?.extra['mac'] as String?; + + try { + // 45s 不是随手写的:GATT 最多等 35s(设备被别的手机占着时不接受新连接), + // 之后杰理认证再给 15s。给 15s 会在设备刚被抢走时误报"超时"。 + await link.connect( + deviceId, + timeout: options?.timeout ?? const Duration(seconds: 45), + adv: adv is SmartcarAdvertisement ? adv : null, + ); + } on TimeoutException catch (e) { + throw DeviceException(DeviceErrorCode.connectTimeout, '$e'); + } catch (e) { + throw DeviceException(DeviceErrorCode.connectFailed, '$e'); + } + + final s = SmartcarSession( + deviceId: deviceId, + link: link, + plugin: this, + macAddress: link.advertisement?.macAddress ?? macHint, + ); + // 契约要求:握手完成后才 resolve。这里的「握手」= 取到固件版本, + // 取不到说明服务/特征对不上,宁可判失败也别把半条链路交给业务层。 + try { + await s._handshake(); + } catch (e) { + await link.disconnect(); + // 握手失败 = BLE 连上了但设备不认我们的命令(命令号错、CRC 错、 + // 或这一版固件根本没有 0x15/0x01)。**必须把原因带出去**, + // 只说「连接失败」分不清是链路问题还是协议问题。 + throw DeviceException( + DeviceErrorCode.handshakeFailed, 'BLE 已连上,但握手失败:$e'); + } + // 确权闸门。放在握手之后:要拿设备名去登记,而设备名是握手时才确定的。 + // + // ⚠️ 只有 denied 才断开。unknown(未登录/断网/没解出 MAC)一律放行—— + // 判严的代价是合法用户断网就用不了自己的设备,见 [SmartcarDeviceAuth] 类注释。 + final auth = await SmartcarDeviceAuth.verify( + mac: s.info.macAddress, + name: s.info.name, + ); + if (auth == DeviceAuthResult.denied) { + await link.disconnect(); + throw DeviceException( + DeviceErrorCode.connectFailed, + '设备未登记:这台 MAC 不在后台设备表里', + ); + } + + _session = s; + // 顺手把经典蓝牙(A2DP)接起来:AI 回复与音乐都靠它出声,BLE 只走控制与上行。 + // Android 上是 createBond(配上了系统自己接 A2DP);iOS 上做不到,只会返回 + // unsupported_ios,由扫描页提示用户去系统设置配对。失败一律不影响 BLE 会话。 + unawaited(s.connectClassicAudio().then((r) { + Logger.i(_tag, '经典蓝牙: $r'); + }).catchError((Object e) { + Logger.w(_tag, '经典蓝牙自动连接失败(不影响 BLE): $e'); + })); + _emit(DevicePluginEvent( + type: DevicePluginEventType.connectionStateChanged, + deviceId: deviceId, + connectionState: DeviceConnectionState.ready, + )); + return s; + } + + // ────────────────────── 记住 / 回连 / 解绑 ────────────────────── + + List> get _remembered => + (_storage.read(_rememberedKey) ?? const []) + .whereType() + .map((e) => e.cast()) + .toList(); + + @override + List get rememberedDevices => _remembered + .map((m) => DiscoveredDevice( + id: '${m['id']}', + name: '${m['name'] ?? 'Smartcar'}', + vendor: vendorKey, + metadata: {'mac': m['mac']}, + )) + .toList(); + + @override + DiscoveredDevice? get lastKnownDevice { + final list = rememberedDevices; + return list.isEmpty ? null : list.first; + } + + @override + Future rememberDevice(DiscoveredDevice device) async { + final list = _remembered..removeWhere((m) => m['id'] == device.id); + // 最近的排前面,[lastKnownDevice] 靠这个顺序 + list.insert(0, { + 'id': device.id, + 'name': device.name, + 'mac': device.metadata['mac'], + }); + await _storage.write(_rememberedKey, list); + } + + @override + Future forgetDevice(String deviceId) async { + final list = _remembered..removeWhere((m) => m['id'] == deviceId); + await _storage.write(_rememberedKey, list); + if (link.deviceId == deviceId) await link.disconnect(); + } + + @override + Future tryAutoConnect() async { + if (_disposed || _session != null || link.isConnected) return; + final first = rememberedDevices.isEmpty ? null : rememberedDevices.first; + if (first == null) return; + try { + await connect(first.id); + } catch (e) { + // 回连失败很正常(设备不在身边 / 蓝牙没开),不该打扰用户 + Logger.i(_tag, '自动回连未成功: $e'); + } + } + + @override + Future dispose() async { + if (_disposed) return; + _disposed = true; + await _scanSub?.cancel(); + await _connSub?.cancel(); + await _diagSub?.cancel(); + await link.dispose(); + _emit(const DevicePluginEvent(type: DevicePluginEventType.pluginDisposed)); + await _events.close(); + } + + void _emit(DevicePluginEvent e) { + if (!_events.isClosed) _events.add(e); + } + + void _checkAlive() { + if (_disposed) throw StateError('SmartcarDevicePlugin 已 dispose'); + } +} + +/// Smartcar 的会话句柄 +class SmartcarSession implements DeviceSession { + SmartcarSession({ + required this.deviceId, + required SmartcarLink link, + required SmartcarDevicePlugin plugin, + String? macAddress, + }) : _link = link, + _plugin = plugin, + _mac = macAddress { + _frameSub = _link.frames.listen(_onFrame); + } + + /// 本期实现到的能力。 + /// + /// ⚠️ **只增不删**,而且**别提前声明没做的**:业务层按能力画 UI, + /// 声明了 `micUplink` 却没实现,AI 页就会出现一个点了没反应的入口。 + static const Set caps = { + DeviceCapability.scan, + DeviceCapability.connect, + DeviceCapability.battery, + // Smartcar 的 MAC 在广播里,**iOS 也拿得到**——这点比恒玄强, + // 恒玄在 iOS 上只有 peripheral UUID,确权等于没有。 + DeviceCapability.macAddress, + DeviceCapability.customCommand, + // 杰理 OTA:原生 cmdOTAData + stage2 扫描回连(从 lumi 搬),见 [SmartcarOtaPort] + DeviceCapability.ota, + // 设备麦克风上行:opus → 16k PCM(原生 SmartcarAudio 解码) + DeviceCapability.micUplink, + // 设备按键/语音唤醒 AI:设备主动上报 0xCC 0x11。声明它就能白嫖 + // DeviceAiSessionService 那整套会话编排 + DeviceCapability.aiWake, + // ⚠️ 刻意**不声明** speakerDownlink:AI 回复不走 BLE,走经典蓝牙 A2DP + // (手机正常播放,设备当音箱)。openSpeaker(ai) 返回的是"手机扬声器"这个汇, + // 见 [_SmartcarPhoneSpeaker]。 + }; + + @override + final String deviceId; + + final SmartcarLink _link; + /// OTA 结束后回连要用([SmartcarOtaPort.close]) + final SmartcarDevicePlugin _plugin; + final String? _mac; + + StreamSubscription? _frameSub; + final _events = StreamController.broadcast(); + final _wake = StreamController.broadcast(); + _SmartcarMic? _mic; + _SmartcarPhoneSpeaker? _spk; + + DeviceConnectionState _state = DeviceConnectionState.linkConnected; + DeviceInfo _info = const DeviceInfo(id: '', name: '', vendor: ''); + + @override + String get vendor => DeviceVendors.smartcar; + + @override + DeviceConnectionState get state => _state; + + @override + DeviceInfo get info => _info; + + @override + Set get capabilities => caps; + + @override + bool supports(DeviceCapability c) => caps.contains(c); + + @override + Stream get eventStream => _events.stream; + + /// 握手:先宣告「APP 已连接」(0x10),再取一次固件版本 + 参数汇总。 + /// + /// ⚠️ 0x10 不能省:杰理认证通过、0x15 也能应答的情况下,设备屏幕照样显示 + /// BLE 未连接,直到收到这条(真机 2026-09-10 验证,见 [SmartcarProtocol.cmdAppConnected])。 + /// 它失败就判握手失败——"App 以为连上了、设备不认"正是这次排查的起点。 + /// + /// 0x15 一次就把电量、版本、各种开关全带回来了,比逐条问省好几个往返。 + /// 拿不到 0x15 时退回 0x01(只要版本号),两条都失败才判握手失败。 + Future _handshake() async { + _info = DeviceInfo( + id: deviceId, + name: 'Smartcar', + vendor: vendor, + macAddress: _mac, + ); + await _announceAppConnected(); + await _jlPostAuth(); + await _syncTime(); + Object? e15; + try { + final f = await _link.send(SmartcarProtocol.cmdSyncSummary); + if (f != null && f.success) { + _applySummary(f.payload); + _state = DeviceConnectionState.ready; + return; + } + e15 = '设备回了 0x15 但 len=0(命令执行失败)'; + } catch (e) { + e15 = e; + Logger.w('SmartcarSession', '0x15 参数汇总失败,退回取版本号: $e'); + } + Object? e01; + SmartcarFrame? v; + try { + v = await _link.send(SmartcarProtocol.cmdGetVersion); + } catch (e) { + e01 = e; + } + if (v == null || !v.success) { + // 两条查询命令都没回应答。最可能的原因按概率排: + // ① 命令号不对(协议文档与 lumi 代码本来就冲突,见 SmartcarProtocol 的 + // TODO(smartcar-cmd));② CRC 算法或帧格式对不上;③ 这版固件不支持。 + throw StateError('0x15 与 0x01 都没有有效应答 ' + '(0x15: $e15; 0x01: ${e01 ?? '无应答'})。' + '多半是命令号或帧格式不对——见 SmartcarProtocol 里的 TODO(smartcar-cmd)'); + } + _applyVersion(v.payload); + _state = DeviceConnectionState.ready; + } + + /// 0x10「蓝牙连接成功」:`[设备类型, 车企编号]`,设备回 `BB 10 01 64` 才算数。 + Future _announceAppConnected() async { + final appType = Platform.isIOS + ? SmartcarProtocol.appTypeIos + : SmartcarProtocol.appTypeAndroid; + SmartcarFrame? f; + try { + f = await _link.send( + SmartcarProtocol.cmdAppConnected, + payload: [appType, SmartcarProtocol.carVendorDefault], + ); + } catch (e) { + throw StateError('0x10「蓝牙连接成功」无应答:$e。' + '认证已过但设备不会把手机当成已连接,屏幕会一直显示 BLE 未连接'); + } + if (f == null || !f.success) { + throw StateError('设备拒绝了 0x10「蓝牙连接成功」(len=0)'); + } + Logger.i('SmartcarSession', '已向设备宣告 APP 连接 (type=$appType),设备应答 ${f.payload}'); + } + + /// 杰理 RCSP 认证后的收尾:设时间 → GET_TARGET_INFO → GET_SYS_INFO。 + /// + /// lumi 两端的 JL SDK 都会在认证后自动发这一串(iOS `initDialSystem`、Android `WatchOpImpl`), + /// 我们自己持有 GATT 就得自己发。2026-09-10 真机:0x10 + 0x15 都成功时屏幕仍显示未连接, + /// 把这串和 0x17 补上之后才亮。TODO(smartcar-handshake):还没二分出到底是哪一步点亮的, + /// 全部保留;失败只记日志不断链——这几条是"锦上添花",链路本身已经能用。 + Future _jlPostAuth() async { + try { + final r = await _link.jlPostAuth(); + Logger.i('SmartcarSession', 'RCSP 认证后收尾: $r'); + } catch (e) { + Logger.w('SmartcarSession', 'RCSP 认证后收尾失败(继续): $e'); + } + } + + /// 0x17 同步手机时间:`[年%100, 月, 日, 时, 分, 秒, 0x01]`(lumi 连上 800ms 后发,设备回 `BB 17 01 64`)。 + /// 协议文档里没有这条,以 lumi 代码与真机应答为准。 + Future _syncTime() async { + final n = DateTime.now(); + try { + await _link.send( + SmartcarProtocol.cmdSyncTime, + payload: [n.year % 100, n.month, n.day, n.hour, n.minute, n.second, 0x01], + timeout: const Duration(seconds: 2), + ); + } catch (e) { + Logger.w('SmartcarSession', '0x17 时间同步无应答(继续): $e'); + } + } + + void _applySummary(List p) { + final s = SmartcarAllSettings.parse(p); + if (s == null) return; + _info = _info.copyWith( + firmwareVersion: s.firmwareVersion, + batteryPercent: s.battery, + battery: DeviceBattery(single: s.battery), + ); + _emitInfo(); + _emitFeature('common.battery', {'percent': s.battery}); + } + + void _applyVersion(List p) { + if (p.length < 3) return; + _info = _info.copyWith( + firmwareVersion: '${p[0] & 0xFF}.${p[1] & 0xFF}.${p[2] & 0xFF}'); + _emitInfo(); + } + + void _onFrame(SmartcarFrame f) { + if (f.isNotify) { + // 设备主动上报。0xCC 0x11 = AI 唤醒:设备已经自己开麦了, + // DeviceAiSessionService 收到 wakeEvents 后会 aiAccept + openMic。 + if (f.cmd == SmartcarProtocol.notifyAiWake) { + Logger.i('SmartcarSession', '设备唤醒 AI 对话 (0xCC 0x11)'); + _emitFeature('smartcar.ai_wake', const {}); + if (!_wake.isClosed) { + _wake.add(DeviceWakeEvent( + deviceId: deviceId, + // 设备侧是按键或语音触发的,协议里区分不出来,统一按 ptt 上报 + reason: WakeReason.ptt, + )); + } + return; + } + if (f.cmd == SmartcarProtocol.cmdGetBattery && f.payload.isNotEmpty) { + final b = f.payload[0] & 0xFF; + _info = _info.copyWith( + batteryPercent: b, battery: DeviceBattery(single: b)); + _emitInfo(); + _emitFeature('common.battery', {'percent': b}); + } + return; + } + if (f.isResponse && f.success) { + if (f.cmd == SmartcarProtocol.cmdSyncSummary) _applySummary(f.payload); + if (f.cmd == SmartcarProtocol.cmdGetVersion) _applyVersion(f.payload); + if (f.cmd == SmartcarProtocol.cmdGetBattery && f.payload.isNotEmpty) { + final b = f.payload[0] & 0xFF; + _info = _info.copyWith( + batteryPercent: b, battery: DeviceBattery(single: b)); + _emitInfo(); + } + } + } + + void _emitInfo() { + if (_events.isClosed) return; + _events.add(DeviceSessionEvent( + type: DeviceSessionEventType.deviceInfoUpdated, + deviceId: deviceId, + deviceInfo: _info, + )); + } + + void _emitFeature(String key, Map data) { + if (_events.isClosed) return; + _events.add(DeviceSessionEvent( + type: DeviceSessionEventType.feature, + deviceId: deviceId, + feature: DeviceFeatureEvent(key: key, data: data), + )); + } + + void _closeAudio() { + _mic?.close(); + _mic = null; + _spk?.close(); + _spk = null; + } + + void _markDisconnected() { + if (_state == DeviceConnectionState.disconnected) return; + _state = DeviceConnectionState.disconnected; + if (!_events.isClosed) { + _events.add(DeviceSessionEvent( + type: DeviceSessionEventType.connectionStateChanged, + deviceId: deviceId, + connectionState: DeviceConnectionState.disconnected, + )); + _events.close(); + } + _frameSub?.cancel(); + _frameSub = null; + // 断链时把音频通路一起收掉:麦克风流没人再喂,扬声器要停掉正在播的 AI 回复 + _closeAudio(); + if (!_wake.isClosed) _wake.close(); + } + + void _requireReady() { + if (_state == DeviceConnectionState.disconnected) { + throw StateError('会话已断开'); + } + if (_state != DeviceConnectionState.ready) { + throw DeviceException( + DeviceErrorCode.noActiveSession, 'Smartcar 会话未就绪'); + } + } + + @override + Future readRssi() async { + _requireReady(); + // flutter_blue_plus 的 readRssi 挂在 BluetoothDevice 上,本期不接; + // 契约允许抛 not_supported,业务层已按能力判断(没声明 rssi 能力)。 + throw DeviceException(DeviceErrorCode.notSupported, 'readRssi'); + } + + @override + Future readBattery() async { + _requireReady(); + final f = await _link.send(SmartcarProtocol.cmdGetBattery); + if (f == null || !f.success || f.payload.isEmpty) return null; + return f.payload[0] & 0xFF; + } + + @override + Future refreshInfo() async { + _requireReady(); + final f = await _link.send(SmartcarProtocol.cmdSyncSummary); + if (f != null && f.success) _applySummary(f.payload); + return _info; + } + + @override + Stream get wakeEvents => _wake.stream; + + @override + Future openMic({AudioRoute route = AudioRoute.mic}) async { + _requireReady(); + // ⚠️ **先关旧的、再开新的**,顺序反了会踩这个坑(2026-09-11 真机): + // 旧 mic 的 close() 会 audioStop(),写在 audioStart() 后面就等于把刚打开的 + // 解码器又关掉。第一次唤醒 _mic 是 null 看不出来,**第二次起每次都上行 0 包**, + // 表现成"第一句正常、后面全卡住"。[_closeMic] 的身份校验是第二道保险。 + final old = _mic; + _mic = null; + await old?.close(); + + // 设备在唤醒后自己开麦,这里只是打开原生的 opus 解码转发 + final ok = await _link.audioStart(); + if (!ok) { + throw DeviceException( + DeviceErrorCode.notSupported, 'opus 解码器起不来,拿不到设备麦克风'); + } + final src = _SmartcarMic(route, _link, _closeMic); + _mic = src; + return src; + } + + /// 关掉某个麦克风源。**只有它还是当前那个才真去停解码器**—— + /// 已经被新会话换掉的旧 mic 再 close 是空操作,否则会误伤新会话。 + Future _closeMic(_SmartcarMic mic) async { + if (!identical(_mic, mic)) return; + _mic = null; + await _link.audioStop(); + } + + @override + Future openSpeaker({AudioRoute route = AudioRoute.ai}) async { + _requireReady(); + if (route != AudioRoute.ai) { + throw DeviceException( + DeviceErrorCode.notSupported, 'openSpeaker($route)'); + } + // ⚠️ 与恒玄不同:Smartcar 的下行**不经 BLE**。AI 回复由手机正常播放, + // 经典蓝牙 A2DP 把它送到设备喇叭。所以这个"汇"就是手机扬声器。 + // 没配对 A2DP 时声音会从手机外放出来——功能仍然成立,只是不在车里响, + // 所以这里只提示、不拦截。 + if (!await isClassicAudioConnected()) { + Logger.w('SmartcarSession', + 'A2DP 未连接,AI 回复会从手机外放。设备 MAC=$_mac'); + } + // 同 openMic:先关旧的再建新的。这里每个 sink 自带播放器、互不共享, + // 顺序反了不会互相误伤,但保持一致的写法,免得下次照着抄出问题。 + final old = _spk; + _spk = null; + await old?.close(); + final sink = _SmartcarPhoneSpeaker(); + _spk = sink; + return sink; + } + + /// 经典蓝牙音频通路(A2DP)通没通——决定 AI 回复"在不在车里响"。 + /// + /// 判据有两个,取其一即可: + /// 1. 系统层:`ClassicBluetooth.isA2dpConnected(MAC)`(Android 查 A2DP profile, + /// iOS 查 AVAudioSession 当前输出) + /// 2. 设备层:广播里的经典蓝牙连接位(`0x0C`)——设备自己说的,最权威, + /// 但只有扫描时才能拿到,连上之后就不再更新 + Future isClassicAudioConnected() async { + final mac = classicMacCandidate; + if (mac == null || mac.isEmpty) return false; + return ClassicBluetooth.isA2dpConnected(mac); + } + + SmartcarOtaPort? _otaPort; + + /// 杰理 OTA 端口。同一会话复用一个实例(端口内部有互斥,重复 start 抛 ota_busy)。 + @override + DeviceOtaPort? otaPort() => _otaPort ??= SmartcarOtaPort(_link, _plugin); + + /// 车载香薰**没有**设备端文件仓库(没有 TF 卡,录音不落设备),所以恒为 null, + /// 能力集里也没有 `DeviceCapability.fileStore`。 + /// 支架那条「录到 TF 卡、事后拉」的链路见 `HolderFileStore`。 + @override + DeviceFileStore? fileStore() => null; + + /// 通用 feature key → C2 命令。 + /// + /// ⚠️ 这张表就是**冻结的协议**:同一个 key 永远发同样的字节。 + /// 改它之前先看 [SmartcarProtocol] 里那些 TODO(smartcar-cmd) 标记—— + /// 有几条命令号本身还没经真机验证。 + @override + Future> invokeFeature( + String key, [ + Map args = const {}, + ]) async { + _requireReady(); + switch (key) { + case 'battery.query': + final b = await readBattery(); + return {'percent': b}; + case 'state.refresh': + await refreshInfo(); + return {'ok': true}; + case 'smartcar.volume': + final v = (args['value'] as num?)?.toInt() ?? 0; + await _link.send(SmartcarProtocol.cmdSetVolume, payload: [v & 0xFF]); + return {'ok': true}; + case 'smartcar.brightness': + final v = (args['value'] as num?)?.toInt() ?? 0; + await _link + .send(SmartcarProtocol.cmdControlBrightness, payload: [v & 0xFF]); + return {'ok': true}; + case 'smartcar.app_connected': + // 重发一次「APP 已连接」宣告(握手里已经发过;这里给排查/固件回落时用) + await _announceAppConnected(); + return {'ok': true}; + + // ---------- AI 会话(DeviceAiSessionService 驱动) ---------- + case DeviceFeatures.aiAccept: + // 设备发完 0xCC 0x11 就自己开麦了,App 这边只要把状态回报过去, + // 设备据此切"聆听中"的表情。**不需要**再下开麦命令。 + await _setAiState(SmartcarProtocol.aiStateListening); + return {'ok': true}; + case DeviceFeatures.aiExit: + await _setAiState(SmartcarProtocol.aiStateClose); + await _link.audioStop(); + return {'ok': true}; + case DeviceFeatures.aiState: + // 通用语义 → C2 的 0x07。**设备的表情动画全靠这条**:不发的话 + // 整轮对话里设备只在开头收到一次"聆听中",之后一直是那个表情 + // (2026-09-11 真机反馈"表情没反应"就是这个原因)。 + final st = args['state']; + final v = switch (st) { + DeviceAiState.listening => SmartcarProtocol.aiStateListening, + DeviceAiState.thinking => SmartcarProtocol.aiStateThinking, + DeviceAiState.speaking => SmartcarProtocol.aiStateSpeakStart, + DeviceAiState.idle => SmartcarProtocol.aiStateSpeakEnd, + _ => null, + }; + if (v == null) { + throw DeviceException( + DeviceErrorCode.invalidArgument, 'ai.state 参数非法: $st'); + } + await _setAiState(v); + return {'ok': true}; + case 'smartcar.ai_state': + final v = (args['value'] as num?)?.toInt(); + if (v == null) { + throw DeviceException(DeviceErrorCode.invalidArgument, '缺少 value'); + } + await _setAiState(v); + return {'ok': true}; + + // ---------- 经典蓝牙 / 音乐 ---------- + case 'smartcar.music_playing': + // 0x05:告诉设备手机在不在放音乐,设备据此显示"听音乐"表情 + final on = args['value'] == true; + await _link.send(SmartcarProtocol.cmdMusicPlayState, + payload: [on ? 0x01 : 0x00]); + return {'ok': true}; + case 'smartcar.a2dp_status': + return { + 'mac': _mac, + 'connected': await isClassicAudioConnected(), + 'devices': (await ClassicBluetooth.getConnectedDevices()) + .map((d) => {'name': d.name, 'address': d.address}) + .toList(), + }; + case 'smartcar.a2dp_connect': + return await connectClassicAudio(); + + case 'smartcar.emotion': + final v = (args['value'] as num?)?.toInt() ?? 0; + await _link + .send(SmartcarProtocol.cmdControlEmotion, payload: [v & 0xFF]); + return {'ok': true}; + default: + throw DeviceException(DeviceErrorCode.notSupported, 'feature $key'); + } + } + + /// 0x07 AI 状态。设备靠它切表情动画,**不回应答**,发完就完事。 + Future _setAiState(int state) async { + try { + await _link + .send(SmartcarProtocol.cmdAiState, payload: [state & 0xFF]); + } catch (e) { + // 状态同步失败不该中断会话——它只影响设备表情,不影响对话本身 + Logger.w('SmartcarSession', '0x07 AI 状态($state) 发送失败: $e'); + } + } + + /// 发起经典蓝牙配对,让 A2DP 通起来(AI 回复与音乐都靠它出声)。 + /// + /// - Android:`createBond()`,配对成功后系统自己接 A2DP + /// - iOS:**做不到**——Apple 没有发起经典蓝牙配对的公开 API,只能引导用户 + /// 去「设置 → 蓝牙」手动配一次。返回 `{'ok': false, 'status': 'unsupported_ios'}` + Future> connectClassicAudio() async { + final mac = classicMacCandidate; + if (mac == null || mac.isEmpty) { + return {'ok': false, 'status': 'no_mac', 'hint': '广播里没解出 MAC'}; + } + if (await ClassicBluetooth.isA2dpConnected(mac)) { + return {'ok': true, 'status': 'already_connected', 'mac': mac}; + } + try { + final status = await ClassicBluetooth.connectDevice(mac); + Logger.i('SmartcarSession', + '经典蓝牙 connectDevice($mac) → $status(广播MAC=$_mac, BLE id=$deviceId)'); + return { + 'ok': status != null && status != 'unsupported_ios', + 'status': status, + 'mac': mac, + }; + } catch (e) { + Logger.w('SmartcarSession', '经典蓝牙配对失败: $e'); + return {'ok': false, 'status': 'error', 'error': '$e', 'mac': mac}; + } + } + + /// 拿去配经典蓝牙的 MAC。 + /// + /// 协议文档说广播里那 6 字节就是**经典蓝牙 MAC**,iOS 真机上服务端也按它确权通过了, + /// 所以默认原样用。但 lumi 的 Android 实现是另一套:`经典 MAC = BLE MAC 首字节 − 1` + /// (`deriveClassicMacFromBleMac`,固件约定),前提是广播里给的就是 BLE MAC。 + /// + /// 两种说法只能在安卓上分辨——安卓的 `deviceId` 就是 BLE MAC,iOS 只有 UUID: + /// - 广播 MAC ≠ BLE MAC → 广播给的是另一个地址,按文档当经典 MAC 用 + /// - 广播 MAC == BLE MAC → 广播给的其实是 BLE 地址,按 lumi 的规则减一 + /// + /// ⚠️ **未经安卓真机验证**(TODO(smartcar-a2dp))。首次真机看 + /// `connectDevice(...)` 那行日志里三个地址的关系就能定论。 + String? get classicMacCandidate { + final mac = _mac; + if (mac == null || mac.isEmpty) return null; + if (!Platform.isAndroid) return mac; + if (mac.toUpperCase() != deviceId.toUpperCase()) return mac; + final parts = mac.split(':'); + if (parts.length != 6) return mac; + final first = int.tryParse(parts[0], radix: 16); + if (first == null) return mac; + parts[0] = ((first - 1) & 0xFF).toRadixString(16).padLeft(2, '0').toUpperCase(); + return parts.join(':'); + } + + @override + Future disconnect() async { + _state = DeviceConnectionState.disconnecting; + await _link.audioStop(); + await _link.disconnect(); + _markDisconnected(); + } +} + +/// 设备麦克风 → 业务层。原生已经把 opus 解成 16k/16bit/mono PCM。 +class _SmartcarMic implements DeviceAudioSource { + _SmartcarMic(this.route, this._link, this._onClose); + + @override + final AudioRoute route; + final SmartcarLink _link; + + /// 交给会话去决定要不要真停:这个源可能早就被新会话换掉了, + /// 直接 `audioStop()` 会把新会话的解码器一起关了。 + final Future Function(_SmartcarMic) _onClose; + + @override + AudioFormat get format => AudioFormat.pcm16kMono; + + @override + Stream get pcm => _link.audioPcm; + + @override + Future close() => _onClose(this); +} + +/// AI 回复的去处:**手机扬声器**(经典蓝牙 A2DP 连着时就从设备喇叭出来)。 +/// +/// 与恒玄那种"PCM 编码后经 BLE 灌给设备"完全不同——Smartcar 的下行不经 BLE, +/// 所以这里不写任何字节到链路上,只是把 PCM 交给手机播放。 +class _SmartcarPhoneSpeaker implements DeviceAudioSink { + _SmartcarPhoneSpeaker(); + + final PcmStreamPlayer _player = + PcmStreamPlayer(sampleRate: 16000, channels: 1); + + @override + AudioRoute get route => AudioRoute.ai; + + @override + AudioFormat get format => AudioFormat.pcm16kMono; + + @override + Future write(Uint8List pcm) async { + // feed 内部会自己 begin,不用外面掐时序 + _player.feed(pcm); + } + + @override + Future discardPending() => _player.stopNow(); + + @override + Future close() => _player.dispose(); +} diff --git a/apps/client/lib/devices/smartcar/smartcar_link.dart b/apps/client/lib/devices/smartcar/smartcar_link.dart new file mode 100644 index 00000000..2227a575 --- /dev/null +++ b/apps/client/lib/devices/smartcar/smartcar_link.dart @@ -0,0 +1,410 @@ +import 'dart:async'; + +import 'package:device_smartcar/device_smartcar.dart'; +import 'package:flutter/services.dart'; + +import '../../core/utils/logger.dart'; +import 'smartcar_protocol.dart'; + +/// Smartcar 的 BLE 链路:扫描 / 连接 / 收发 C2 帧。 +/// +/// ## 为什么是原生插件、不是 flutter_blue_plus(2026-09-10 真机踩出来的) +/// +/// Smartcar 是杰理芯片,**固件要求先过杰理 RCSP 认证**(在服务 `AE00` 上,由闭源 +/// `JL_BLEKit` 的 `JL_Assist` 跑挑战应答)才把手机当成已连接:认证前设备屏幕显示 +/// BLE 未连接、`ABC0` 私有通道的命令也不理。lumi 两端代码里都写明了这一点 +/// (Android:「全新的 BLE 连接,没有走 JLWatchManager 认证,设备拒绝响应任何 RCSP 命令」)。 +/// +/// 第一版用 flutter_blue_plus 纯 Dart 实现,只订阅了 `ABC0`,从没和 `AE00` 说过话—— +/// 设备看来就是"没人认证过"。认证算法在闭源 SDK 里,Dart 复刻不了;而要把 +/// CBPeripheralDelegate 的回调转交给 SDK,GATT 必须由自己持有,flutter_blue_plus +/// 做不到。于是链路收进原生插件 `device_smartcar`,这里只剩通道封装。 +/// +/// 组帧 / CRC / 广播解析仍在 Dart([SmartcarProtocol]),单测继续守着。 +/// +/// ⚠️ 一部手机对同一个 peripheral **只能有一条 GATT 连接**。阶段 6 的 Opus 上行 +/// 要在原生插件里复用这条连接订阅音频特征,**不能另起一条**。 +class SmartcarLink { + static const String _tag = 'SmartcarLink'; + + final DeviceSmartcar _native = DeviceSmartcar.instance; + StreamSubscription>? _eventSub; + + final _frames = StreamController.broadcast(); + final _connState = StreamController.broadcast(); + final _diag = StreamController>.broadcast(); + final _ota = StreamController>.broadcast(); + final _audio = StreamController.broadcast(); + + /// 设备麦克风上行 PCM(**16k / 16bit / mono**,原生已把 opus 解好)。 + /// 帧格式与解码见原生 `SmartcarAudio`。 + Stream get audioPcm => _audio.stream; + + /// 原生 OTA 事件:`{state: preparing|transferring|stage2|done|failed|cancelled, percent, code?, message?}` + Stream> get otaEvents => _ota.stream; + + /// 解好的帧(CRC 已校验,坏帧不会出现在这里) + Stream get frames => _frames.stream; + + /// 链路通断。**true = 杰理认证已通过**,不是 GATT 连上。 + Stream get connected => _connState.stream; + + /// 扫描诊断:每一台扫到的 BLE 设备(含没命中判定的),扫描页拿去摊开给人看。 + /// 「扫不到」「连不上」两次排查都栽在失败不可见上,所以原生报上来的每个状态/原因 + /// 也会以一行的形式塞进这里。 + Stream> get diagnostics => _diag.stream; + + bool _isConnected = false; + bool get isConnected => _isConnected; + + String? _deviceId; + String? get deviceId => _deviceId; + + /// 连上时记下的广播信息(MAC / License 从这里来) + SmartcarAdvertisement? advertisement; + + /// 最近一次原生上报的链路状态与原因,连接失败时拼进错误信息 + String _lastState = 'disconnected'; + String? _lastReason; + + SmartcarLink() { + _eventSub = _native.events.listen(_onNativeEvent, onError: (Object e) { + Logger.w(_tag, '原生事件流错误: $e'); + }); + } + + // ───────────────────────────── 事件路由 ───────────────────────────── + + StreamController? _scanCtrl; + + void _onNativeEvent(Map e) { + switch (e['type']) { + case 'adapter': + _diagLine('(蓝牙适配器)', 'adapter=${e['state']}'); + break; + case 'scan': + _onScanHit(e); + break; + case 'scanStopped': + final c = _scanCtrl; + _scanCtrl = null; + if (c != null && !c.isClosed) c.close(); + break; + case 'state': + _onStateEvent(e); + break; + case 'custom': + final d = e['data']; + if (d is Uint8List) _onValue(d); + break; + case 'ota': + if (!_ota.isClosed) _ota.add(Map.from(e)); + break; + case 'audio': + final d = e['data']; + if (d is Uint8List && !_audio.isClosed) _audio.add(d); + break; + } + } + + /// 开始接收设备麦克风上行(设备自己开麦,这里只是打开原生的解码转发) + Future audioStart() async { + try { + return await _native.audioStart(); + } on PlatformException catch (e) { + Logger.w(_tag, '音频上行起不来: ${e.message ?? e.code}'); + return false; + } on MissingPluginException { + return false; + } + } + + Future audioStop() async { + try { + await _native.audioStop(); + } catch (_) {} + } + + Future> audioStats() async { + try { + return await _native.audioStats(); + } catch (_) { + return const {}; + } + } + + /// 启动杰理 OTA(原生 `SmartcarOta`:cmdOTAData + stage2 扫描回连)。失败抛 [StateError]。 + Future otaStart(String filePath) async { + try { + await _native.otaStart(filePath); + } on PlatformException catch (e) { + throw StateError(e.message ?? e.code); + } + } + + Future otaCancel() async { + try { + await _native.otaCancel(); + } catch (_) {} + } + + void _onStateEvent(Map e) { + final s = '${e['state']}'; + _lastState = s; + _lastReason = e['reason'] as String?; + Logger.i(_tag, '链路状态 → $s${_lastReason == null ? '' : '($_lastReason)'}'); + _diagLine('(链路 ${e['id'] ?? ''})', '$s${_lastReason == null ? '' : ':$_lastReason'}'); + final up = s == 'ready'; + if (up == _isConnected) return; + _isConnected = up; + if (up) { + _deviceId = e['id'] as String?; + } else { + _failAllPending('链路断开: $s ${_lastReason ?? ''}'); + } + if (!_connState.isClosed) _connState.add(up); + } + + void _diagLine(String name, String msg) { + if (_diag.isClosed) return; + _diag.add({ + 'name': name, 'id': '', 'rssi': 0, 'matched': false, + 'mfg': msg, 'services': '', + }); + } + + // ───────────────────────────── 扫描 ───────────────────────────── + + /// 扫本品类设备。原生侧全量扫(不加 service 过滤——CoreBluetooth 的过滤只认 + /// 「Service UUIDs」AD 字段,C2 的身份在厂商数据里,加了一台都扫不到),这里按两条判定收: + /// 1. 厂商数据能解出合法 C2 广播且 CID == 0x8505(主判据,MAC/License 一并解出) + /// 2. 广播名含 `smartcar`(兜底) + Stream scan({ + Duration timeout = const Duration(seconds: 15), + }) { + final ctrl = StreamController(); + _scanCtrl?.close(); + _scanCtrl = ctrl; + ctrl.onCancel = () async { + if (identical(_scanCtrl, ctrl)) _scanCtrl = null; + await stopScan(); + }; + + () async { + try { + await _native.startScan(timeoutSec: timeout.inSeconds); + } on PlatformException catch (e) { + final msg = e.message ?? e.code; + Logger.e(_tag, '启动扫描失败: $msg'); + _diagLine('(扫描启动失败)', msg); + if (!ctrl.isClosed) ctrl.addError(StateError(msg)); + } on MissingPluginException { + const msg = '本平台没有 Smartcar 原生链路(只支持 Android / iOS)'; + if (!ctrl.isClosed) ctrl.addError(StateError(msg)); + } + }(); + + return ctrl.stream; + } + + Future stopScan() async { + try { + await _native.stopScan(); + } catch (_) {} + } + + void _onScanHit(Map e) { + final id = '${e['id'] ?? ''}'; + final name = '${e['name'] ?? ''}'; + final rssi = (e['rssi'] as num?)?.toInt() ?? 0; + final mfg = e['mfg']; + final services = (e['services'] as List?)?.map((x) => '$x').join(',') ?? ''; + + // CBAdvertisementDataManufacturerDataKey 原样过来:前 2 字节是小端公司 ID + int? companyId; + List payload = const []; + if (mfg is Uint8List && mfg.length >= 2) { + companyId = mfg[0] | (mfg[1] << 8); + payload = mfg.sublist(2); + } + + SmartcarAdvertisement? adv; + // 云衍厂商 ID 0x8505;0x0585 是字节序反过来的写法,两个都收(lumi 的常量表并列了两者) + final cidMatched = companyId == 0x8505 || companyId == 0x0585; + if (cidMatched) { + // 补回 [长度, 0xFF, CID低, CID高]:解析器按协议文档吃完整 AD 结构 + adv = SmartcarProtocol.parseManufacturerData( + [payload.length + 3, 0xFF, 0x05, 0x85, ...payload]); + } + final byName = name.toLowerCase().contains('smartcar'); + + if (!_diag.isClosed) { + _diag.add({ + 'name': name, + 'id': id, + 'rssi': rssi, + 'matched': adv != null || byName, + 'mfg': companyId == null + ? '(无厂商数据)' + : '0x${companyId.toRadixString(16).toUpperCase()}[${payload.length}]=' + '${payload.map((b) => b.toRadixString(16).padLeft(2, '0')).join()}', + 'services': services, + 'parsedMac': adv?.macAddress ?? '(解不出)', + }); + } + + if (adv == null && !byName) return; + if (adv == null) { + Logger.w(_tag, '按名字命中 "$name" 但厂商广播段解析失败,MAC 取不到;companyId=$companyId len=${payload.length}'); + } + final c = _scanCtrl; + if (c != null && !c.isClosed) { + c.add(SmartcarScanResult(id: id, name: name, rssi: rssi, advertisement: adv)); + } + } + + // ───────────────────────────── 连接 ───────────────────────────── + + /// 连上并**等杰理认证通过**才返回。失败抛 [StateError],message 带原生报上来的原因 + /// (没有 AE00 / 认证失败 / 认证超时 / GATT 超时 各不相同,别再合并成"连接失败")。 + /// + /// [timeout] 是总超时:GATT 连接本身最多 35s(设备被别的手机占着时不接受新连接, + /// 只能等它超时),认证再给 15s,所以默认给到 45s。 + Future connect( + String deviceId, { + Duration timeout = const Duration(seconds: 45), + SmartcarAdvertisement? adv, + }) async { + advertisement = adv; + _lastReason = null; + try { + await _native.connect(deviceId, timeoutSec: timeout.inSeconds); + } on PlatformException catch (e) { + throw StateError(e.message ?? e.code); + } on MissingPluginException { + throw StateError('本平台没有 Smartcar 原生链路(只支持 Android / iOS)'); + } + // 原生只在 ready 时 resolve;state 事件与 result 谁先到不确定,这里补齐 + if (!_isConnected) { + _isConnected = true; + _deviceId = deviceId; + if (!_connState.isClosed) _connState.add(true); + } + // 认证刚过,给固件一拍再发业务命令(lumi 连上后也留了延迟才 syncCurrentTime) + await Future.delayed(const Duration(milliseconds: 300)); + Logger.i(_tag, '已连接并通过认证 $deviceId'); + } + + /// 杰理 RCSP 认证后的收尾(原生 SDK 发:设时间 / GET_TARGET_INFO / GET_SYS_INFO)。 + /// 返回各步状态,0 = 成功;失败抛 [StateError]。 + Future> jlPostAuth() async { + try { + return await _native.jlPostAuth(); + } on PlatformException catch (e) { + throw StateError(e.message ?? e.code); + } + } + + Future disconnect() async { + _failAllPending('主动断开'); + try { + await _native.disconnect(); + } catch (_) {} + if (_isConnected) { + _isConnected = false; + if (!_connState.isClosed) _connState.add(false); + } + _deviceId = null; + } + + Future dispose() async { + await disconnect(); + await _eventSub?.cancel(); + await _frames.close(); + await _connState.close(); + await _diag.close(); + await _ota.close(); + await _audio.close(); + } + + // ───────────────────────── 收发 ───────────────────────── + + /// 等应答的命令:cmd → 等待者。同一条命令不允许并发两次(应答里没有序号)。 + final Map> _pending = {}; + + void _onValue(List value) { + final f = SmartcarProtocol.parseFrame(value); + if (f == null) { + Logger.w(_tag, '丢弃非法帧: ${_hex(value)}'); + return; + } + if (f.isResponse) { + final c = _pending.remove(f.cmd); + if (c != null && !c.isCompleted) c.complete(f); + } + if (!_frames.isClosed) _frames.add(f); + } + + /// 发一条命令。[expectResponse] 不传就按 [SmartcarProtocol.expectsResponse] 判断—— + /// 那四条设备不回包的命令若强行等,只会白等到超时并把成功记成失败。 + Future send( + int cmd, { + List payload = const [], + bool? expectResponse, + Duration timeout = const Duration(seconds: 3), + }) async { + if (!_isConnected) { + throw StateError('链路未就绪($_lastState),不能发 0x${cmd.toRadixString(16)}'); + } + final wantResp = expectResponse ?? SmartcarProtocol.expectsResponse(cmd); + + Completer? waiter; + if (wantResp) { + final exist = _pending[cmd]; + if (exist != null) return exist.future; + waiter = Completer(); + _pending[cmd] = waiter; + } + + final packet = SmartcarProtocol.buildPacket(cmd, payload); + final ok = await _native.writeCustom(packet); + if (!ok) { + _pending.remove(cmd); + throw StateError('写 0x${cmd.toRadixString(16)} 失败:原生侧没有可用的写特征'); + } + if (waiter == null) return null; + + return waiter.future.timeout(timeout, onTimeout: () { + _pending.remove(cmd); + throw TimeoutException('0x${cmd.toRadixString(16)} 等应答超时'); + }); + } + + void _failAllPending(String why) { + for (final c in _pending.values) { + if (!c.isCompleted) c.completeError(StateError(why)); + } + _pending.clear(); + } + + static String _hex(List b) => + b.map((x) => (x & 0xFF).toRadixString(16).padLeft(2, '0')).join(' '); +} + +/// 一条扫描结果 +class SmartcarScanResult { + const SmartcarScanResult({ + required this.id, + required this.name, + required this.rssi, + this.advertisement, + }); + + final String id; + final String name; + final int rssi; + + /// 厂商广播段。**可能为 null**:仅按名字命中、厂商段解不出来时就是空的, + /// 此时拿不到 MAC,绑定确权会走 unknown(放行但不登记)。 + final SmartcarAdvertisement? advertisement; +} diff --git a/apps/client/lib/devices/smartcar/smartcar_ota_port.dart b/apps/client/lib/devices/smartcar/smartcar_ota_port.dart new file mode 100644 index 00000000..19d64ccf --- /dev/null +++ b/apps/client/lib/devices/smartcar/smartcar_ota_port.dart @@ -0,0 +1,159 @@ +import 'dart:async'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; + +import '../../core/utils/logger.dart'; +import 'smartcar_device_plugin.dart'; +import 'smartcar_link.dart'; + +/// Smartcar(杰理方案)的 OTA 端口。 +/// +/// 推送本身在原生 `SmartcarOta`(从 lumi `PbMangerImp` 搬:`cmdOTAData` + 0xfc 后 +/// 扫描回连 + 认证 + 续传),这里只做三件事: +/// 1. 把原生事件翻译成 [DeviceOtaProgress]; +/// 2. 终态锁定——成功后迟到的 failed/cancelled 不能把它覆盖回去(恒玄踩过); +/// 3. [close]:升级成功设备会重启,退出页面时延时回连记住的设备。 +/// +/// 与恒玄不同,**这条链路不用断 app 层连接**:OTA 数据走同一条 GATT 的 AE01, +/// 私有通道 ABC1 由原生在升级期间挡掉。stage2 阶段设备会主动断开重启, +/// 那次「断开」是升级流程的一部分,不是失败——由原生判定,这里不看链路状态。 +/// +/// ⚠️ 上层 `DeviceOtaController` 的看门狗 90s 没进度就判失败,而 stage2 等待可达 3 分钟, +/// 原生在这段窗口每 15s 发一次 `stage2` 心跳事件喂它。 +class SmartcarOtaPort implements DeviceOtaPort { + SmartcarOtaPort(this._link, this._plugin); + + static const String _tag = 'SmartcarOtaPort'; + + final SmartcarLink _link; + final SmartcarDevicePlugin _plugin; + final StreamController _progress = + StreamController.broadcast(); + + StreamSubscription>? _sub; + bool _running = false; + bool _terminal = false; + bool _succeeded = false; + int _lastPercent = -1; + + @override + bool get isRunning => _running; + + @override + Stream get progressStream => _progress.stream; + + @override + Future start(DeviceOtaRequest request) async { + if (_running) throw DeviceException(DeviceErrorCode.otaBusy); + if (request is! DeviceOtaFileRequest) { + throw DeviceException( + DeviceErrorCode.notSupported, '${request.runtimeType}'); + } + if (!_link.isConnected) { + throw DeviceException(DeviceErrorCode.noActiveSession, '链路未就绪'); + } + _running = true; + _terminal = false; + _succeeded = false; + _lastPercent = -1; + _sub ??= _link.otaEvents.listen(_onEvent, onError: (Object e) { + _fail(DeviceErrorCode.otaTransferFailed, '$e'); + }); + _emit(DeviceOtaState.inquiring, 0); + try { + await _link.otaStart(request.filePath); + } catch (e) { + _fail(DeviceErrorCode.otaTransferFailed, '$e'); + rethrow; + } + } + + void _onEvent(Map e) { + if (_terminal) return; + final state = '${e['state']}'; + final percent = (e['percent'] as num?)?.toInt() ?? -1; + switch (state) { + case 'preparing': + _emit(DeviceOtaState.entering, 0); + break; + case 'transferring': + // 只在单调递增时上报,SDK 的 preparing/prepared 会把百分比打回 0 + if (percent > _lastPercent) { + _lastPercent = percent; + _emit(DeviceOtaState.transferring, percent); + } + break; + case 'stage2': + // 设备断开重启进 stage2,原生在扫描回连;进度条停在 15% 但要持续有事件喂看门狗 + Logger.i(_tag, 'stage2 等待回连: ${e['message'] ?? ''}'); + _emit(DeviceOtaState.rebooting, _lastPercent < 15 ? 15 : _lastPercent); + break; + case 'done': + _terminal = true; + _succeeded = true; + _running = false; + _emit(DeviceOtaState.done, 100); + break; + case 'cancelled': + _terminal = true; + _running = false; + _emit(DeviceOtaState.cancelled, -1); + break; + case 'failed': + _fail(DeviceErrorCode.otaTransferFailed, + '${e['message'] ?? ''} (code=${e['code']})'); + break; + } + } + + void _fail(String code, String message) { + if (_terminal) return; + _terminal = true; + _running = false; + _emit(DeviceOtaState.failed, -1, errorCode: code, errorMessage: message); + } + + @override + Future cancel() async { + if (!_running) return; + await _link.otaCancel(); + // 原生会回 cancelled;5s 内没回就自己收尾(契约要求) + Future.delayed(const Duration(seconds: 5), () { + if (!_terminal) { + _terminal = true; + _running = false; + _emit(DeviceOtaState.cancelled, -1); + } + }); + } + + @override + Future close() async { + if (_running) await cancel(); + await _sub?.cancel(); + _sub = null; + // 升级成功设备会重启,广播回来要几秒;失败/取消时原生已把链路断开,一样回连 + final delay = _succeeded ? const Duration(seconds: 8) : const Duration(seconds: 2); + Future.delayed(delay, () async { + try { + await _plugin.tryAutoConnect(); + } catch (e) { + Logger.w(_tag, 'OTA 后回连失败: $e'); + } + }); + } + + void _emit(DeviceOtaState s, int percent, + {String? errorCode, String? errorMessage}) { + if (_progress.isClosed) return; + _progress.add(DeviceOtaProgress( + state: s, + sentBytes: 0, + totalBytes: 0, + percent: percent, + tsMs: DateTime.now().millisecondsSinceEpoch, + errorCode: errorCode, + errorMessage: errorMessage, + )); + } +} diff --git a/apps/client/lib/devices/smartcar/smartcar_protocol.dart b/apps/client/lib/devices/smartcar/smartcar_protocol.dart new file mode 100644 index 00000000..617e058c --- /dev/null +++ b/apps/client/lib/devices/smartcar/smartcar_protocol.dart @@ -0,0 +1,402 @@ +import 'dart:typed_data'; + +/// Smartcar(车载香薰,方案代号 **C2**)的 BLE 私有协议。 +/// +/// 纯函数 + 纯数据,不碰蓝牙栈,方便单测把每个字节钉死 +/// (`test/devices/smartcar_protocol_test.dart`)。 +/// +/// 帧格式: +/// ``` +/// APP → 设备 0xAA | cmd(1) | len(1) | data(len) | crc(1) +/// 设备 → APP 0xBB | cmd(1) | len(1) | data(len) | crc(1) 应答 +/// 设备 → APP 0xCC | cmd(1) | len(1) | data(len) | crc(1) 主动上报 +/// ``` +/// CRC 覆盖**除自己以外的全部前导字节**,算法见 [crc8Maxim]。 +/// +/// ⚠️ 多字节字段一律**小端**。 +class SmartcarProtocol { + SmartcarProtocol._(); + + // ─────────────────────────── GATT ─────────────────────────── + + /// 控制服务 + static const String serviceUuid = '0000abc0-0000-1111-2222-123456789abc'; + + /// 写特征(WriteWithoutResponse) + static const String writeCharUuid = '0000abc1-0000-1111-2222-123456789abc'; + + /// 通知特征 + static const String notifyCharUuid = '0000abc2-0000-1111-2222-123456789abc'; + + /// 广播里用于扫描过滤的服务 UUID + static const String broadcastServiceUuid = + '0000bb01-0000-1000-8000-00805f9b34fb'; + + /// 音频上行服务 / 特征(**本期不用**,阶段 6 接 Opus 时才需要)。 + /// 注意它与控制服务是两个不同的 service,别混。 + static const String audioServiceUuid = + '0000ae00-0000-1000-8000-00805f9b34fb'; + static const String audioNotifyCharUuid = + '0000ae02-0000-1000-8000-00805f9b34fb'; + + // ─────────────────────────── 帧头 ─────────────────────────── + + static const int headerRequest = 0xAA; + static const int headerResponse = 0xBB; + static const int headerNotify = 0xCC; + + static bool isFrameHeader(int b) => + b == headerRequest || b == headerResponse || b == headerNotify; + + // ───────────────────────── 命令号 ───────────────────────── + // + // ⚠️⚠️ 下面标了 TODO(smartcar-cmd) 的几条,**协议文档与 lumi 代码是冲突的**。 + // 按 2026-09-10 的决定:一律以 lumi 的 BleConst.kt 为准(那是真机上跑着的), + // 协议文档只作参考。样机到手后逐条复核,改这里并同步更新 + // docs/Smartcar车载香薰-接入设计与落地文档.md 的 2.4 节。 + // + // ⚠️ 复核时**只扫查询类命令**。0x0C 恢复出厂 / 0x0D 启停开关 / 0x0E 遥控电机 + // 会真的改设备状态,别拿来试探。 + + /// 获取设备版本号。 + /// + /// ✅ **2026-09-11 真机实测**(样机固件):应答是 **3 字节** `02 0c 0c` → `2.12.12`, + /// **不是**协议文档写的 6 字节(两组 major/minor/patch)。同一个值在 0x15 的 + /// `[5..7]` 又出现了一次,两处对得上,所以 3 字节是可信的。 + static const int cmdGetVersion = 0x01; + + /// 获取设备 ID。✅ 真机实测应答 1 字节:`01` + static const int cmdGetProductId = 0x02; + + /// ⚠️ **含义仍未定**。协议文档里没有这条;lumi `BleConst.kt` 叫 CMD_GET_COLOR_ID, + /// 但 2026-09-11 真机实测应答是 **14 字节** + /// `03 00 00 00 3d 00 00 00 00 00 00 00 00 00`,一个"颜色 ID"不该这么长。 + /// 里面的 `3d`(61) 与当时电量 60 只差 1,也可能是另一份状态汇总。 + /// **本项目没有任何地方在用它**,先留着名字不动,等厂商给准信。 + static const int cmdGetColorId = 0x03; + + /// 获取电量。应答 data[0] = 0~100。 + /// ✅ 真机实测 `3c` = 60%,与同一时刻 0x15 的 `[4]` 完全一致。 + static const int cmdGetBattery = 0x04; + + /// 手机音乐播放状态:`0x00` 没在放 / `0x01` 在放。设备据此显示"听音乐"表情。 + /// + /// ✅ **2026-09-11 定论(改过一次)**:早先按 lumi `BleConst.kt` 的名字 + /// `CMD_CLOSE_AI_DIALOG` 理解成"关闭 AI 对话",是错的。判据是 lumi 的**运行时代码**—— + /// `BleService.swift` 的 `checkMusicPlaybackState()` 在检测到手机在放音乐时发的正是 + /// `0x05 [0x01]`、停止时发 `0x05 [0x00]`,与协议文档「0x05 手机音乐播放状态」一致。 + /// `BleConst.kt` 里那个名字是没跟上的旧命名,别再照它改回去。 + static const int cmdMusicPlayState = 0x05; + + /// 控制设备情绪表达 + static const int cmdControlEmotion = 0x06; + + /// AI 状态(APP → 设备),载荷 1 字节,取值见 [aiStateSpeakEnd] 等。 + /// + /// ✅ **2026-09-11 定论(改过一次)**:早先按 `BleConst.kt` 的 `CMD_CONTROL_MOTION` + /// 理解成"控制动作",是错的——协议文档里"遥控电机"另有其号([cmdRemoteMotor] `0x0E`), + /// 0x07 就是 AI 状态。设备靠它切换"思考中/说话中/聆听中"的表情动画。 + static const int cmdAiState = 0x07; + + /// [cmdAiState] 的取值 + static const int aiStateSpeakEnd = 0x00; + static const int aiStateThinking = 0x01; + static const int aiStateSpeakStart = 0x02; + static const int aiStateClose = 0x03; + static const int aiStateListening = 0x04; + + /// TODO(smartcar-cmd): 未经真机验证 —— 协议文档里没有这条, + /// BleConst.kt 说 CMD_CONTROL_MUSIC_BEAT,取后者。 + static const int cmdControlMusicBeat = 0x08; + + static const int cmdControlBrightness = 0x0A; + static const int cmdSetVolume = 0x0B; + + /// ⚠️ 恢复出厂设置。复核命令表时**不要**发这条。 + static const int cmdFactoryReset = 0x0C; + + /// ⚠️ 启停开关。同上,会改设备状态。 + static const int cmdAutoPowerSwitch = 0x0D; + + /// ⚠️ 遥控电机。同上。 + static const int cmdRemoteMotor = 0x0E; + + static const int cmdSetMusicExpression = 0x0F; + + /// 「蓝牙连接成功」——**APP 告诉设备"我连上了"**,不是经典蓝牙。 + /// + /// ⚠️ 2026-09-10 真机定论:GATT 连上 + 杰理认证通过 + 0x15 都能应答之后, + /// 设备屏幕**仍显示 BLE 未连接**;发了这条(`AA 10 02 03 00`)设备回 `BB 10 01 64`, + /// 屏幕才认。也就是说固件把"手机已连接"这个状态交给 APP 来宣告。 + /// 所以它是握手的一部分([SmartcarSession._handshake]),不是可选功能。 + /// + /// 载荷 2 字节:`[设备类型, 车企编号]`,设备类型 0 车机 / 1 小程序 / 2 安卓 / 3 iOS / 4 鸿蒙, + /// 车企编号 0 默认 / 1 长城。lumi 没发过这条(它不是车载产品)。 + static const int cmdAppConnected = 0x10; + + /// [cmdAppConnected] 的「设备类型」取值 + static const int appTypeAndroid = 0x02; + static const int appTypeIos = 0x03; + static const int appTypeHarmony = 0x04; + + /// [cmdAppConnected] 的「车企编号」:0 默认 + static const int carVendorDefault = 0x00; + + /// 陀螺仪开关(APP → 设备,`0xAA 0x11`)。 + /// + /// ✅ **2026-09-11 定论**:与 [notifyAiWake] 号相同但**方向不同**,协议文档里两条都在 + /// (「0x11 开启AI智能对话」是 `0xCC` 设备上报,「0x11 陀螺仪开关」是 `0xAA` APP 下发), + /// 靠帧头区分,不冲突。 + static const int cmdGyroscopeSwitch = 0x11; + + static const int cmdMusicHeadStyle = 0x12; + static const int cmdRandomExpressionInterval = 0x13; + static const int cmdMotorSwitch = 0x14; + + /// 同步参数汇总。应答 data = 14 字节,见 [SmartcarAllSettings] + static const int cmdSyncSummary = 0x15; + + /// 同步手机时间(协议文档没写,lumi 代码有,真机回 `BB 17 01 64`): + /// 载荷 `[年%100, 月, 日, 时, 分, 秒, 0x01]` + static const int cmdSyncTime = 0x17; + + /// 设备主动上报:AI 对话唤醒(`0xCC 0x11 0x01 0xAA`)。 + /// + /// ⚠️ 协议文档原话:「**不需要 app 回复,设备端直接开麦,录音发 opus 数据给到 app**」。 + /// 也就是说 App 收到它之后不用下"开麦"命令,只要准备好接 opus(见 `SmartcarAudio`), + /// 并用 [cmdAiState] 把会话状态回报给设备去驱动表情。 + static const int notifyAiWake = 0x11; + + /// 这几条设备**不回应答**,发完就完事。 + /// + /// ⚠️ 别给它们等回包——会白等到超时,把一次正常操作记成失败。 + static const Set _noResponse = { + cmdMusicPlayState, + cmdControlEmotion, + cmdAiState, + cmdControlMusicBeat, + }; + + static bool expectsResponse(int cmd) => !_noResponse.contains(cmd); + + // ─────────────────────────── CRC ─────────────────────────── + + /// CRC-8/MAXIM(Dallas/Maxim)。 + /// + /// poly=0x31,反射后 0x8C;init=0x00,xorOut=0x00,refIn/refOut=true。 + /// 与 lumi `BleProtocol.calcCrc` 逐位一致——**改这里等于改协议**, + /// 单测里有真实帧的金值守着。 + static int crc8Maxim(List data) { + var crc = 0x00; + for (final b in data) { + crc ^= b & 0xFF; + for (var i = 0; i < 8; i++) { + crc = (crc & 0x01) != 0 ? (crc >> 1) ^ 0x8C : crc >> 1; + } + } + return crc & 0xFF; + } + + // ────────────────────────── 组帧 ────────────────────────── + + /// 组一帧 APP → 设备的请求。 + static Uint8List buildPacket(int cmd, [List payload = const []]) { + final out = Uint8List(payload.length + 4); + out[0] = headerRequest; + out[1] = cmd & 0xFF; + out[2] = payload.length & 0xFF; + for (var i = 0; i < payload.length; i++) { + out[3 + i] = payload[i] & 0xFF; + } + out[out.length - 1] = crc8Maxim(out.sublist(0, out.length - 1)); + return out; + } + + /// 解一帧设备发来的数据。 + /// + /// 返回 null 表示这段不是合法帧(长度不够 / 帧头不认识 / CRC 不符)。 + /// **CRC 不符一律丢弃**,不要「先用着再说」——错帧解出来的电量、版本号 + /// 看着都像合法值,查起来极费劲(恒玄那次就是被错位解析出的垃圾值带偏的)。 + static SmartcarFrame? parseFrame(List raw) { + if (raw.length < 4) return null; + final header = raw[0] & 0xFF; + if (!isFrameHeader(header)) return null; + final cmd = raw[1] & 0xFF; + final len = raw[2] & 0xFF; + if (raw.length < len + 4) return null; + final expected = raw[len + 3] & 0xFF; + final calc = crc8Maxim(raw.sublist(0, len + 3)); + if (expected != calc) return null; + return SmartcarFrame( + header: header, + cmd: cmd, + payload: Uint8List.fromList(raw.sublist(3, 3 + len)), + ); + } + + // ──────────────────────── 广播解析 ──────────────────────── + + /// 解厂商自定义广播段(传完整 AD 结构:`[长度, 0xFF, CID低, CID高, ...]`)。 + /// + /// **真机实测布局(2026-09-10,Smartcar 样机,与 lumi iOS `parseMacFromManufacturer` + /// 的 0x0585 分支一致)**:CID 之后只有 7 字节 + /// ``` + /// [0] 长度 [1] Type=0xFF + /// [2-3] CID 0x05 0x85 → 小端 0x8505 + /// [4-9] MAC 原样、不异或、不倒序:a9 1a b3 21 e4 dd = A9:1A:B3:21:E4:DD + /// [10] 1 字节状态 TODO(smartcar-adv):未连经典蓝牙时实测为 0x00, + /// 按协议文档「0x0C = 经典蓝牙已连」处理,连上 A2DP 后要复核 + /// ``` + /// 实测原始厂商数据:`05 85 a9 1a b3 21 e4 dd 00`,解出的 MAC 与设备已知地址逐字节相同, + /// 服务端 `user_binddevice` 也按这个 MAC 确权通过。 + /// + /// ⚠️ 协议文档里那套「26 字节:BID/PID/MAC XOR 0x5A/License/设备类型」**这台固件没有发**, + /// 第一版照文档写的解析器要求 26 字节,于是永远解不出、MAC 恒为空。 + /// BID/PID/License 现在从广播里拿不到,字段保留为 0 / 空串。 + static SmartcarAdvertisement? parseManufacturerData(List? raw) { + if (raw == null || raw.length < 10) return null; + if ((raw[1] & 0xFF) != 0xFF) return null; + int le16(int off) => (raw[off] & 0xFF) | ((raw[off + 1] & 0xFF) << 8); + final mac = raw + .sublist(4, 10) + .map((b) => (b & 0xFF).toRadixString(16).padLeft(2, '0').toUpperCase()) + .join(':'); + final state = raw.length > 10 ? raw[10] & 0xFF : 0; + return SmartcarAdvertisement( + cid: le16(2), + bid: 0, + pid: 0, + classicBtConnected: state == 0x0C, + macAddress: mac, + license: '', + deviceType: 0, + ); + } +} + + +/// 一帧解好的数据 +class SmartcarFrame { + const SmartcarFrame({ + required this.header, + required this.cmd, + required this.payload, + }); + + final int header; + final int cmd; + final Uint8List payload; + + bool get isResponse => header == SmartcarProtocol.headerResponse; + bool get isNotify => header == SmartcarProtocol.headerNotify; + + /// 设备回的应答里,`len == 0` 表示这条命令**执行失败** + /// (协议就是这么设计的:成功才带数据)。 + bool get success => payload.isNotEmpty; + + @override + String toString() => + 'SmartcarFrame(0x${header.toRadixString(16)}, cmd=0x${cmd.toRadixString(16)}, ' + 'len=${payload.length})'; +} + +/// 广播里带的设备身份 +class SmartcarAdvertisement { + const SmartcarAdvertisement({ + required this.cid, + required this.bid, + required this.pid, + required this.classicBtConnected, + required this.macAddress, + required this.license, + required this.deviceType, + }); + + /// 生产商 ID(云衍 = 0x8505) + final int cid; + + /// 服务商 ID + final int bid; + + /// 产品 ID + final int pid; + + /// 经典蓝牙当前连没连上(决定要不要发起 A2DP 配对) + final bool classicBtConnected; + + /// **经典蓝牙** MAC,已还原 XOR,大写冒号分隔。 + /// 服务端确权用的就是它(`user_binddevice`)。 + final String macAddress; + + /// 授权码,20 个十六进制字符 + final String license; + + final int deviceType; + + @override + String toString() => 'SmartcarAdv(pid=0x${pid.toRadixString(16)}, ' + 'mac=$macAddress, btConnected=$classicBtConnected)'; +} + +/// `0x15 同步参数汇总` 的 14 字节应答 +class SmartcarAllSettings { + const SmartcarAllSettings({ + required this.otaAbnormal, + required this.volume, + required this.randomExprFreq, + required this.brightness, + required this.battery, + required this.firmwareVersion, + required this.powerSwitch, + required this.musicHeadStyle, + required this.musicExpression, + required this.gyroscope, + required this.motor, + }); + + final bool otaAbnormal; + final int volume; + final int randomExprFreq; + final int brightness; + + /// 0~100 + final int battery; + + /// `major.minor.patch` + final String firmwareVersion; + + final bool powerSwitch; + final int musicHeadStyle; + final bool musicExpression; + final bool gyroscope; + final bool motor; + + /// 布局见 lumi `BleProtocol.AllSettings`: + /// `[0]OTA异常 [1]音量 [2]随机表情频次 [3]亮度 [4]电量 [5..7]版本 + /// [8]启停 [9]摇头风格 [10]音乐表情 [11]陀螺仪 [12]保留 [13]电机` + /// + /// ✅ **2026-09-11 真机实测帧**:`01 00 14 0a 3c 02 0c 0c 00 02 01 01 04 01` + /// —— 偏移由两处**独立交叉验证**钉死:`[4]=0x3c`(60) 与单发 0x04 的电量一字不差、 + /// `[5..7]=02 0c 0c` 与单发 0x01 的版本一字不差。解出来: + /// 亮度 10(0-10 满格)、随机表情频次 20 秒、电量 60%、版本 2.12.12。 + /// + /// ⚠️ **`[1]` 音量实测是 0**。如果这个偏移没错,说明样机当前是静音的—— + /// A2DP 接上后 AI 回复也可能听不见。真机验声音前先确认这一项。 + static SmartcarAllSettings? parse(List d) { + if (d.length < 14) return null; + int u(int i) => d[i] & 0xFF; + return SmartcarAllSettings( + otaAbnormal: u(0) != 0, + volume: u(1), + randomExprFreq: u(2), + brightness: u(3), + battery: u(4), + firmwareVersion: '${u(5)}.${u(6)}.${u(7)}', + powerSwitch: u(8) != 0, + musicHeadStyle: u(9), + musicExpression: u(10) != 0, + gyroscope: u(11) != 0, + motor: u(13) != 0, + ); + } +} diff --git a/apps/client/lib/modules/bes_test/controllers/bes_test_controller.dart b/apps/client/lib/modules/bes_test/controllers/bes_test_controller.dart index f30a3602..a10b60d7 100644 --- a/apps/client/lib/modules/bes_test/controllers/bes_test_controller.dart +++ b/apps/client/lib/modules/bes_test/controllers/bes_test_controller.dart @@ -1,20 +1,24 @@ +import 'package:device_plugin_interface/device_plugin_interface.dart'; import 'package:get/get.dart'; import '../../../core/utils/logger.dart'; -import '../../../data/services/bes_bluetooth_service.dart'; +import '../../../devices/device_hub.dart'; +import '../../../devices/device_vendors.dart'; -/// 恒玄(BES)蓝牙连接模块验证页控制器。 -/// 用于确认原生插件(Android RFCOMM / iOS GATT 桥接)已正确编译、 -/// 注册进 GeneratedPluginRegistrant,方法通道调用不崩溃。 -/// 是否能真正配对/收发数据依赖一台恒玄芯片的实体耳机。 +/// 恒玄(BES)协议探测页控制器(设置 → 开发者)。 +/// +/// 走 [DeviceHub] 的耳机插件;发原始帧用 `bes.send`、扫命令用 `bes.probe`。 +/// 换固件要重扫命令时用它(见 CLAUDE.md「私有协议命令号会随固件版本变」)。 class BesTestController extends GetxController { static const String _tag = 'BesTestController'; - final BesBluetoothService _service = BesBluetoothService.to; + DevicePlugin get _plugin => DeviceHub.to.plugin(DeviceVendors.bes)!; + DeviceSession? get _session => DeviceHub.to.sessionOf(DeviceVendors.bes); - RxInt get deviceStatus => _service.deviceStatus; - RxString get connectedDeviceName => _service.connectedDeviceName; - RxString get connectedDeviceId => _service.connectedDeviceId; + /// 0=未连接 1=连接中 2=已连接(沿用页面原来的约定) + final RxInt deviceStatus = 0.obs; + final RxString connectedDeviceName = ''.obs; + final RxString connectedDeviceId = ''.obs; final RxBool isInitialized = false.obs; final RxBool isBusy = false.obs; @@ -22,9 +26,32 @@ class BesTestController extends GetxController { >[].obs; final RxList logLines = [].obs; + Worker? _worker; + + @override + void onInit() { + super.onInit(); + _worker = ever(DeviceHub.to.revision, (_) => _sync()); + _sync(); + } + + @override + void onClose() { + _worker?.dispose(); + super.onClose(); + } + + void _sync() { + final s = _session; + deviceStatus.value = s == null ? 0 : 2; + connectedDeviceName.value = s?.info.name ?? ''; + connectedDeviceId.value = s?.deviceId ?? ''; + } + void _log(String line) { Logger.i(_tag, line); - logLines.insert(0, '${DateTime.now().toIso8601String().substring(11, 19)} $line'); + logLines.insert( + 0, '${DateTime.now().toIso8601String().substring(11, 19)} $line'); if (logLines.length > 100) logLines.removeRange(100, logLines.length); } @@ -32,12 +59,12 @@ class BesTestController extends GetxController { if (isBusy.value) return; isBusy.value = true; try { - _log('调用 initialize() ...'); - final ok = await _service.initialize(); + _log('调用 ensureReady() ...'); + final ok = await _plugin.ensureReady(); isInitialized.value = ok; - _log('initialize() 返回: $ok'); + _log('ensureReady() 返回: $ok'); } catch (e) { - _log('initialize() 异常: $e'); + _log('ensureReady() 异常: $e'); } finally { isBusy.value = false; } @@ -47,12 +74,14 @@ class BesTestController extends GetxController { if (isBusy.value) return; isBusy.value = true; try { - _log('调用 getBondedDevices() ...'); - final devices = await _service.getBondedDevices(); - bondedDevices.value = devices; - _log('getBondedDevices() 返回 ${devices.length} 个设备'); + _log('调用 bondedDevices() ...'); + final devices = await _plugin.bondedDevices(); + bondedDevices.value = devices + .map((d) => {'address': d.id, 'name': d.name}) + .toList(); + _log('bondedDevices() 返回 ${devices.length} 个设备'); } catch (e) { - _log('getBondedDevices() 异常: $e'); + _log('bondedDevices() 异常: $e'); } finally { isBusy.value = false; } @@ -66,22 +95,43 @@ class BesTestController extends GetxController { return; } _log('连接 $name ($address) ...'); - await _service.savePairedDevice(device); - await _service.connectToDevice(address, name); + deviceStatus.value = 1; + try { + await _plugin.rememberDevice(DiscoveredDevice(id: address, name: name)); + await _plugin.connect(address, + options: DeviceConnectOptions(extra: {'name': name})); + _log('已连接'); + } catch (e) { + _log('连接失败: $e'); + } + _sync(); } Future disconnect() async { _log('调用 disconnect() ...'); - await _service.disconnectDevice(); + await _session?.disconnect(); + _sync(); } + /// 发一帧固件版本查询(AA 06),看回包 Future sendPing() async { try { _log('发送测试帧 [0xAA, 0x06] ...'); - await _service.sendData([0xAA, 0x06]); - _log('sendData() 已调用'); + await _session?.invokeFeature('bes.send', {'bytes': [0xAA, 0x06]}); + _log('已发送'); + } catch (e) { + _log('发送异常: $e'); + } + } + + /// 重扫查询类命令(0x01~0x20),0x5x/0x6x 会切工作模式,插件里已跳过 + Future probe({int from = 0x01, int to = 0x20}) async { + try { + _log('开始探测 0x${from.toRadixString(16)}~0x${to.toRadixString(16)}'); + await _session?.invokeFeature('bes.probe', {'from': from, 'to': to}); + _log('探测结束,看日志里的「恒玄设备命令事件」'); } catch (e) { - _log('sendData() 异常: $e'); + _log('探测异常: $e'); } } } diff --git a/apps/client/lib/modules/call_recording/controllers/call_recording_controller.dart b/apps/client/lib/modules/call_recording/controllers/call_recording_controller.dart index bee9d6bb..4111466c 100644 --- a/apps/client/lib/modules/call_recording/controllers/call_recording_controller.dart +++ b/apps/client/lib/modules/call_recording/controllers/call_recording_controller.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:io'; -import 'dart:math' as math; import 'dart:typed_data'; import 'package:get/get.dart'; @@ -9,20 +8,17 @@ import 'package:just_audio/just_audio.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:record/record.dart'; -import 'package:echomeet_device_sdk/echomeet_device_sdk.dart'; +import 'package:device_plugin_interface/device_plugin_interface.dart'; import '../../../core/utils/logger.dart'; import '../../../core/utils/background_session_notifier.dart'; -import '../../../data/services/ble_manager.dart'; -import '../../../data/services/holder_device_service.dart'; -import '../../../data/services/holder_recording_service.dart'; -import '/data/services/bes_bluetooth_service.dart'; -import '/data/services/bes_recording_service.dart'; -import '/data/services/bes_call_recording_service.dart'; +import '../../../core/utils/device_connection.dart'; +import '../../../data/services/device_call_recording_service.dart'; +import '../../../data/services/device_recording_service.dart'; import '../../../data/services/db/sqflite_api.dart'; import '../../../data/services/meeting/meeting_upload_service.dart'; import '../../../data/services/network/api.dart'; -import '../../meeting/utils/jieli_call_recorder.dart'; +import '../../../devices/device_hub.dart'; /// 一条已保存的通话录音文件 class CallRecordingItem { @@ -53,11 +49,12 @@ class CallRecordingItem { } /// 通话录音 / 现场录音页控制器:开始/停止录制、列出/播放/删除已保存的录音。 -/// 复用会议模块里的 [JieliCallRecorder](设备录音通路 PCM→WAV 写入器), -/// 但不接入"会议"概念(无纪要/任务/上传),是独立于会议模块的轻量录音功能。 /// -/// 通话录音与现场录音底层录制机制相同(均走设备录音通路写 WAV),仅保存 -/// 目录/标题不同,靠路由 arguments 区分: +/// 设备通路的采集/落盘/归档全部由全局服务负责(现场录音 [DeviceRecordingService]、 +/// 通话录音 [DeviceCallRecordingService]),本页只做展示与转发指令; +/// 没连设备时现场录音退回手机麦克风。**不认厂商**。 +/// +/// 通话录音与现场录音靠路由 arguments 区分: /// `Get.toNamed(Routes.recording, arguments: {'title': '通话录音', 'folder': 'call_recordings'})` /// `Get.toNamed(Routes.fieldRecording, arguments: {'title': '现场录音', 'folder': 'field_recordings'})` class CallRecordingController extends GetxController { @@ -75,10 +72,6 @@ class CallRecordingController extends GetxController { static int notificationIdFor(String tag) => tag == 'field_recordings' ? 91011 : 91012; - /// 设备录音通路(杰理 PCM → WAV)。onWavePcm 回调用来驱动波形。 - late final JieliCallRecorder _recorder = - JieliCallRecorder(onWavePcm: _onDevicePcm); - /// 手机麦克风录音通路(没连设备时用) final _micRecorder = AudioRecorder(); @@ -87,19 +80,13 @@ class CallRecordingController extends GetxController { /// 本次录制是否走的手机麦克风,停止时要按同一条通路收尾 bool _recordingWithMic = false; - /// 本次录制是否走蓝讯支架(echomeet SDK)通路 - bool _recordingWithHolder = false; - bool _recordingWithBes = false; + /// 本次录制是否走设备通路(由全局服务采集) + bool _recordingWithDevice = false; - /// 支架 PCM 帧订阅 + WAV 写入句柄 - - /// 监听设备端录音状态:支架上按开始/结束时,本页要跟着起停 - Worker? _holderStateWorker; - Worker? _holderElapsedWorker; - Worker? _holderWaveWorker; - Worker? _besStateWorker; - Worker? _besElapsedWorker; - Worker? _besWaveWorker; + /// 监听设备端录音状态:设备上按开始/结束时,本页要跟着起停 + Worker? _devStateWorker; + Worker? _devElapsedWorker; + Worker? _devWaveWorker; /// 本次录制的目标文件路径(停止后要用它归档) String? _currentPath; @@ -166,93 +153,49 @@ class CallRecordingController extends GetxController { } }); _loadRecordings(); - _bindHolderRecordingState(); - _bindBesRecordingState(); + _bindDeviceRecordingState(); } - /// 设备端按键与本页联动。 + /// 设备端按键与本页联动:现场录音页盯 [DeviceRecordingService], + /// 通话录音页盯 [DeviceCallRecordingService]。 /// - /// 支架上直接开始录音 → 本页自动进入录音态并接收 PCM; - /// 支架上结束录音 → 本页停止、落盘并归档进语音记录助手(走既有上传逻辑)。 - void _bindHolderRecordingState() { - if (!_archiveToMeeting) return; // 只有现场录音页做联动 - if (!Get.isRegistered()) return; - if (!Get.isRegistered()) return; - final rec = HolderRecordingService.to; - - // 页面进来时若设备已经在录,立刻同步为录音态(比如先在支架上按了录音再进页面) - if (rec.isRecording.value) _syncFromHolder(); - - _holderStateWorker = ever(rec.isRecording, (recording) { - if (recording) { - Logger.info('$_tag 设备端开始录音,界面同步进入录音态'); - _recordingWithHolder = true; - isRecording.value = true; - isPaused.value = false; - } else if (_recordingWithHolder) { - Logger.info('$_tag 设备端结束录音,界面同步停止(归档由全局服务完成)'); - _recordingWithHolder = false; - isRecording.value = false; - elapsedMs.value = 0; - elapsedSeconds.value = 0; - waveform.clear(); - level.value = 0; - _loadRecordings(); - } - }); - - // 时长与波形直接镜像全局服务,保证界面数值和实际落盘一致 - _holderElapsedWorker = ever(rec.elapsedMs, (ms) { - if (!_recordingWithHolder) return; - elapsedMs.value = ms; - elapsedSeconds.value = ms ~/ 1000; - }); - _holderWaveWorker = ever>(rec.waveform, (w) { - if (!_recordingWithHolder) return; - waveform.assignAll(w); - level.value = w.isEmpty ? 0 : w.last; - }); - } - - /// 耳机端按键与本页联动(与支架那套同构,只是数据源换成耳机侧服务)。 - /// - /// 现场录音页盯 [BesRecordingService](主麦 AA 59/5A), - /// 通话录音页盯 [BesCallRecordingService](通话双路 AA 51/52)。 - /// 之前这里 `if (!_archiveToMeeting) return` 直接把通话录音页排除在外, - /// 于是耳机按键停止、或通话挂断触发的兜底停止,页面都不会跟着回到未录音态。 - void _bindBesRecordingState() { + /// 设备上直接开始录音 → 本页自动进入录音态;结束 → 本页停止(归档由全局服务完成)。 + void _bindDeviceRecordingState() { + final RxBool isRec; + final RxInt elapsed; + final RxList wave; if (_archiveToMeeting) { - if (!Get.isRegistered()) return; - _bindBesSource(BesRecordingService.to.isRecording, - BesRecordingService.to.elapsedMs, BesRecordingService.to.waveform); + if (!Get.isRegistered()) return; + final r = DeviceRecordingService.to; + isRec = r.isRecording; + elapsed = r.elapsedMs; + wave = r.waveform; } else { - if (!Get.isRegistered()) return; - _bindBesSource( - BesCallRecordingService.to.isRecording, - BesCallRecordingService.to.elapsedMs, - BesCallRecordingService.to.waveform); + if (!Get.isRegistered()) return; + final r = DeviceCallRecordingService.to; + isRec = r.isRecording; + elapsed = r.elapsedMs; + wave = r.waveform; } - } - void _bindBesSource( - RxBool isRec, RxInt elapsed, RxList wave) { + // 页面进来时若设备已经在录,立刻同步为录音态 if (isRec.value) { - _recordingWithBes = true; + _recordingWithDevice = true; isRecording.value = true; elapsedMs.value = elapsed.value; elapsedSeconds.value = elapsed.value ~/ 1000; waveform.assignAll(wave); } - _besStateWorker = ever(isRec, (recording) { + _devStateWorker = ever(isRec, (recording) { if (recording) { - Logger.info('$_tag 耳机端开始录音,界面同步进入录音态'); - _recordingWithBes = true; + Logger.info('$_tag 设备端开始录音,界面同步进入录音态'); + _recordingWithDevice = true; isRecording.value = true; isPaused.value = false; - } else if (_recordingWithBes) { - Logger.info('$_tag 耳机端结束录音,界面同步停止(归档由全局服务完成)'); - _recordingWithBes = false; + } else if (_recordingWithDevice) { + Logger.info('$_tag 设备端结束录音,界面同步停止(归档由全局服务完成)'); + _recordingWithDevice = false; isRecording.value = false; elapsedMs.value = 0; elapsedSeconds.value = 0; @@ -261,51 +204,33 @@ class CallRecordingController extends GetxController { _loadRecordings(); } }); - _besElapsedWorker = ever(elapsed, (ms) { - if (!_recordingWithBes) return; + // 时长与波形直接镜像全局服务,保证界面数值和实际落盘一致 + _devElapsedWorker = ever(elapsed, (ms) { + if (!_recordingWithDevice) return; elapsedMs.value = ms; elapsedSeconds.value = ms ~/ 1000; }); - _besWaveWorker = ever>(wave, (w) { - if (!_recordingWithBes) return; + _devWaveWorker = ever>(wave, (w) { + if (!_recordingWithDevice) return; waveform.assignAll(w); level.value = w.isEmpty ? 0 : w.last; }); } - - void _syncFromHolder() { - final rec = HolderRecordingService.to; - _recordingWithHolder = true; - isRecording.value = true; - elapsedMs.value = rec.elapsedMs.value; - elapsedSeconds.value = rec.elapsedMs.value ~/ 1000; - waveform.assignAll(rec.waveform); - } - @override void onClose() { _elapsedTimer?.cancel(); _micAmpTimer?.cancel(); _sampleTimer?.cancel(); - _holderStateWorker?.dispose(); - _holderElapsedWorker?.dispose(); - _holderWaveWorker?.dispose(); - _besStateWorker?.dispose(); - _besElapsedWorker?.dispose(); - _besWaveWorker?.dispose(); + _devStateWorker?.dispose(); + _devElapsedWorker?.dispose(); + _devWaveWorker?.dispose(); _playerStateSub?.cancel(); _player.dispose(); - // 注意:支架/恒玄通路的录音分别由全局 HolderRecordingService / - // BesRecordingService(BesCallRecordingService) 负责,页面关闭不能停它们, - // 否则用户退出页面就把设备端的录音中断了。这里只收尾本页自己接管的通路 - // (手机麦克风 / 杰理设备录音,这两条没有独立于本页的全局服务)。 - if (isRecording.value && !_recordingWithHolder && !_recordingWithBes) { - if (_recordingWithMic) { - _micRecorder.stop(); - } else { - _recorder.stop(save: true); - } + // 注意:设备通路的录音由全局服务负责,页面关闭不能停它们, + // 否则用户退出页面就把设备端的录音中断了。这里只收尾手机麦克风。 + if (isRecording.value && !_recordingWithDevice && _recordingWithMic) { + _micRecorder.stop(); } _micRecorder.dispose(); super.onClose(); @@ -391,43 +316,13 @@ class CallRecordingController extends GetxController { } } - /// 蓝讯支架是否已连接(优先级最高的录音通路) - bool get _holderAvailable { - if (!Get.isRegistered()) return false; - return Get.find().isConnected; - } - - /// 恒玄耳机是否已连接(走 SPP 主麦录音,与支架那条互不影响) - bool get _besAvailable { - if (!Get.isRegistered()) return false; - return BesBluetoothService.to.isConnected; - } - - /// 杰理耳机是否已连接 - bool get _deviceAvailable { - if (!Get.isRegistered()) return false; - return Get.find().isConnected; - } + /// 有没有一台能走本页这条通路的设备:现场录音看主麦录音能力,通话录音看双路抓音 + bool get _deviceAvailable => _archiveToMeeting + ? DeviceConnection.has(DeviceCapability.micRecording) + : DeviceConnection.has(DeviceCapability.callAudioTap); // ==================== 波形 / 电平 ==================== - /// 设备通路:从写入的 stereo PCM 算 RMS 电平 - void _onDevicePcm(Uint8List pcm) { - if (pcm.lengthInBytes < 2) return; - final samples = pcm.buffer.asInt16List( - pcm.offsetInBytes, - pcm.lengthInBytes ~/ 2, - ); - var sumSq = 0.0; - for (final s in samples) { - final v = s / 32768.0; - sumSq += v * v; - } - final rms = math.sqrt(sumSq / samples.length); - // RMS 本身偏小,开根放大一下让波形更有跳动感 - _pushLevel(math.sqrt(rms).clamp(0.0, 1.0)); - } - /// 手机麦通路:轮询 record 包的振幅(dBFS,约 -60~0) Future _pollMicAmplitude() async { try { @@ -489,33 +384,23 @@ class CallRecordingController extends GetxController { final ts = DateFormat('yyyyMMdd_HHmmss').format(DateTime.now()); final path = '${dir.path}/call_$ts.wav'; - // 通路优先级:蓝讯支架 > 恒玄耳机 > 杰理耳机 > 手机麦克风 - final bool useHolder = _holderAvailable; - final bool useBes = !useHolder && _besAvailable; - final bool useMic = !useHolder && !useBes && !_deviceAvailable; + // 通路:有能用的设备就走设备(由全局服务采集,页面只展示),否则手机麦克风 + final bool useDevice = _deviceAvailable; + final bool useMic = !useDevice; final bool ok; - if (useHolder) { - // 支架通路统一由全局服务采集,页面只做展示 - ok = deviceInitiated - ? true - : await HolderRecordingService.to.start(sendCommand: true); - } else if (useBes) { - // 耳机通路同理,由全局服务采集,页面只展示。 - // 通话录音走双声道通话通路(AA 51/52),现场录音走主麦(AA 59/5A)。 + if (useDevice) { + // 通话录音走双路通话通路,现场录音走主麦 ok = deviceInitiated ? true : _archiveToMeeting - ? await BesRecordingService.to.start(sendCommand: true) - : await BesCallRecordingService.to.start(sendCommand: true); - } else if (useMic) { - ok = await _startMicRecording(path); + ? await DeviceRecordingService.to.start(sendCommand: true) + : await DeviceCallRecordingService.to.start(sendCommand: true); } else { - ok = await _recorder.start(path); + ok = await _startMicRecording(path); } if (!ok) { - // 手机麦/支架/恒玄分支自己弹过提示了,这里只补杰理分支的 - if (!useMic && !useHolder && !useBes) { + if (useDevice) { Get.snackbar('error'.tr, '录音启动失败,请检查设备连接', snackPosition: SnackPosition.TOP); } @@ -523,8 +408,7 @@ class CallRecordingController extends GetxController { } _recordingWithMic = useMic; - _recordingWithHolder = useHolder; - _recordingWithBes = useBes; + _recordingWithDevice = useDevice; _currentPath = path; isRecording.value = true; isPaused.value = false; @@ -549,7 +433,7 @@ class CallRecordingController extends GetxController { (_) => _sampleTick(), ); - // 手机麦没有 PCM 回调,只能轮询振幅;设备通路靠 onWavePcm 推 + // 手机麦没有 PCM 回调,只能轮询振幅;设备通路的波形镜像自全局服务 _micAmpTimer?.cancel(); if (useMic) { _micAmpTimer = Timer.periodic( @@ -563,22 +447,18 @@ class CallRecordingController extends GetxController { Future togglePause() async { if (!isRecording.value) return; if (isPaused.value) { - if (_recordingWithHolder) { - await Get.find().toggleRecording(); + if (_recordingWithDevice) { + await _toggleDevicePause(); } else if (_recordingWithMic) { await _micRecorder.resume(); - } else { - _recorder.resume(); } _stopwatch.start(); isPaused.value = false; } else { - if (_recordingWithHolder) { - await Get.find().toggleRecording(); + if (_recordingWithDevice) { + await _toggleDevicePause(); } else if (_recordingWithMic) { await _micRecorder.pause(); - } else { - _recorder.pause(); } _stopwatch.stop(); isPaused.value = true; @@ -586,6 +466,19 @@ class CallRecordingController extends GetxController { } } + /// 设备端暂停/继续(支架支持,耳机不支持——不支持就当没按) + Future _toggleDevicePause() async { + final s = DeviceHub.to.sessionWith(DeviceCapability.micRecording); + if (s == null) return; + try { + await s.invokeFeature('record.toggle'); + } on DeviceException catch (e) { + Logger.info('$_tag 设备不支持暂停: ${e.code}'); + } catch (e) { + Logger.error('$_tag 设备暂停失败: $e'); + } + } + /// 手机麦克风录制。采样参数与设备通路对齐(16kHz/16bit),只是单声道, /// 时长换算靠读 WAV 头的字节率,不受声道数影响。 Future _startMicRecording(String path) async { @@ -627,40 +520,22 @@ class CallRecordingController extends GetxController { bool ok; // 按开始时选定的通路收尾,中途设备断连也不会走错分支。 - // - // 恒玄这支以前**嵌在支架分支里面**,而开始录音时 - // `_recordingWithHolder=useHolder` 对恒玄通路恒为 false, - // 于是点停止时根本进不来,最后掉到杰理 `_recorder.stop()` 分支—— - // 结果就是:设备没收到 AA 52 还在上行,文件也没落盘归档, - // 只能等挂断电话时靠 BesCallRecordingService 的兜底才保存。 - // 这里提成与支架平级的独立分支。 - if (_recordingWithBes) { + if (_recordingWithDevice) { + // 设备通路的落盘与归档全部由全局服务负责,页面只负责把停止指令转过去; + // 设备端自己停的(deviceInitiated)不再回发指令,避免和设备状态打架。 try { - // 设备端自己停的(0xDA)不再回发指令,避免和设备状态打架 final bool sendCmd = !deviceInitiated; if (_archiveToMeeting) { - await BesRecordingService.to.stop(sendCommand: sendCmd); + await DeviceRecordingService.to.stop(sendCommand: sendCmd); } else { - await BesCallRecordingService.to.stop(sendCommand: sendCmd); + await DeviceCallRecordingService.to.stop(sendCommand: sendCmd); } ok = true; } catch (e) { - Logger.error('$_tag 耳机停止失败: $e'); + Logger.error('$_tag 设备停止失败: $e'); ok = false; } - } else if (_recordingWithHolder) { - // 支架通路的落盘与归档全部由全局 HolderRecordingService 负责, - // 页面只负责在用户点停止时把指令转过去;设备端自己停的则什么都不用做。 - try { - if (!deviceInitiated) { - await HolderRecordingService.to.stop(sendCommand: true); - } - ok = true; - } catch (e) { - Logger.error('$_tag 支架停止失败: $e'); - ok = false; - } - } else if (_recordingWithMic) { + } else { try { final p = await _micRecorder.stop(); ok = p != null; @@ -668,12 +543,9 @@ class CallRecordingController extends GetxController { Logger.error('$_tag 手机麦克风停止失败: $e'); ok = false; } - } else { - ok = await _recorder.stop(save: true); } _recordingWithMic = false; - _recordingWithHolder = false; - _recordingWithBes = false; + _recordingWithDevice = false; _currentPath = null; isRecording.value = false; isPaused.value = false; diff --git a/apps/client/lib/modules/call_recording/module.dart b/apps/client/lib/modules/call_recording/module.dart new file mode 100644 index 00000000..ac6e630b --- /dev/null +++ b/apps/client/lib/modules/call_recording/module.dart @@ -0,0 +1,49 @@ +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../routes/app_routes.dart'; +import '../home/controllers/home_controller.dart'; +import '../module_descriptor.dart'; +import 'bindings/call_recording_binding.dart'; +import 'views/call_recording_view.dart'; + +final List _pages = [ + GetPage( + name: Routes.recording, + page: () => const CallRecordingView(), + binding: CallRecordingBinding(), + transition: Transition.rightToLeft, + transitionDuration: const Duration(milliseconds: 250), + ), + GetPage( + name: Routes.fieldRecording, + page: () => const CallRecordingView(), + binding: CallRecordingBinding(), + transition: Transition.rightToLeft, + transitionDuration: const Duration(milliseconds: 250), + ), +]; + +/// 通话录音(需设备抓通话双路)与现场录音(有设备走设备,没设备用手机麦) +final List callRecordingModules = [ + AgentModuleDescriptor( + id: 'callRecording', + title: 'agentCallRecording', + subtitle: 'agentCallRecordingDesc', + icon: Icons.fiber_manual_record, + gradient: const [Color(0xFFEF5350), Color(0xFFE53935)], + requiredCapabilities: const {DeviceCapability.callAudioTap}, + onLaunch: () => HomeController.to.openCallRecording(), + pages: _pages, + ), + AgentModuleDescriptor( + id: 'fieldRecording', + title: 'agentFieldRecording', + subtitle: 'agentFieldRecordingDesc', + icon: Icons.mic, + gradient: const [Color(0xFF26C6DA), Color(0xFF00838F)], + onLaunch: () => HomeController.to.openFieldRecording(), + pages: _pages, + ), +]; diff --git a/apps/client/lib/modules/devices/views/bes_scan_view.dart b/apps/client/lib/modules/devices/views/bes_scan_view.dart index 821ce61e..23e7d3ac 100644 --- a/apps/client/lib/modules/devices/views/bes_scan_view.dart +++ b/apps/client/lib/modules/devices/views/bes_scan_view.dart @@ -1,29 +1,25 @@ import 'dart:io'; +import 'package:device_plugin_interface/device_plugin_interface.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../../../core/theme/app_palette.dart'; import '../../../data/services/background_launch_consent.dart'; -import '../../../data/services/bes_bluetooth_service.dart'; +import '../../../devices/device_hub.dart'; +import '../../../devices/device_vendors.dart'; import '../../../routes/app_routes.dart'; import '../../main_tab/controllers/main_tab_controller.dart'; -/// 恒玄(BES)方案耳机的连接页。 +/// AI 耳机(恒玄 Echo-one)的连接页——走 [DeviceHub] 里的耳机插件。 /// -/// 与蓝讯支架([HolderScanView],BLE 广播扫描)是**完全独立的一条通路**, -/// 而且两端的底层实现也不一样(native 插件已按平台各写一套): -/// - Android:经典蓝牙 RFCOMM/SPP,`getBondedDevices` 给的是系统**已配对**列表; -/// - iOS:CoreBluetooth 走厂商私有 service 的 GATT 桥接(BR/EDR 承载), -/// `getBondedDevices` 底层是 `retrieveConnectedPeripherals`, -/// 给的是系统里**当前已连接**且带该 service 的耳机,address 是 CBPeripheral 的 -/// UUID 而不是 MAC。 +/// 两端的用户前提不同(插件按平台各写一套): +/// - Android:经典蓝牙 RFCOMM/SPP,`bondedDevices` 给的是系统**已配对**列表; +/// - iOS:CoreBluetooth GATT 桥接,给的是系统里**当前已连接**且带该 service 的耳机, +/// id 是 CBPeripheral 的 UUID 而不是 MAC。 /// -/// 所以两端的用户前提不同:Android 只要配过对就能连;iOS 必须先在系统蓝牙里 -/// 把耳机连上(A2DP/HFP),App 才看得到它。页面文案按平台分开。 -/// -/// 三条链路各自持有自己的 service、各自的连接态和持久化,互不影响。 +/// 所以 Android 只要配过对就能连;iOS 必须先在系统蓝牙里把耳机连上。页面文案按平台分开。 class BesScanView extends StatefulWidget { const BesScanView({super.key}); @@ -32,64 +28,51 @@ class BesScanView extends StatefulWidget { } class _BesScanViewState extends State { - /// 展示用的设备名(提示文案、连接成功 snackbar 的兜底)。当前固件的广播名。 - /// - /// ⚠️ 大小写按设备端实际广播的写;**匹配**不要直接拿它比,走 - /// [_acceptedNames]([_findTargets] 里统一转大写)——上一版常量恰好是全大写的 - /// `DEEPVOICE`,跟大写后的设备名比才碰巧成立,改成混合大小写就会全部匹配不到。 + /// 展示用的设备名。当前固件的广播名。 static const String _targetName = 'Echo-one'; - /// 认哪些广播名。恒玄这条链路只对接自家耳机,其它已配对的经典蓝牙设备 - /// (车机、音箱、别家耳机)都不该出现在这个页面里,直接按名字写死过滤。 - /// - /// 之所以是列表而不是单个值:设备端 2026-08-31 把广播名从 `DEEPVOICE` 改成 - /// `Echo-one`,但 Android 的 `getBondedDevices` 给的是**系统缓存的配对名**, - /// 改名前配过对的手机在重新配对之前仍然报旧名,只认新名会让这些机器扫不到。 - /// 旧名可在存量设备全部换代后删除。 + /// 认哪些广播名:设备端 2026-08-31 把广播名从 `DEEPVOICE` 改成 `Echo-one`, + /// 但 Android 的配对列表给的是系统缓存的配对名,改名前配过对的手机在重新配对 + /// 之前仍然报旧名。旧名可在存量设备全部换代后删除。 static const List _acceptedNames = ['Echo-one', 'DEEPVOICE']; - late final BesBluetoothService _service; - final RxList> _devices = >[].obs; + DevicePlugin get _plugin => DeviceHub.to.plugin(DeviceVendors.bes)!; + final RxList _devices = [].obs; final RxBool _loading = true.obs; bool _connecting = false; + Worker? _sessionsWorker; + bool _finished = false; @override void initState() { super.initState(); - _service = Get.isRegistered() - ? Get.find() - : Get.put(BesBluetoothService()); // 主动连接失败后耳机才连上手机的场景:原生靠 ACL 广播自动补 RFCOMM, - // 状态一旦变成「已连接」,这页也要把绑定存下来并跳回设备页。 - // - // ⚠️ `_connecting` 期间不能开火:_connect 正在按候选列表逐个试, - // 第一个候选一连上就 _finish() 会把用户点的那台挤掉(存盘存成先连上的 - // 那一台并直接跳走)。候选循环自己会收尾—— - // · 回连发生在循环期间 → _waitConnected 看到 2 就 break,由 _connect 走 _finish; - // · 回连发生在循环之后 → finally 已把 _connecting 置回 false,这里照常开火。 - // 两条路都有人收尾,不存在空档。 - _statusWorker = ever(_service.deviceStatus, (v) { - if (v == 2 && mounted && !_finished && !_connecting) _finish(); + // 一旦上线,这页也要把绑定存下来并跳回设备页。 + // `_connecting` 期间不开火:候选循环自己会收尾。 + _sessionsWorker = ever>(DeviceHub.to.sessions, (_) { + if (_liveSession != null && mounted && !_finished && !_connecting) { + _finish(); + } }); WidgetsBinding.instance.addPostFrameCallback((_) => _load()); } - Worker? _statusWorker; - bool _finished = false; + DeviceSession? get _liveSession => DeviceHub.to.sessionOf(DeviceVendors.bes); @override void dispose() { - _statusWorker?.dispose(); + _sessionsWorker?.dispose(); super.dispose(); } Future _finish() async { _finished = true; - final id = _service.connectedDeviceId.value; - final name = _service.connectedDeviceName.value; - if (id.isNotEmpty) { - await _service.savePairedDevice({'address': id, 'name': name}); + final s = _liveSession; + if (s != null && s.deviceId.isNotEmpty) { + await _plugin.rememberDevice( + DiscoveredDevice(id: s.deviceId, name: s.info.name)); } + final name = s?.info.name ?? ''; Get.snackbar('连接成功', '${name.isEmpty ? _targetName : name} 已连接', snackPosition: SnackPosition.TOP, duration: const Duration(seconds: 2)); @@ -104,17 +87,14 @@ class _BesScanViewState extends State { Future _load() async { _loading.value = true; try { - await _service.initialize(); - // ⚠️ 进页面时已经连上(冷启动自动回连 / 上个页面连过)**不再直接跳回主页**。 - // 这页要展示已配对的耳机并把「当前连着的那台」高亮出来,直接跳走的话 - // 用户根本看不到这个区分。想回主页点那一行即可(走 _finish)。 + await _plugin.ensureReady(); + // 进页面时已经连上**不再直接跳回主页**:这页要展示已配对的耳机并把 + // 「当前连着的那台」高亮出来。想回主页点那一行即可(走 _finish)。 final target = await _findTargets(); _devices.assignAll(target); - // 只有一台目标耳机时不用再让用户点一次,直接连。 - // 但用户拒绝过后台自动连接就不再自动发起——否则每次进页面都要被拦一次, - // 变成「重复启动 + 重复弹窗」。这时列表照常展示,等用户自己点。 + // 只有一台目标耳机时直接连;但用户拒绝过后台自动连接就不再自动发起。 if (target.length == 1 && - _service.deviceStatus.value != 2 && + _liveSession == null && !BackgroundLaunchConsent.declined) { await _connect(target.first, userInitiated: false); } @@ -126,18 +106,14 @@ class _BesScanViewState extends State { } } - /// 取目标耳机列表。 - /// - /// iOS 上 `initialize()` 只是把 CBCentralManager 建出来,state 变成 .poweredOn - /// 要等系统回调;在那之前 `getBondedDevices` 底层的 - /// `retrieveConnectedPeripherals` 会直接返回空。所以 iOS 要轮询几次再判定 - /// 「没找到」,否则刚进页面必定误报。Android 是同步查系统配对列表,一次就够。 - Future>> _findTargets() async { + /// 取目标耳机列表。iOS 上 CBCentralManager 变成 .poweredOn 要等系统回调, + /// 在那之前列表是空的,所以要轮询几次再判定「没找到」。 + Future> _findTargets() async { final int attempts = Platform.isIOS ? 10 : 1; for (var i = 0; i < attempts; i++) { - final list = await _service.getBondedDevices(); + final list = await _plugin.bondedDevices(); final target = list.where((d) { - final n = (d['name'] as String? ?? '').toUpperCase(); + final n = d.name.toUpperCase(); return _acceptedNames.any((t) => n.contains(t.toUpperCase())); }).toList(); if (target.isNotEmpty || i == attempts - 1) return target; @@ -147,15 +123,10 @@ class _BesScanViewState extends State { return const []; } - Future _connect(Map d, - {bool userInitiated = true}) async { + Future _connect(DiscoveredDevice d, {bool userInitiated = true}) async { if (_connecting) return; - final id = (d['address'] ?? '') as String; - final name = (d['name'] ?? '') as String; - if (id.isEmpty) return; - // 绑定后耳机开机会自动回连(Android 靠 ACL 广播、iOS 靠 .peerConnected), - // 属于后台自动连接,先取得用户明示同意。 - // 只有用户亲手点连接才允许弹窗;自动路径拿不到授权就安静地不连。 + if (d.id.isEmpty) return; + // 绑定后耳机开机会自动回连,属于后台自动连接,先取得用户明示同意。 if (!await BackgroundLaunchConsent.ensure(userInitiated: userInitiated)) { if (userInitiated) { Get.snackbar( @@ -170,34 +141,30 @@ class _BesScanViewState extends State { setState(() => _connecting = true); try { // 候选 = 用户点的那台(永远第一)+ 列表里的同名设备。 - // - // 身份由连上之后的 MAC 校验来定(见 BesDeviceAuth 与 _listen 的回填), - // 不由拨哪个地址来定。所以连接阶段只要「拨通一条链路」即可, - // 不需要在地址层面追求精确——同名的另一行既可能是同一只耳机的另一个 - // BR/EDR 地址(Android TWS 双地址:实测配对列表是 …C1:C4,SPP 走 …BE:F8), + // 身份由连上之后的 MAC 校验来定,连接阶段只要「拨通一条链路」即可—— + // 同名的另一行既可能是同一只耳机的另一个 BR/EDR 地址(Android TWS 双地址), // 也可能是另一台同款耳机,两种都值得试。 - // - // ⚠️ **不要把 currentConnectedDevice() / lastDeviceAddress 加回来。** - // 插件里没有任何扫描/发现路径,地址的唯一来源是 adapter.bondedDevices; - // 而这两个值都只是把 App 自己拨过的地址回吐(lastDeviceId 只在 connect() - // 里赋值,lastDeviceAddress 来自 savePairedDevice 存的 connectedDeviceId)。 - // 它们永远产生不了一个「新地址」,唯一的实际效果是把**上一台耳机**塞进 - // 候选并排在用户的选择前面——换耳机时就会连上旧的那台,或者在旧耳机 - // 不在身边时白等一轮超时。 - final tappedName = name.trim().toUpperCase(); - final candidates = [id]; + final tappedName = d.name.trim().toUpperCase(); + final candidates = [d.id]; for (final row in _devices) { - final a = (row['address'] as String? ?? ''); - final n = (row['name'] as String? ?? '').trim().toUpperCase(); - if (a.isEmpty || n != tappedName) continue; - if (candidates.any((c) => c.toUpperCase() == a.toUpperCase())) continue; - candidates.add(a); + final n = row.name.trim().toUpperCase(); + if (row.id.isEmpty || n != tappedName) continue; + if (candidates.any((c) => c.toUpperCase() == row.id.toUpperCase())) { + continue; + } + candidates.add(row.id); } bool ok = false; for (final addr in candidates) { - await _service.connectToDevice(addr, name); - ok = await _waitConnected(); + try { + await _plugin.connect(addr, + options: DeviceConnectOptions(extra: {'name': d.name})); + ok = true; + } on DeviceException catch (e) { + debugPrint('bes connect $addr failed: ${e.code}'); + ok = false; + } if (ok || !mounted) break; } if (!mounted) return; @@ -219,28 +186,6 @@ class _BesScanViewState extends State { } } - /// 等状态流推到「已连接」,超时返回当前状态。 - /// - /// 进过「连接中」又掉回 0 就提前判失败:原生 `connectBlocking` 失败时会 - /// `publishBluetoothStatus(0)`,不必每个候选都干等满超时——遍历同名设备的 - /// 总耗时会从「N × timeout」降到接近真实失败时间。 - /// - /// ⚠️ 仍要保留超时兜底:原生若把这次 connect 丢弃了(见 BluetoothManager.kt - /// 的 isConnecting 门禁),状态会停在 connectToDevice 自己写的 1,等不到 0。 - Future _waitConnected( - {Duration timeout = const Duration(seconds: 8)}) async { - final end = DateTime.now().add(timeout); - bool sawConnecting = false; - while (DateTime.now().isBefore(end)) { - final s = _service.deviceStatus.value; - if (s == 2) return true; - if (s == 1) sawConnecting = true; - if (sawConnecting && s == 0) return false; - await Future.delayed(const Duration(milliseconds: 300)); - } - return _service.deviceStatus.value == 2; - } - @override Widget build(BuildContext context) { final bool isDark = Theme.of(context).brightness == Brightness.dark; @@ -259,8 +204,8 @@ class _BesScanViewState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - CircularProgressIndicator(), - SizedBox(height: 16), + const CircularProgressIndicator(), + const SizedBox(height: 16), Text('besConnecting'.tr), ], ), @@ -270,12 +215,10 @@ class _BesScanViewState extends State { return const Center(child: CircularProgressIndicator()); } if (_devices.isEmpty) return _empty(isDark); - // ⚠️ 连接态必须在**这里**读出来再传下去:ListView 的 itemBuilder 是 - // 延迟调用的,在 _tile 里读 Rx 不会被这个 Obx 收集到, - // 耳机连上/断开时列表不会重绘。 - final live = _service.deviceStatus.value == 2; - final connId = _service.connectedDeviceId.value; - final connName = _service.connectedDeviceName.value; + // 连接态必须在**这里**读出来再传下去:ListView 的 itemBuilder 是 + // 延迟调用的,在 _tile 里读 Rx 不会被这个 Obx 收集到。 + DeviceHub.to.sessions.length; + final live = _liveSession; return ListView.separated( padding: EdgeInsets.fromLTRB(16.w, 16.h, 16.w, 24.h), itemCount: _devices.length, @@ -283,8 +226,7 @@ class _BesScanViewState extends State { itemBuilder: (context, i) => _tile( _devices[i], isDark, - connected: - live && _isLiveDevice(_devices[i], connId, connName), + connected: live != null && _isLiveDevice(_devices[i], live), ), ); }), @@ -307,7 +249,6 @@ class _BesScanViewState extends State { SizedBox(height: 6.h), Text( Platform.isIOS - // iOS 只能看到「系统里已经连上的」耳机,配过对但没连上是看不到的 ? '请先在系统「设置 → 蓝牙」里连接 $_targetName(显示"已连接"),再回到这里' : '$_targetName 走经典蓝牙,请先在系统「设置 → 蓝牙」里完成配对,再回到这里连接', textAlign: TextAlign.center, @@ -320,35 +261,24 @@ class _BesScanViewState extends State { ); } - /// 这一行是不是当前正连着的那台。 - /// - /// ⚠️ 不能只比地址:Android 上耳机是 TWS 双地址,系统配对列表给的地址不一定 - /// 是真正跑 SPP 的那个(实测配对列表是 …C1:C4,SPP 走 …BE:F8)。只比地址会让 - /// 明明连着的那台显示成「未连接」。地址对不上时退回比设备名——本项目一次只 - /// 连一台耳机,重名的风险可以忽略。 - bool _isLiveDevice( - Map d, String connId, String connName) { - final addr = (d['address'] as String? ?? '').toUpperCase(); - if (addr.isNotEmpty && addr == connId.toUpperCase()) return true; - final n = (d['name'] as String? ?? '').trim().toUpperCase(); - final cn = connName.trim().toUpperCase(); + /// 这一行是不是当前正连着的那台。不能只比地址:Android 上耳机是 TWS 双地址, + /// 系统配对列表给的地址不一定是真正跑 SPP 的那个。地址对不上时退回比设备名。 + bool _isLiveDevice(DiscoveredDevice d, DeviceSession live) { + final addr = d.id.toUpperCase(); + final localId = (live.info.metadata['localId'] as String?) ?? live.deviceId; + if (addr.isNotEmpty && addr == localId.toUpperCase()) return true; + final n = d.name.trim().toUpperCase(); + final cn = live.info.name.trim().toUpperCase(); return n.isNotEmpty && n == cn; } - /// 一行设备。[connected] 决定这一行是高亮态还是置灰态。 - /// - /// 置灰的是「配过对但此刻没连上」的存量设备——它们仍然可点(点了就去连), - /// 只是视觉权重压下去,让用户一眼看出哪台是活的。 - Widget _tile(Map d, bool isDark, {bool connected = false}) { - final name = (d['name'] ?? 'bleUnknownDevice'.tr) as String; - final addr = (d['address'] ?? '') as String; - + Widget _tile(DiscoveredDevice d, bool isDark, {bool connected = false}) { + final name = d.name.isEmpty ? 'bleUnknownDevice'.tr : d.name; const Color accent = AppPalette.accent; final Color idle = AppPalette.textHint(isDark); return GestureDetector( behavior: HitTestBehavior.opaque, - // 已经连着的那台点了就是「用这台」——存盘并回主页,跟连接成功后同一条路径 onTap: () => connected ? _finish() : _connect(d), child: Container( padding: EdgeInsets.all(14.w), @@ -380,8 +310,7 @@ class _BesScanViewState extends State { ? AppPalette.textPrimary(isDark) : AppPalette.textSecondary(isDark))), SizedBox(height: 2.h), - Text(addr, - style: TextStyle(fontSize: 11.sp, color: idle)), + Text(d.id, style: TextStyle(fontSize: 11.sp, color: idle)), ], ), ), diff --git a/apps/client/lib/modules/devices/views/device_category_view.dart b/apps/client/lib/modules/devices/views/device_category_view.dart index eab25e28..3f92b299 100644 --- a/apps/client/lib/modules/devices/views/device_category_view.dart +++ b/apps/client/lib/modules/devices/views/device_category_view.dart @@ -2,14 +2,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import '../../../core/theme/app_palette.dart'; +import '../../../core/utils/toast_throttle.dart'; import '../../../data/models/device_category.dart'; import '../../../routes/app_routes.dart'; -import '../../../core/theme/app_palette.dart'; /// 「添加设备」第一步:选择要绑定的产品品类。 /// /// 以产品图为主的两列网格——每格一张实拍图 + 一行品类名,不放描述文字。 -/// 选完带着 categoryId 进扫描页,只扫该品类产品的 scanuuid。 +/// 选完带着 categoryId 进扫描页,用来筛扫描结果的展示。 class DeviceCategoryView extends StatelessWidget { const DeviceCategoryView({Key? key}) : super(key: key); @@ -53,16 +54,42 @@ class DeviceCategoryView extends StatelessWidget { ); } + /// 蓝牙链路尚未接入的品类。点它们只提示,不进任何扫描页。 + /// + /// 目前是空的——耳机、支架、车载香薰三条链路都已接上。 + /// 以后加新品类时,链路没做完就先放进来,别让用户点进一个扫不出东西的页面。 + static const Set _scanNotReady = {}; + void _openCategory(DeviceCategory category) { + if (_scanNotReady.contains(category.id)) { + ToastThrottle.show( + 'device.scan_not_ready.${category.id}', + title: category.title.tr, + message: 'featureInDev'.tr, + window: ToastThrottle.gateWindow, + ); + return; + } switch (category.id) { - case DeviceCategories.phoneHolder: - Get.toNamed(Routes.holderScan); - break; case DeviceCategories.earphone: Get.toNamed(Routes.besScan); break; + case DeviceCategories.carAroma: + // Smartcar 车载香薰,走 lib/devices/smartcar 那条 BLE 链路(C2 私有协议)。 + Get.toNamed(Routes.smartcarScan); + break; + case DeviceCategories.phoneHolder: + // EaiRec 录音支架,走 recorder_holder 那条 BLE 链路。 + Get.toNamed(Routes.holderScan); + break; default: - Get.toNamed(Routes.devices, arguments: {'categoryId': category.id}); + // 还没接蓝牙链路的品类,与 _scanNotReady 同一处理 + ToastThrottle.show( + 'device.scan_not_ready.${category.id}', + title: category.title.tr, + message: 'featureInDev'.tr, + window: ToastThrottle.gateWindow, + ); } } @@ -73,8 +100,8 @@ class DeviceCategoryView extends StatelessWidget { return GestureDetector( behavior: HitTestBehavior.opaque, - // 每个品类走各自独立的蓝牙链路: - // 手机支架 = 蓝讯 BLE(echomeet SDK)、耳机 = 恒玄经典蓝牙、其余 = 杰理 BLE + // 每个品类走各自的连接页(背后是 DeviceHub 里对应的厂商插件)。 + // Smartcar 的链路还没接,见 [_scanNotReady]。 onTap: () => _openCategory(category), child: Container( decoration: BoxDecoration( diff --git a/apps/client/lib/modules/devices/views/holder_scan_view.dart b/apps/client/lib/modules/devices/views/holder_scan_view.dart index e01d291d..b9ece800 100644 --- a/apps/client/lib/modules/devices/views/holder_scan_view.dart +++ b/apps/client/lib/modules/devices/views/holder_scan_view.dart @@ -1,18 +1,18 @@ -import 'package:echomeet_device_sdk/echomeet_device_sdk.dart'; +import 'dart:async'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../../../core/theme/app_palette.dart'; import '../../../data/services/background_launch_consent.dart'; -import '../../../data/services/holder_device_service.dart'; +import '../../../devices/device_hub.dart'; +import '../../../devices/device_vendors.dart'; import '../../../routes/app_routes.dart'; import '../../main_tab/controllers/main_tab_controller.dart'; -/// 蓝讯方案设备(AI手机支架)的扫描 / 连接页。 -/// -/// 走的是从 echomeet 拉过来的 [EchoMeetDeviceSdk],与杰理耳机的扫描页 -/// (DevicesView)是两条独立链路,互不干扰。 +/// EaiRec 录音支架(AI手机支架)的扫描 / 连接页——走 [DeviceHub] 里的支架插件。 class HolderScanView extends StatefulWidget { const HolderScanView({super.key}); @@ -21,27 +21,60 @@ class HolderScanView extends StatefulWidget { } class _HolderScanViewState extends State { - late final HolderDeviceService _service; + DevicePlugin get _plugin => DeviceHub.to.plugin(DeviceVendors.holder)!; + final RxList _scanned = [].obs; + final RxBool _isScanning = false.obs; + StreamSubscription? _sub; + bool _connecting = false; @override void initState() { super.initState(); - _service = Get.isRegistered() - ? Get.find() - : Get.put(HolderDeviceService()); + _sub = _plugin.eventStream.listen((e) { + switch (e.type) { + case DevicePluginEventType.scanStarted: + _isScanning.value = true; + break; + case DevicePluginEventType.scanStopped: + _isScanning.value = false; + break; + case DevicePluginEventType.deviceDiscovered: + final d = e.discovered; + if (d == null || d.id.isEmpty) break; + // 按地址去重累积:原生是「每扫到一个就单独上报一次」 + final i = _scanned.indexWhere((x) => x.id == d.id); + if (i >= 0) { + _scanned[i] = d; + } else { + _scanned.add(d); + } + break; + default: + break; + } + }); // 进页面自动开扫 - WidgetsBinding.instance.addPostFrameCallback((_) => _service.startScan()); + WidgetsBinding.instance.addPostFrameCallback((_) => _startScan()); + } + + Future _startScan() async { + _scanned.clear(); + if (!await _plugin.ensureReady()) { + Get.snackbar('tip'.tr, 'holderPairHint'.tr, + snackPosition: SnackPosition.TOP); + return; + } + await _plugin.startScan(); } @override void dispose() { - _service.stopScan(); + _sub?.cancel(); + _plugin.stopScan(); super.dispose(); } - bool _connecting = false; - - Future _connect(EchoMeetScannedDevice d) async { + Future _connect(DiscoveredDevice d) async { if (_connecting) return; // Android 上 SDK 的 connect() 本身就是向系统注册后台扫连(设备靠近就唤醒 // 本应用),属于自启动行为,必须先向用户明示并取得同意。 @@ -55,11 +88,15 @@ class _HolderScanViewState extends State { return; } setState(() => _connecting = true); - // 用户主动点了连接:允许再申请一次系统蓝牙权限 - _service.resetPermissionDenied(); - // connect() 只是注册后台扫连,真正连上要等 connectionState - final registered = await _service.connect(d); - final ok = registered && await _service.waitConnected(); + bool ok = false; + try { + await _plugin.connect(d.id); + ok = true; + } on DeviceException catch (e) { + debugPrint('holder connect failed: ${e.code} ${e.message}'); + } catch (e) { + debugPrint('holder connect failed: $e'); + } if (!mounted) return; setState(() => _connecting = false); if (ok) { @@ -67,7 +104,6 @@ class _HolderScanViewState extends State { snackPosition: SnackPosition.TOP, duration: const Duration(seconds: 2)); Get.offAllNamed(Routes.home); - // 回到主框架后切到「设备」页,展示刚连上的设备 WidgetsBinding.instance.addPostFrameCallback((_) { if (Get.isRegistered()) { MainTabController.to.changeTab(MainTabController.tabDevice); @@ -89,7 +125,7 @@ class _HolderScanViewState extends State { elevation: 0, title: Text('holderAddTitle'.tr), actions: [ - Obx(() => _service.isScanning.value + Obx(() => _isScanning.value ? Padding( padding: EdgeInsets.only(right: 16.w), child: Center( @@ -102,7 +138,7 @@ class _HolderScanViewState extends State { ) : IconButton( icon: const Icon(Icons.refresh), - onPressed: _service.startScan, + onPressed: _startScan, )), ], ), @@ -111,93 +147,96 @@ class _HolderScanViewState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - CircularProgressIndicator(), - SizedBox(height: 16), + const CircularProgressIndicator(), + const SizedBox(height: 16), Text('holderConnecting'.tr), ], ), ) : Obx(() { - final list = _service.scanned; - if (list.isEmpty) { - return Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(Icons.bluetooth_searching, - size: 56.sp, color: AppPalette.brand300), - SizedBox(height: 12.h), - Text( - _service.isScanning.value ? 'holderSearching'.tr : 'holderNotFound'.tr, - style: TextStyle( - fontSize: 15.sp, color: AppPalette.textSecondary(isDark)), - ), - SizedBox(height: 6.h), - Text( - 'holderPairHint'.tr, - style: TextStyle( - fontSize: 12.sp, color: AppPalette.textHint(isDark)), - ), - ], - ), - ); - } - return ListView.separated( - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h), - itemCount: list.length, - separatorBuilder: (_, __) => SizedBox(height: 12.h), - itemBuilder: (context, i) { - final d = list[i]; - return GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () => _connect(d), - child: Container( - padding: EdgeInsets.all(14.w), - decoration: BoxDecoration( - color: AppPalette.surface(isDark), - borderRadius: BorderRadius.circular(14.r), - border: Border.all(color: AppPalette.border(isDark)), - ), - child: Row( - children: [ - Icon(Icons.stay_current_portrait, - size: 26.sp, color: AppPalette.accent), - SizedBox(width: 12.w), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + final list = _scanned; + if (list.isEmpty) { + return Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.bluetooth_searching, + size: 56.sp, color: AppPalette.brand300), + SizedBox(height: 12.h), + Text( + _isScanning.value + ? 'holderSearching'.tr + : 'holderNotFound'.tr, + style: TextStyle( + fontSize: 15.sp, + color: AppPalette.textSecondary(isDark)), + ), + SizedBox(height: 6.h), + Text( + 'holderPairHint'.tr, + style: TextStyle( + fontSize: 12.sp, color: AppPalette.textHint(isDark)), + ), + ], + ), + ); + } + return ListView.separated( + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h), + itemCount: list.length, + separatorBuilder: (_, __) => SizedBox(height: 12.h), + itemBuilder: (context, i) { + final d = list[i]; + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => _connect(d), + child: Container( + padding: EdgeInsets.all(14.w), + decoration: BoxDecoration( + color: AppPalette.surface(isDark), + borderRadius: BorderRadius.circular(14.r), + border: Border.all(color: AppPalette.border(isDark)), + ), + child: Row( children: [ - Text( - d.displayName, - style: TextStyle( - fontSize: 15.sp, - fontWeight: FontWeight.w600, - color: AppPalette.textPrimary(isDark), - ), - ), - SizedBox(height: 2.h), - Text( - d.address, - style: TextStyle( - fontSize: 11.sp, - color: AppPalette.textHint(isDark), + Icon(Icons.stay_current_portrait, + size: 26.sp, color: AppPalette.accent), + SizedBox(width: 12.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + d.name.isEmpty ? 'bleUnknownDevice'.tr : d.name, + style: TextStyle( + fontSize: 15.sp, + fontWeight: FontWeight.w600, + color: AppPalette.textPrimary(isDark), + ), + ), + SizedBox(height: 2.h), + Text( + d.id, + style: TextStyle( + fontSize: 11.sp, + color: AppPalette.textHint(isDark), + ), + ), + ], ), ), + Text('连接', + style: TextStyle( + fontSize: 13.sp, + fontWeight: FontWeight.w600, + color: AppPalette.accent)), ], ), ), - Text('连接', - style: TextStyle( - fontSize: 13.sp, - fontWeight: FontWeight.w600, - color: AppPalette.accent)), - ], - ), - ), - ); - }, - ); - }), + ); + }, + ); + }), ); } } diff --git a/apps/client/lib/modules/devices/views/smartcar_scan_view.dart b/apps/client/lib/modules/devices/views/smartcar_scan_view.dart new file mode 100644 index 00000000..67d152cd --- /dev/null +++ b/apps/client/lib/modules/devices/views/smartcar_scan_view.dart @@ -0,0 +1,398 @@ +import 'dart:async'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; + +import '../../../core/theme/app_palette.dart'; +import '../../../devices/device_hub.dart'; +import '../../../devices/device_vendors.dart'; +import '../../../routes/app_routes.dart'; +import '../../main_tab/controllers/main_tab_controller.dart'; + +/// Smartcar(AI车载香薰)的扫描 / 连接页——走 [DeviceHub] 里的 Smartcar 插件。 +/// +/// 与支架那页结构一致,两点不同: +/// 1. **不需要后台自启动授权**:Smartcar 的连接是纯 GATT,没有向系统注册 +/// 「设备靠近就唤醒本应用」那种后台扫连,不构成自启动行为。 +/// 2. 卡片上多显示一行 MAC —— 它来自 BLE 广播,是服务端确权的依据, +/// 连不上时看一眼就知道是不是扫到了别的设备。 +class SmartcarScanView extends StatefulWidget { + const SmartcarScanView({super.key}); + + @override + State createState() => _SmartcarScanViewState(); +} + +class _SmartcarScanViewState extends State { + DevicePlugin get _plugin => DeviceHub.to.plugin(DeviceVendors.smartcar)!; + + final RxList _scanned = [].obs; + final RxBool _isScanning = false.obs; + + /// 附近**所有** BLE 设备(含没命中判定的),按 id 去重。 + /// 只在一台都没扫到时给人看——「扫不到」这个故障, + /// 不摊开设备到底播了什么就只能靠反复出包猜。 + final RxMap> _nearby = + >{}.obs; + final RxBool _showDiag = false.obs; + + /// 扫描起不来时的原因。**必须显示出来**:第一版失败是静默的, + /// 界面只会一直转圈,分不清「没扫到设备」和「压根没扫起来」。 + final RxnString _scanError = RxnString(); + StreamSubscription? _sub; + bool _connecting = false; + + @override + void initState() { + super.initState(); + _sub = _plugin.eventStream.listen((e) { + switch (e.type) { + case DevicePluginEventType.scanStarted: + _isScanning.value = true; + break; + case DevicePluginEventType.scanStopped: + _isScanning.value = false; + break; + case DevicePluginEventType.deviceDiscovered: + final d = e.discovered; + if (d == null || d.id.isEmpty) break; + // 按 id 去重累积:BLE 扫描会对同一台设备反复上报 + final i = _scanned.indexWhere((x) => x.id == d.id); + if (i >= 0) { + _scanned[i] = d; + } else { + _scanned.add(d); + } + break; + case DevicePluginEventType.customEvent: + // 厂商插件转发的扫描诊断(业务层不能直接 import 厂商目录) + if (e.customKey == 'smartcar.scan_diagnostic') { + final d = e.customPayload; + if (d is Map) { + final id = '${d['id']}'; + if (id.isNotEmpty) _nearby[id] = d; + } + } + break; + case DevicePluginEventType.error: + _scanError.value = e.errorMessage ?? e.errorCode; + _isScanning.value = false; + break; + default: + break; + } + }); + WidgetsBinding.instance.addPostFrameCallback((_) => _startScan()); + } + + Future _startScan() async { + _scanned.clear(); + _nearby.clear(); + _scanError.value = null; + if (!await _plugin.ensureReady()) return; + await _plugin.startScan(); + } + + @override + void dispose() { + _sub?.cancel(); + _plugin.stopScan(); + super.dispose(); + } + + Future _connect(DiscoveredDevice d) async { + if (_connecting) return; + setState(() => _connecting = true); + + String? failReason; + try { + await _plugin.connect( + d.id, + // MAC 只在广播里有,连上就拿不到了。这里带过去给确权用, + // 免得连上之后再回头找。 + options: DeviceConnectOptions(extra: {'mac': d.metadata['mac']}), + ); + await _plugin.rememberDevice(d); + } on DeviceException catch (e) { + failReason = e.message ?? e.code; + } catch (e) { + failReason = '$e'; + } + if (!mounted) return; + setState(() => _connecting = false); + + if (failReason == null) { + Get.snackbar('smartcarConnected'.tr, d.name, + snackPosition: SnackPosition.TOP, + duration: const Duration(seconds: 2)); + // BLE 通了不等于听得见:AI 回复和音乐走的是**经典蓝牙 A2DP**(见落地文档 7.0)。 + // 没接上时提示一次,别让用户以为"连上了却没声音"是坏了。 + unawaited(_hintClassicAudioIfNeeded(d.name)); + Get.offAllNamed(Routes.home); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (Get.isRegistered()) { + MainTabController.to.changeTab(MainTabController.tabDevice); + } + }); + } else { + // ⚠️ 失败原因**留在页面上**,不能只弹一下就没了: + // 这些信息(设备实际暴露了哪些服务、握手卡在哪条命令)是排查的全部依据, + // snackbar 几秒就消失,用户根本来不及看清更别说转述。 + _scanError.value = failReason; + Get.snackbar('smartcarConnectFailed'.tr, failReason, + snackPosition: SnackPosition.TOP, + duration: const Duration(seconds: 5)); + } + } + + /// 经典蓝牙没接上就提示一次。 + /// + /// - Android:插件已经在连接后自动 `createBond` 试过一次,这里只兜底提示 + /// - iOS:**没有**发起经典蓝牙配对的公开 API,只能引导用户去系统设置 + Future _hintClassicAudioIfNeeded(String name) async { + try { + final r = await _plugin.activeSession + ?.invokeFeature('smartcar.a2dp_status'); + if (r == null || r['connected'] == true) return; + Get.snackbar( + 'smartcarA2dpTitle'.tr, + 'smartcarA2dpHint'.tr.replaceAll('@name', name), + snackPosition: SnackPosition.TOP, + duration: const Duration(seconds: 6), + ); + } catch (_) { + // 查不到就不提示——这只是体验提示,不该把连接流程搅黄 + } + } + + @override + Widget build(BuildContext context) { + final bool isDark = Theme.of(context).brightness == Brightness.dark; + return Scaffold( + backgroundColor: AppPalette.background(isDark), + appBar: AppBar( + backgroundColor: AppPalette.background(isDark), + elevation: 0, + title: Text('catCarAroma'.tr), + actions: [ + Obx(() => _isScanning.value + ? Padding( + padding: EdgeInsets.only(right: 16.w), + child: Center( + child: SizedBox( + width: 18.w, + height: 18.w, + child: const CircularProgressIndicator(strokeWidth: 2), + ), + ), + ) + : IconButton( + icon: const Icon(Icons.refresh), + onPressed: _startScan, + )), + ], + ), + body: _connecting + ? Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const CircularProgressIndicator(), + SizedBox(height: 16.h), + Text('smartcarConnecting'.tr), + ], + ), + ) + : Obx(() { + final list = _scanned; + if (list.isEmpty) return _empty(isDark); + return ListView.separated( + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h), + itemCount: list.length, + separatorBuilder: (_, __) => SizedBox(height: 12.h), + itemBuilder: (context, i) => _card(list[i], isDark), + ); + }), + ); + } + + Widget _empty(bool isDark) => Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.bluetooth_searching, + size: 56.sp, color: AppPalette.brand300), + SizedBox(height: 12.h), + Obx(() => Text( + _isScanning.value + ? 'smartcarSearching'.tr + : 'smartcarNotFound'.tr, + style: TextStyle( + fontSize: 15.sp, + color: AppPalette.textSecondary(isDark)), + )), + SizedBox(height: 6.h), + Text( + 'smartcarScanHint'.tr, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12.sp, color: AppPalette.textHint(isDark)), + ), + SizedBox(height: 20.h), + _diagnostics(isDark), + ], + ), + ); + + /// 诊断面板:把附近扫到的 BLE 设备摊开。 + /// + /// 判据(厂商 ID 0x8505 / 名字含 smartcar)对不对,看这里最快: + /// - 列表里根本没有目标设备 → 设备没在播,或不在范围内 + /// - 有、但 mfg 那栏的厂商 ID 不是 0x8505 → 判据要按实际值改 + /// - 有、厂商 ID 对但长度不足 22 → 广播段布局和文档对不上 + Widget _diagnostics(bool isDark) => Obx(() { + final list = _nearby.values.toList(); + final err = _scanError.value; + // ⚠️ 0 台也要显示。「附近 0 台」和「面板不出现」是两回事: + // 前者说明扫描跑了但什么都没收到,后者说明扫描压根没起来。 + return Padding( + padding: EdgeInsets.symmetric(horizontal: 24.w), + child: Column( + children: [ + if (err != null) + Container( + width: double.infinity, + margin: EdgeInsets.only(bottom: 8.h), + padding: EdgeInsets.all(10.w), + decoration: BoxDecoration( + color: Colors.red.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(8.r), + ), + child: SelectableText('失败详情:$err', + style: TextStyle(fontSize: 11.sp, color: Colors.red)), + ), + TextButton.icon( + onPressed: () => _showDiag.value = !_showDiag.value, + icon: Icon( + _showDiag.value ? Icons.expand_less : Icons.expand_more, + size: 18.sp), + label: Text('附近 ${list.length} 台蓝牙设备', + style: TextStyle(fontSize: 12.sp)), + ), + if (_showDiag.value && list.isEmpty) + Text('一台都没收到 —— 蓝牙可能没开、权限被拒,或周围确实没有设备', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 11.sp, color: AppPalette.textHint(isDark))), + if (_showDiag.value && list.isNotEmpty) + Container( + constraints: BoxConstraints(maxHeight: 260.h), + padding: EdgeInsets.all(10.w), + decoration: BoxDecoration( + color: AppPalette.surface(isDark), + borderRadius: BorderRadius.circular(10.r), + border: Border.all(color: AppPalette.border(isDark)), + ), + child: ListView.builder( + shrinkWrap: true, + itemCount: list.length, + itemBuilder: (_, i) { + final d = list[i]; + final matched = d['matched'] == true; + final name = '${d['name']}'; + return Padding( + padding: EdgeInsets.symmetric(vertical: 4.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '${matched ? '✓ ' : ''}' + '${name.isEmpty ? '(无名)' : name} ${d['rssi']}dBm', + style: TextStyle( + fontSize: 11.sp, + fontWeight: matched + ? FontWeight.w700 + : FontWeight.w400, + color: AppPalette.textPrimary(isDark), + ), + ), + // 可长按复制:MAC 解错时要把这串原始字节发出来分析 + SelectableText( + 'mfg=${d['mfg']}\n' + '解出MAC=${d['parsedMac']}\n' + 'svc=${d['services']}', + style: TextStyle( + fontSize: 10.sp, + color: AppPalette.textHint(isDark)), + ), + ], + ), + ); + }, + ), + ), + ], + ), + ); + }); + + Widget _card(DiscoveredDevice d, bool isDark) { + final mac = '${d.metadata['mac'] ?? ''}'; + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => _connect(d), + child: Container( + padding: EdgeInsets.all(14.w), + decoration: BoxDecoration( + color: AppPalette.surface(isDark), + borderRadius: BorderRadius.circular(14.r), + border: Border.all(color: AppPalette.border(isDark)), + ), + child: Row( + children: [ + Icon(Icons.air, size: 26.sp, color: AppPalette.brand500), + SizedBox(width: 12.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + d.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 15.sp, + fontWeight: FontWeight.w600, + color: AppPalette.textPrimary(isDark), + ), + ), + if (mac.isNotEmpty) ...[ + SizedBox(height: 3.h), + Text( + mac, + style: TextStyle( + fontSize: 11.sp, + color: AppPalette.textHint(isDark), + ), + ), + ], + ], + ), + ), + if (d.rssi != null) + Text( + '${d.rssi} dBm', + style: TextStyle( + fontSize: 11.sp, color: AppPalette.textHint(isDark)), + ), + SizedBox(width: 6.w), + Icon(Icons.chevron_right, + size: 20.sp, color: AppPalette.textHint(isDark)), + ], + ), + ), + ); + } +} diff --git a/apps/client/lib/modules/emai/controllers/emai_controller.dart b/apps/client/lib/modules/emai/controllers/emai_controller.dart index 1d1528cb..c5575264 100644 --- a/apps/client/lib/modules/emai/controllers/emai_controller.dart +++ b/apps/client/lib/modules/emai/controllers/emai_controller.dart @@ -4,13 +4,14 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:haptic_feedback/haptic_feedback.dart'; +import '../../../data/services/network/api.dart'; import '../../../core/utils/logger.dart'; import '../../../data/models/appconfig.dart'; import '../../../data/models/user_Info.dart' as user_info; import '../../../data/services/assistant_directive_service.dart'; import '../../../data/services/bailian_multimodal_service.dart'; import '../../../data/models/emai_message.dart'; -import '../../../data/services/bes_ai_session_service.dart'; +import '../../../data/services/device_ai_session_service.dart'; import '../../../data/services/emai_chat_store.dart'; import '../../../data/utils/mic_pcm_streamer.dart'; import '../../../data/services/mcp_token_service.dart'; @@ -39,10 +40,17 @@ enum EmaiLinkState { class EmaiController extends GetxController with WidgetsBindingObserver implements EmaiSessionOwner { + /// [service] 不传就用全局那个(EMAI 的百炼应用),行为与改造前一致。 + /// + /// 传了才用传的——给「同一套对话 UI、不同百炼应用」的 agent 复用(如 Smartcar + /// 车载助手)。两个 agent 各自 new 一个 service 实例,不能共用,理由见 + /// [BailianMultimodalService] 的类注释。 + EmaiController({BailianMultimodalService? service}) + : _svc = service ?? Get.find(); + static const String _tag = 'EmaiController'; - static EmaiController get to => Get.find(); - final BailianMultimodalService _svc = Get.find(); + final BailianMultimodalService _svc; final MicPcmStreamer _mic = MicPcmStreamer(sampleRate: BailianMultimodalService.upstreamSampleRate); final PcmStreamPlayer _player = PcmStreamPlayer( @@ -78,7 +86,7 @@ class EmaiController extends GetxController /// ⚠️ duplex 在手机上能成立的前提是 AEC —— 外放的播报会被自己的麦收回去, /// 服务端 VAD 会当成用户插话,每次 AI 一开口就被自己打断。 /// [MicPcmStreamer] 已经开了 echoCancel/noiseSuppress,所以不需要像耳机那条 - /// 链路那样做「播报期间门控上行」的半双工妥协(见 BesAiSessionService 的注释: + /// 链路那样做「播报期间门控上行」的半双工妥协(见 DeviceAiSessionService 的注释: /// 耳机没把下行接进 AEC 参考路径,只能门控)。 /// /// **默认关**:进页面只建立会话,不开麦。连续对话必须由用户点一下中间按钮 @@ -87,7 +95,7 @@ class EmaiController extends GetxController /// ⚠️ 别再改回默认开。进页面即开麦意味着用户还没表达意图,麦克风就已经在 /// 录音并往服务端推流了——既是隐私问题,也会让「不小心点进来」变成一次 /// 计费的对话。耳机唤醒那条链路不走这里,它有自己的会话生命周期 - /// (见 BesAiSessionService)。 + /// (见 DeviceAiSessionService)。 final isContinuous = false.obs; /// 文字输入模式 / 语音输入模式 @@ -160,12 +168,12 @@ class EmaiController extends GetxController // 那条路径不经过本控制器的事件处理,得单独盯着 store 才能跟到底 _storeWorker = ever(_store.messages, (_) => _scrollToBottom()); - // 让 BesAiSessionService 能在耳机唤醒时找到本页并要求让出会话, + // 让 DeviceAiSessionService 能在耳机唤醒时找到本页并要求让出会话, // 同时避免 data 层反向 import modules 层。 // 用普通引用而不是 Get.put(this):后者会让 GetX // 再跑一次 onStart→onInit,而我们就在 onInit 里,直接递归爆栈。 - if (Get.isRegistered()) { - BesAiSessionService.to.attachPhonePage(this); + if (Get.isRegistered()) { + DeviceAiSessionService.to.attachPhonePage(this); } _subs.add(_svc.events.listen(_onEvent)); @@ -192,8 +200,8 @@ class EmaiController extends GetxController @override void onClose() { WidgetsBinding.instance.removeObserver(this); - if (Get.isRegistered()) { - BesAiSessionService.to.detachPhonePage(this); + if (Get.isRegistered()) { + DeviceAiSessionService.to.detachPhonePage(this); } _handshakeTimer?.cancel(); _cancelIdle(); @@ -245,8 +253,8 @@ class EmaiController extends GetxController if (linkState.value == EmaiLinkState.connecting) return; // 耳机会话正在跑:本页不去抢,等它结束后 resumeFromEarphone 会接回来 if (linkState.value == EmaiLinkState.onEarphone) return; - if (Get.isRegistered() && - BesAiSessionService.to.isActive.value) { + if (Get.isRegistered() && + DeviceAiSessionService.to.isActive.value) { linkState.value = EmaiLinkState.onEarphone; return; } @@ -304,18 +312,18 @@ class EmaiController extends GetxController /// 手机页面主动把控制权要回来:让耳机退出 AI 模式。 /// - /// 收尾是异步的——[BesAiSessionService.requestStop] 发完 `AA 65` 要等耳机回 + /// 收尾是异步的——[DeviceAiSessionService.requestStop] 发完 `AA 65` 要等耳机回 /// `0xE5`(或 2s 超时),它的 teardown 会回调 [resumeFromEarphone] 把本页接回来, /// 所以这里不用自己 connect(),否则会和耳机会话抢。 Future takeBackFromEarphone() async { - if (!Get.isRegistered()) { + if (!Get.isRegistered()) { // 服务没注册(理论上不会),至少别让页面卡在 onEarphone linkState.value = EmaiLinkState.idle; await connect(); return; } linkState.value = EmaiLinkState.connecting; - await BesAiSessionService.to.requestStop(); + await DeviceAiSessionService.to.requestStop(); } @override @@ -604,6 +612,32 @@ class EmaiController extends GetxController _svc.sendText(text); } + /// 一轮对话结束后上报**原始字数**(输入 = 这轮之前最近一条用户消息,输出 = 助手这条回复), + /// 服务端按后台换算系数折成算力记账。客户端**不算算力**——系数可在后台改,客户端算的话 + /// 改一次系数就要发一次版。字符数按 Unicode 码点(runes)计,与服务端口径一致。 + /// 上报失败只记日志:这是记账不是闸门,不该影响对话。 + void _reportAiUsage(EmaiMessage assistant) { + int up = 0; + for (final msg in messages.reversed) { + if (identical(msg, assistant)) continue; + if (msg.isUser) { + up = msg.text.runes.length; + break; + } + } + final down = assistant.text.runes.length; + if (up == 0 && down == 0) return; + unawaited(Api.usagesResPoints({ + 'usagetype': 3, // UsageType.AI + 'usages': {}, + 'upchars': up, + 'downchars': down, + }).catchError((e) { + Logger.w(_tag, 'AI 用量上报失败: $e'); + return null; + })); + } + /// 打断当前回复 Future interrupt() async { if (!isResponding) return; @@ -706,6 +740,7 @@ class EmaiController extends GetxController if (e.text.isNotEmpty) _mergeInto(m, e.text); _store.finalize(m); _streamingAssistant = null; + _reportAiUsage(m); } // 文本收完不代表音频收完,但下行音频到此为止,让播放器把缓冲播完 _player.end(); diff --git a/apps/client/lib/modules/emai/module.dart b/apps/client/lib/modules/emai/module.dart new file mode 100644 index 00000000..2243a314 --- /dev/null +++ b/apps/client/lib/modules/emai/module.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../core/utils/ai_navigation.dart'; +import '../../routes/app_routes.dart'; +import '../module_descriptor.dart'; +import 'bindings/emai_binding.dart'; +import 'views/emai_view.dart'; + +/// EMAI 助手(阿里百炼多模态对话) +final AgentModuleDescriptor emaiModule = AgentModuleDescriptor( + id: 'emaiAssistant', + title: 'agentEmai', + subtitle: 'agentEmaiDesc', + icon: Icons.auto_awesome, + gradient: const [Color(0xFF5B8DEF), Color(0xFF7E57C2)], + // 按 agentType 走移动精灵或 EMAI 页 + onLaunch: navigateToAIAssistant, + pages: [ + GetPage( + name: Routes.emai, + page: () => const EmaiView(), + binding: EmaiBinding(), + transition: Transition.rightToLeft, + transitionDuration: const Duration(milliseconds: 250), + ), + ], +); diff --git a/apps/client/lib/modules/emai/views/emai_view.dart b/apps/client/lib/modules/emai/views/emai_view.dart index 9eb74920..33c01254 100644 --- a/apps/client/lib/modules/emai/views/emai_view.dart +++ b/apps/client/lib/modules/emai/views/emai_view.dart @@ -13,7 +13,17 @@ import 'widgets/emai_level_bar.dart'; /// 结构自上而下:状态条 → 消息列表 → 输入区(按住说话 / 文字输入二选一)。 /// 所有 AI 能力都在阿里百炼多模态应用里,页面本身只管采音、播音和展示。 class EmaiView extends GetView { - const EmaiView({super.key}); + /// [controllerTag]:不传 = 取全局那个 [EmaiController](EMAI 自己),行为不变。 + /// 传了则取同名 tag 的实例——给复用这套 UI 的其它 agent 用(如 Smartcar)。 + /// [titleKey]:标题栏的 i18n key,默认 EMAI 自己的。 + const EmaiView({super.key, this.controllerTag, this.titleKey = 'agentEmai'}); + + final String? controllerTag; + final String titleKey; + + /// GetView 用它决定 `controller` 取哪个实例 + @override + String? get tag => controllerTag; @override Widget build(BuildContext context) { @@ -52,7 +62,7 @@ class EmaiView extends GetView { onPressed: () => Get.back(), ), title: Text( - 'agentEmai'.tr, + titleKey.tr, style: TextStyle( fontSize: 17.sp, fontWeight: FontWeight.w600, diff --git a/apps/client/lib/modules/goods/controllers/goods_base_controller.dart b/apps/client/lib/modules/goods/controllers/goods_base_controller.dart index 78a2eac8..944bf2d1 100644 --- a/apps/client/lib/modules/goods/controllers/goods_base_controller.dart +++ b/apps/client/lib/modules/goods/controllers/goods_base_controller.dart @@ -141,8 +141,25 @@ abstract class GoodsBaseController extends GetxController { } } + /// 本包是否为 Google Play 渠道。 + /// + /// ⚠️ 读的是编译期烧进包里的 `.env` 的 `Channel`,**不要**换成 + /// `VersionUpdateService.cachedChannel`——那个值在版本检查跑完前会回退成 + /// `GLOBAL_GOOGLE`(见 version_update_service.dart 的 getter),用它会在国内包 + /// 启动初期把微信/支付宝误杀掉。 + static bool get _isGooglePlayBuild => + (dotenv.env['Channel'] ?? '').trim().toUpperCase() == 'GLOBAL_GOOGLE'; + /// 解析后端 paychannels 并结合平台过滤可用支付方式 + /// + /// ⚠️ Google Play 卖数字商品必须走 Play 结算,摆出微信/支付宝/PayPal 是最典型的 + /// 下架理由。所以 Google 渠道**一律只留 google**:既不信后端下发的渠道列表, + /// 配置缺失时也不回退成「展示所有」。其它渠道行为保持不变。 List<_PayMethod> _getEnabledPayMethods() { + if (_isGooglePlayBuild) { + final bool isAndroid = GetPlatform.isAndroid && !kIsWeb; + return isAndroid ? <_PayMethod>[_PayMethod.google] : <_PayMethod>[]; + } try { //1. 获取后端配置的支付渠道 final paychannels = diff --git a/apps/client/lib/modules/goods/controllers/goodsvip_controller.dart b/apps/client/lib/modules/goods/controllers/goodsvip_controller.dart index 98b18c03..55c9d737 100644 --- a/apps/client/lib/modules/goods/controllers/goodsvip_controller.dart +++ b/apps/client/lib/modules/goods/controllers/goodsvip_controller.dart @@ -1,15 +1,92 @@ +import 'package:get/get.dart'; import '../../../data/models/goods.dart'; import '../../../data/services/network/api.dart'; import 'goods_base_controller.dart'; class GoodsvipController extends GoodsBaseController { + /// 会员与算力状态(`user_getcompute`),页面顶部 VIP 卡片下展示。 + /// 服务端已把自购与设备赋予的 VIP 合并好、算力也拆好了来源,这里**不做任何换算**。 + final compute = Rxn>(); + + @override + void onInit() { + super.onInit(); + refreshCompute(); + } + + Future refreshCompute() async { + try { + final resp = await Api.getCompute(); + if (resp is Map) compute.value = Map.from(resp); + } catch (_) { + // 展示项,拿不到就不显示 + } + } + + /// 「设备 N + 账户 M」形式的算力摘要;没数据返回 null。 + String? get computeSummary { + final c = compute.value?['compute']; + if (c is! Map) return null; + final dev = (c['deviceleft'] as num?)?.toInt() ?? 0; + final usr = (c['userbalance'] as num?)?.toInt() ?? 0; + return 'computeSummary'.trParams({'device': '$dev', 'user': '$usr'}); + } + + /// 需要提示「VIP 快到期了」吗:剩余天数 ≤ 后台配的阈值(阈值为 0 = 后台关掉了这个提示)。 + /// 判定用服务端下发的 vipwarndays,客户端不自己拍数字——运营改阈值不用发版。 + bool get vipExpiringSoon { + final v = compute.value?['vip']; + final r = compute.value?['rates']; + if (v is! Map || r is! Map) return false; + final days = (r['vipwarndays'] as num?)?.toInt() ?? 0; + if (days <= 0) return false; + final exp = (v['exptime'] as num?)?.toInt() ?? 0; + if (exp <= 0) return false; + final left = exp - DateTime.now().millisecondsSinceEpoch ~/ 1000; + return left > 0 && left <= days * 86400; + } + + /// VIP 剩余天数(向上取整,至少 1);无 VIP 或已过期返回 0。 + int get vipDaysLeft { + final v = compute.value?['vip']; + if (v is! Map) return 0; + final exp = (v['exptime'] as num?)?.toInt() ?? 0; + final left = exp - DateTime.now().millisecondsSinceEpoch ~/ 1000; + if (left <= 0) return 0; + return (left / 86400).ceil(); + } + + /// 需要提示「算力不多了」吗:剩余总量 ≤ 后台配的阈值(阈值 0 = 不提示)。 + bool get computeLow { + final c = compute.value?['compute']; + final r = compute.value?['rates']; + if (c is! Map || r is! Map) return false; + final warn = (r['computewarn'] as num?)?.toInt() ?? 0; + if (warn <= 0) return false; + final left = ((c['deviceleft'] as num?)?.toInt() ?? 0) + ((c['userbalance'] as num?)?.toInt() ?? 0); + return left <= warn; + } + + /// 当前 VIP 是否来自设备(用于副标题标注来源)。 + bool get vipFromDevice { + final v = compute.value?['vip']; + if (v is! Map) return false; + final self = (v['selfexptime'] as num?)?.toInt() ?? 0; + final exp = (v['exptime'] as num?)?.toInt() ?? 0; + final level = (v['level'] as num?)?.toInt() ?? 0; + return level > 0 && exp > self; + } + @override Future> fetchProducts() async { + // 2026-09 起在售的只有 VIP 时长与算力包;AI/Meet/Translation 是旧资源点包, + // 仍然拉取是为了让还挂在架上的存量商品能买(发货时会折成算力),但不再新建。 final types = [ + UsageType.Vip, + UsageType.Compute, UsageType.AI, UsageType.Meet, UsageType.Translation, - UsageType.Vip, ]; final Map all = {}; for (final t in types) { diff --git a/apps/client/lib/modules/goods/views/goodsvip_view.dart b/apps/client/lib/modules/goods/views/goodsvip_view.dart index 3edacde0..ffb2bbde 100644 --- a/apps/client/lib/modules/goods/views/goodsvip_view.dart +++ b/apps/client/lib/modules/goods/views/goodsvip_view.dart @@ -52,8 +52,21 @@ class GoodsvipView extends GetView { for (final g in controller.items) { grouped.putIfAbsent(g.usagetype, () => []).add(g); } - final order = [UsageType.Vip]; + // VIP 时长在前、算力包在后;两者都没有商品时页面只剩权益说明 + final order = [UsageType.Vip, UsageType.Compute]; final children = []; + // 到期 / 算力不足提示条:阈值由后台配(0 = 关掉该提示),判定在 controller 里 + if (controller.vipExpiringSoon) { + children.add(_buildWarnBanner( + isDarkMode, + 'vipExpiringSoon'.trParams({'days': '${controller.vipDaysLeft}'}), + )); + children.add(SizedBox(height: 12.h)); + } + if (controller.computeLow) { + children.add(_buildWarnBanner(isDarkMode, 'computeLow'.tr)); + children.add(SizedBox(height: 12.h)); + } children.add(_buildFeaturesSection(isDarkMode)); children.add(SizedBox(height: 16.h)); // children.add(_buildScenesSection(isDarkMode)); @@ -100,6 +113,39 @@ class GoodsvipView extends GetView { ); } + /// 到期 / 算力不足的提示条。刻意做成温和的黄色而不是红色错误样式—— + /// 这是「该续费了」的提醒,不是故障;下面就是购买入口,不需要再额外引导。 + Widget _buildWarnBanner(bool isDarkMode, String text) { + return Container( + width: double.infinity, + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h), + decoration: BoxDecoration( + color: isDarkMode ? const Color(0xFF3A2F16) : const Color(0xFFFFF7E6), + borderRadius: BorderRadius.circular(12.r), + border: Border.all( + color: isDarkMode ? const Color(0xFF6B551F) : const Color(0xFFFFE0A3), + ), + ), + child: Row( + children: [ + Icon(Icons.info_outline, + size: 18.sp, + color: isDarkMode ? const Color(0xFFE0B860) : const Color(0xFFB7791F)), + SizedBox(width: 10.w), + Expanded( + child: Text( + text, + style: TextStyle( + fontSize: 13.sp, + color: isDarkMode ? const Color(0xFFE8D5A8) : const Color(0xFF8A6116), + ), + ), + ), + ], + ), + ); + } + Widget _buildFeaturesSection(bool isDarkMode) { final textColor = isDarkMode ? Colors.white : Colors.black; final subColor = isDarkMode ? Colors.white70 : Colors.grey[700]; @@ -233,11 +279,16 @@ class GoodsvipView extends GetView { UsageType.Meet: 'conferenceAssistant'.tr, UsageType.Translation: 'simultaneousTranslation'.tr, UsageType.Vip: 'memberService'.tr, + UsageType.Compute: 'computePack'.tr, }; final iconAndColor = _iconColorForType(type, isDarkMode); final subColor = isDarkMode ? Colors.white70 : Colors.grey[700]; String titleStr = titles[type] ?? type.name; String? vipSubtitle; + if (type == UsageType.Compute) { + // 算力包分区:副标题显示当前余额(服务端已把设备赠送与账户余额拆好) + vipSubtitle = controller.computeSummary; + } if (type == UsageType.Vip) { int viplv = 0; int vipexptime = 0; @@ -254,7 +305,7 @@ class GoodsvipView extends GetView { } // titleStr = 'Vip $viplv'; vipSubtitle = expiry != null - ? '${'expiryLabel'.tr}${_fmtDate(expiry)}' + ? '${'expiryLabel'.tr}${_fmtDate(expiry)}${controller.vipFromDevice ? ' · ${'vipFromDevice'.tr}' : ''}' : 'notActivated'.tr; } return Container( @@ -298,6 +349,14 @@ class GoodsvipView extends GetView { ), ), SizedBox(height: 8.h), + // 会员与算力(user_getcompute):服务端已合并自购与设备赋予,这里只展示 + if (type == UsageType.Vip && controller.computeSummary != null) ...[ + Text( + controller.computeSummary!, + style: TextStyle(fontSize: 12.sp, color: subColor), + ), + SizedBox(height: 4.h), + ], if (type == UsageType.Vip && vipSubtitle != null) Text( vipSubtitle, @@ -817,6 +876,14 @@ class GoodsvipView extends GetView { : Colors.indigo[100]!, foreground: isDarkMode ? Colors.indigo[300]! : Colors.indigo[600]!, ); + case UsageType.Compute: + return _IconColors( + icon: Icons.bolt, + background: isDarkMode + ? Colors.amber[900]!.withOpacity(0.3) + : Colors.amber[100]!, + foreground: isDarkMode ? Colors.amber[300]! : Colors.amber[700]!, + ); case UsageType.Vip: case UsageType.UsageNull: return _IconColors( diff --git a/apps/client/lib/modules/home/controllers/home_controller.dart b/apps/client/lib/modules/home/controllers/home_controller.dart index d3bfc0c6..c3e705e1 100644 --- a/apps/client/lib/modules/home/controllers/home_controller.dart +++ b/apps/client/lib/modules/home/controllers/home_controller.dart @@ -1,98 +1,48 @@ import 'dart:async'; -import '/core/utils/id_verify_guard.dart'; -import '/core/utils/device_connection.dart'; -import '/core/utils/toast_throttle.dart'; -import 'package:device_jieli/device_jieli.dart'; +import 'package:agent_service/agent_service.dart'; +import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; -import 'package:agent_service/agent_service.dart'; -import '../../../data/services/novice_guide_service.dart'; -import '../../../routes/app_routes.dart'; + +import '/core/utils/device_connection.dart'; +import '/core/utils/id_verify_guard.dart'; +import '/core/utils/toast_throttle.dart'; import '../../../core/utils/logger.dart'; -import 'package:flutter/material.dart'; -import '../../../data/services/bluetooth_manager.dart'; -import '../../../data/services/ble_manager.dart'; -import '../../../data/services/ota_check_service.dart'; -import '../../../data/services/id_verify_service.dart'; import '../../../data/models/appconfig.dart'; import '../../../data/models/appconfig_model.dart'; +import '../../../data/services/id_verify_service.dart'; +import '../../../data/services/novice_guide_service.dart'; +import '../../../data/services/ota_check_service.dart'; +import '../../../devices/device_hub.dart'; +import '../../../routes/app_routes.dart'; -/// 连接状态枚举 -enum ConnectionStatus { - disconnected, // 未连接 - connecting, // 连接中 - connected, // 已连接 - failed // 连接失败 -} - -/// 主页控制器,管理设备连接状态和信息展示 +/// 主框架控制器:各功能入口的跳转与闸门、连上设备后的固件检查、播报打断开关。 +/// +/// 设备状态一律来自 [DeviceHub],这里不再自己维护任何连接/电量真相。 class HomeController extends GetxController { static const String _tag = 'HomeCtrl'; - static const String _lastDeviceNameKey = 'last_connected_device_name'; // 存储键 - static const String _lastDeviceImageKey = - 'last_connected_device_image'; // 存储上一次设备图片的键 static HomeController get to => Get.find(); final GetStorage _storage = GetStorage(); - String? _lastConnectedDeviceImage; // 新增:存储上一次连接设备的图片链接 - - final _isFullyConnected = false.obs; - String? _lastConnectedDeviceName; - // 播报打断开关状态(与 AgentController 对齐) - final isTtsInterruptEnabled = false.obs; // 是否启用播报打断 + // 播报打断开关状态 + final isTtsInterruptEnabled = false.obs; - // 移除了电池信息定时刷新相关变量 - - // OTA检查服务 late final OtaCheckService _otaCheckService; - - bool get isFullyConnected => _isFullyConnected.value; - RxBool get isFullyConnectedRx => _isFullyConnected; - BluetoothDevice? get currentDevice => _bluetoothManager.currentDevice; - Rx get deviceInfo => _bleManager.deviceInfo; - - static final RxInt leftEarBattery = 0.obs; - static final RxInt rightEarBattery = 0.obs; - final caseBattery = 0.obs; - final leftEarCharging = false.obs; - final rightEarCharging = false.obs; - final caseCharging = false.obs; - final firmwareVersion = ''.obs; - - void updateDeviceInfo(DeviceInfo? newDeviceInfo) { - leftEarBattery.value = newDeviceInfo?.leftEarBattery ?? 0; - rightEarBattery.value = newDeviceInfo?.rightEarBattery ?? 0; - caseBattery.value = newDeviceInfo?.caseBattery ?? 0; - leftEarCharging.value = newDeviceInfo?.leftEarCharging ?? false; - rightEarCharging.value = newDeviceInfo?.rightEarCharging ?? false; - caseCharging.value = newDeviceInfo?.caseCharging ?? false; - firmwareVersion.value = newDeviceInfo?.firmwareVersion ?? ''; - } - - Worker? _deviceInfoWorker; - Worker? _classicBluetoothWorker; - Worker? _bleConnectionWorker; - - /// 全局 5s 刷新定时器。声明为 static 是为了让它跨 HomeController 实例存活: - /// `Get.offAllNamed(Routes.home)` 把旧 controller 干掉、新 controller 起来时, - /// 这个定时器始终是同一个,永远在跑,直接调当前注册的 HomeController 的 - /// `refreshDeviceConnection`(=点刷新按钮的逻辑)。 - static Timer? _staticPollTimer; - static const Duration _pollInterval = Duration(seconds: 5); - - final _bluetoothManager = Get.find(); - final _bleManager = Get.find(); - final noviceGuideService = Get.find(); + Worker? _connectedWorker; + + /// 任一设备在线。保留旧名给还在用它的页面。 + RxBool get isFullyConnectedRx => DeviceHub.to.anyConnected; + bool get isFullyConnected => isFullyConnectedRx.value; - /// 按设备名安全地查产品(AppConfig.getproduct 会抛,见调用处注释)。 + /// 按设备名安全地查产品(AppConfig.getproduct 单向包含,这里双向)。 DBProduct? _findProductByName(String deviceName) { if (!AppConfig.isInitialized()) return null; final n = deviceName.trim(); if (n.isEmpty) return null; for (final p in AppConfig.config.products) { - if (p.devicename.contains(n)) return p; + if (p.devicename.contains(n) || n.contains(p.devicename)) return p; } return null; } @@ -106,87 +56,34 @@ class HomeController extends GetxController { if (Get.isRegistered()) { IdVerifyService.to.ensureLoaded(); } - _loadLastConnectedDeviceName(); // 加载持久化的设备名称 - _initWithCachedInfo(); - _loadTtsInterrupt(); // 加载播报打断开关初始状态 - // 监听存储中的“agent_tts_interrupe”键变化,实现与 Agent 页同步 - // 中文注释:当 Agent 页或 Home 页任意一处切换时,另一处通过此监听自动刷新开关状态 + _loadTtsInterrupt(); _storage.listenKey('agent_tts_interrupt', (value) { try { final bool newValue = value is bool ? value : (value == 'true'); if (isTtsInterruptEnabled.value != newValue) { isTtsInterruptEnabled.value = newValue; } - } catch (e) { - // 中文注释:忽略异常,保持现有状态,避免因类型转换失败导致崩溃 + } catch (_) {} + }); + // 连接成功后检查 OTA 升级 + _connectedWorker = ever(DeviceHub.to.anyConnected, (on) { + if (on && noviceGuideService.isHomeGuide) { + Future.delayed(const Duration(seconds: 1), _checkOtaUpgrade); } }); - - // 移除了电池信息定时刷新的启动 } @override void onClose() { - _deviceInfoWorker?.dispose(); - _classicBluetoothWorker?.dispose(); - _bleConnectionWorker?.dispose(); + _connectedWorker?.dispose(); super.onClose(); } - void _initWithCachedInfo() { - _setupStateListeners(); - _checkConnectionStatus(); - _ensureStaticPollTimer(); - } - - /// 启动静态 5s 刷新定时器。已经在跑就什么都不做。 - /// 定时器一旦起来就永远不取消(HomeController 只是 lazyPut,控制器实例可能反复 - /// 销毁/重建,但定时器跨实例存活),每次 fire 都去当前注册的 HomeController - /// 调 refreshDeviceConnection——和用户点刷新按钮完全等价。 - static void _ensureStaticPollTimer() { - if (_staticPollTimer != null && _staticPollTimer!.isActive) return; - _staticPollTimer = Timer.periodic(_pollInterval, (_) { - try { - if (Get.isRegistered()) { - Get.find().refreshDeviceConnection(); - } - } catch (_) { - // 忽略:home 还没注册或者刚销毁中间窗口期 - } - }); - } - - void _setupStateListeners() { - _deviceInfoWorker = ever(_bleManager.deviceInfo, (DeviceInfo? info) { - if (info != null) updateDeviceInfo(info); - }); - - _classicBluetoothWorker = - ever(_bluetoothManager.currentDeviceRx, (BluetoothDevice? device) { - if (device != null) { - _saveLastConnectedDeviceName(device.name); // 使用新的保存方法 - } - _checkConnectionStatus(); - }); - - _bleConnectionWorker = ever(_bleManager.connectionStateRx, (int state) { - _checkConnectionStatus(); - }); - } - - /// 加载“播报打断”开关状态 - /// 逻辑与 AgentController 保持一致: - /// 1)若本地不存在存储,则根据设备产品的 iscontinuouschat 取反作为默认值; - /// 2)若存在存储则直接读取; - /// 3)同步到原生服务 AgentService.isInterrupt。 + /// 加载"播报打断"开关状态:本地没存过时按设备产品的 iscontinuouschat 取反。 Future _loadTtsInterrupt() async { try { if (!_storage.hasData('agent_tts_interrupt')) { final deviceName = getDeviceName(); - // 这里用本地的 _findProductByName 而不是 AppConfig.getproduct(): - // 后者只做「产品名包含设备名」单向匹配,本地这份是双向包含 + 兜底, - // 设备名与产品名不完全一致时才匹配得上。 - // (getproduct 本身已经不会抛了,2026-09-03 起查不到返回 null。) final DBProduct? product = _findProductByName(deviceName); if (deviceName.isNotEmpty && product != null) { isTtsInterruptEnabled.value = !(product.iscontinuouschat ?? true); @@ -204,8 +101,6 @@ class HomeController extends GetxController { } } - /// 切换“播报打断”开关 - /// 同步保存到本地,并通知原生服务。 Future toggleTtsInterrupt() async { try { isTtsInterruptEnabled.toggle(); @@ -216,44 +111,11 @@ class HomeController extends GetxController { } } - /// 从本地存储加载最后连接的设备名称 - void _loadLastConnectedDeviceName() { - _lastConnectedDeviceName = _storage.read(_lastDeviceNameKey); - Logger.d(_tag, '加载最后连接的设备名称: $_lastConnectedDeviceName'); - } - - /// 保存最后连接的设备名称到本地存储 - void _saveLastConnectedDeviceName(String deviceName) { - _lastConnectedDeviceName = deviceName; - _storage.write(_lastDeviceNameKey, deviceName); - Logger.d(_tag, '保存最后连接的设备名称: $deviceName'); - } - - /// 保存上一次连接设备的图片链接到本地存储 - void _saveLastConnectedDeviceImage(String? imageUrl) { - if (imageUrl != null && imageUrl.isNotEmpty) { - _lastConnectedDeviceImage = imageUrl; - _storage.write(_lastDeviceImageKey, imageUrl); - Logger.d(_tag, '保存上一次连接设备的图片: $imageUrl'); - } - } - - Future refreshDeviceConnection() async { - await _checkConnectionStatus(); - - // 如果设备已连接,主动刷新设备信息 - if (_isFullyConnected.value) { - try { - Logger.d(_tag, '刷新设备信息'); - await _bleManager.fetchDeviceInfo(); - } catch (e) { - Logger.e(_tag, '刷新设备信息失败: $e'); - } - } - } + /// 刷新设备状态(点刷新按钮 / 定时) + Future refreshDeviceConnection() => DeviceHub.to.refreshAll(); void rescanDevices() { - Get.toNamed(Routes.devices); + Get.toNamed(Routes.deviceCategory); } void openTranslation() { @@ -262,32 +124,23 @@ class HomeController extends GetxController { } /// 翻译跳转:按 translationId 进入对应翻译模式 - /// 逻辑参考 TranslationMiddlewareController.navigateToTranslationFeature /// translationId 取值:simultaneous / faceToFace / call / audioVideo - /// 其中 call、audioVideo 依赖设备连接,未连接则提示并返回 + /// 其中 call 依赖设备连接且要正处于通话中 void openTranslationFeature(String translationId) { if (IdVerifyGuard.blocked()) return; - // 只有通话翻译必须依赖耳机链路;多媒体翻译走手机摄像头/麦克风,无需连接设备 - final bool needBle = translationId == 'call'; - // 三条链路任意一条连上都算已连接(杰理 / 蓝讯支架 / 恒玄耳机)。 - // 之前只看 _isFullyConnected(杰理专用),恒玄耳机连上了照样被拦。 - // 通话翻译还要求正处于通话中——耳机得先进通话模式(0xD1)才有双路音频 - // ⚠️ 下面三条一律走 ToastThrottle 而不是裸 Get.snackbar: - // 它们拦的都是「这个功能现在就是用不了」,而卡片只是灰着、点得动, - // 用户会连点几下试——每点一下补一条一模一样的提示就把屏幕糊满了, - // 而且 Get 的 snackbar 会排队,要等它们逐条超时才散得干净。 - // 信息量只在第一条,后面全是噪音。 - if (needBle && DeviceConnection.any && !DeviceConnection.inCall) { + final bool needDevice = translationId == 'call'; + // 下面三条一律走 ToastThrottle:卡片只是灰着、点得动,用户会连点几下试 + if (needDevice && DeviceConnection.any && !DeviceConnection.inCall) { ToastThrottle.show(ToastThrottle.keyCallRequired, title: 'callRequiredTitle'.tr, message: 'callRequiredDesc'.tr, window: ToastThrottle.gateWindow); return; } - if (needBle && !DeviceConnection.any) { + if (needDevice && !DeviceConnection.any) { ToastThrottle.show(ToastThrottle.keyConnectDevice, - title: 'connectDevice'.tr, // 连接设备 - message: 'pleaseConnectDeepSoundDevice'.tr, // 请连接 Eaimar 设备 + title: 'connectDevice'.tr, + message: 'pleaseConnectDeepSoundDevice'.tr, window: ToastThrottle.gateWindow); return; } @@ -303,7 +156,7 @@ class HomeController extends GetxController { arguments: {'translationId': translationId}); } - /// 打开通话录音:与首页卡片置灰条件统一,未连接设备则提示并返回 + /// 打开通话录音:与卡片置灰条件统一,未连接设备/不在通话中则提示并返回 void openCallRecording() { if (IdVerifyGuard.blocked()) return; if (DeviceConnection.any && !DeviceConnection.inCall) { @@ -315,8 +168,8 @@ class HomeController extends GetxController { } if (!DeviceConnection.any) { ToastThrottle.show(ToastThrottle.keyConnectDevice, - title: 'connectDevice'.tr, // 连接设备 - message: 'pleaseConnectDeepSoundDevice'.tr, // 请连接 Eaimar 设备 + title: 'connectDevice'.tr, + message: 'pleaseConnectDeepSoundDevice'.tr, window: ToastThrottle.gateWindow); return; } @@ -324,10 +177,7 @@ class HomeController extends GetxController { arguments: {'title': 'agentCallRecording', 'folder': 'call_recordings'}); } - /// 打开现场录音。 - /// - /// 不再要求先连设备:连上了走设备录音通路,没连就用手机麦克风 - /// (具体分支见 CallRecordingController._startRecording)。 + /// 打开现场录音。不要求先连设备:连上了走设备录音通路,没连就用手机麦克风。 void openFieldRecording() { if (DeviceConnection.isBlockedByCall('fieldRecording')) { ToastThrottle.show(ToastThrottle.keyInCallBusy, @@ -340,322 +190,42 @@ class HomeController extends GetxController { Get.toNamed(Routes.fieldRecording, arguments: { 'title': 'agentFieldRecording', 'folder': 'field_recordings', - // 录完归档进语音记录助手,由它统一管理并上云 'archiveToMeeting': true, }); } /// 打开会议模块 - /// 参数:无 - /// 返回值:`Future` 无返回数据 - /// 异常:不显式抛出;内部仅记录日志 - /// 说明:进入会议页前关闭唤醒;返回首页后根据录音状态决定是否开启唤醒(存在录音任务则不启用) void openMeet() { if (IdVerifyGuard.blocked()) return; AgentService.interruptCurrentResponse(); Get.toNamed(Routes.meeting); } - Future _checkConnectionStatus() async { - try { - // 直接问杰理 SDK 当前已连接设备 - JieliDevice? sdkDevice; - try { - sdkDevice = await Jielihome.instance.connectedDevice(); - } catch (e) { - Logger.w(_tag, '查询杰理已连接设备失败: $e'); - sdkDevice = null; - } - final hasBleConnection = - sdkDevice != null && sdkDevice.address.isNotEmpty; - bool wasConnected = _isFullyConnected.value; - bool isNowConnected = hasBleConnection; - - if (_isFullyConnected.value != isNowConnected) { - _isFullyConnected.value = isNowConnected; - _isFullyConnected.refresh(); - //update(); - - if (!wasConnected && isNowConnected) { - // 连接成功后等待1秒再获取设备信息 - Future.delayed(const Duration(seconds: 1), () async { - await _bleManager.fetchDeviceInfo(); - }); - - // 移除了连接成功后的电池信息刷新 - - // 连接成功后检查OTA升级 - if (noviceGuideService.isHomeGuide) { - Future.delayed(const Duration(seconds: 1), () { - _checkOtaUpgrade(); - }); - } - } - // 移除了根据连接状态控制定时器的逻辑 - } - - //update(); - } catch (e) { - Logger.e(_tag, '${'checkConnectionStatusFailed'.tr}: $e'); - if (_isFullyConnected.value) { - _isFullyConnected.value = false; - _isFullyConnected.refresh(); - // 移除了发生错误时停止定时器的逻辑 - // 注意:不再重置OTA检查状态,因为现在由全局服务管理 - //update(); - } - } - } - - Color getConnectionStatusColor() { - return _isFullyConnected.value ? Colors.green : Colors.grey; - } + Color getConnectionStatusColor() => + isFullyConnected ? Colors.green : Colors.grey; - String getConnectionStatusText() { - return _isFullyConnected.value ? 'connected'.tr : 'unconnected'.tr; - } - - bool get shouldShowDeviceInfo => currentDevice != null; + String getConnectionStatusText() => + isFullyConnected ? 'connected'.tr : 'unconnected'.tr; + /// 当前(或最近一次)连接设备的名字;从没连过返回「未知设备」 String getDeviceName() { - if (_isFullyConnected.value && currentDevice == null) { - _checkConnectionStatus(); - } - - final deviceName = currentDevice?.name; - //final deviceName = '102'; - if (deviceName != null && deviceName.isNotEmpty) { - return deviceName; - } - - final bleDeviceName = deviceInfo.value?.name; - if (bleDeviceName != null && bleDeviceName.isNotEmpty) { - return bleDeviceName; - } - - if (!_isFullyConnected.value && - _lastConnectedDeviceName != null && - _lastConnectedDeviceName!.isNotEmpty) { - return _lastConnectedDeviceName!; - } - - return 'unknownEquipment'.tr; - } - - String getSignalStrength() { - if (!_isFullyConnected.value) { - return 'zeroSignal'.tr; - } - - final random = DateTime.now().millisecondsSinceEpoch % 3; - switch (random) { - case 0: - return 'good'.tr; - case 1: - return 'fine'.tr; - default: - return 'excellent'.tr; - } - } - - String getDeviceId() { - return deviceInfo.value?.address ?? currentDevice?.address ?? 'unknown'.tr; - } - - String getBatteryText() { - return deviceInfo.value?.batteryLevel != null && - deviceInfo.value!.batteryLevel > 0 - ? '${deviceInfo.value?.batteryLevel}%' - : 'unknown'.tr; - } - - String getEarbudsText() { - if (deviceInfo.value == null || - (deviceInfo.value!.leftEarBattery <= 0 && - deviceInfo.value!.rightEarBattery <= 0 || - deviceInfo.value!.caseBattery > 100)) { - return 'unknown'.tr; - } - - String leftStatus = deviceInfo.value!.leftEarBattery > 0 - ? '${deviceInfo.value!.leftEarBattery}%' - : 'N/A'; - String rightStatus = deviceInfo.value!.rightEarBattery > 0 - ? '${deviceInfo.value!.rightEarBattery}%' - : 'N/A'; - - leftStatus = - deviceInfo.value!.leftEarCharging ? '$leftStatus ⚡' : leftStatus; - rightStatus = - deviceInfo.value!.rightEarCharging ? '$rightStatus ⚡' : rightStatus; - - return '${'leftEar'.tr}: $leftStatus / ${'rightEar'.tr}: $rightStatus'; // 左耳: xxx / 右耳: xxx - } - - String getCaseText() { - if (deviceInfo.value == null || - deviceInfo.value!.caseBattery <= 0 || - deviceInfo.value!.caseBattery > 100) { - return 'unknown'.tr; - } - - String caseStatus = '${deviceInfo.value!.caseBattery}%'; - if (deviceInfo.value!.caseCharging) { - caseStatus = '$caseStatus ⚡'; - } - - return '${'chargingCase'.tr}: $caseStatus'; // 充电仓: xxx - } - - String getChargingText() { - if (deviceInfo.value == null) { - return 'unknown'.tr; - } - - bool isCharging = deviceInfo.value!.leftEarCharging || - deviceInfo.value!.rightEarCharging || - deviceInfo.value!.caseCharging; - - return isCharging ? 'charging'.tr : 'notCharging'.tr; + final n = DeviceHub.to.lastKnownName; + return n.isNotEmpty ? n : 'unknownEquipment'.tr; } - /// 获取当前设备类型 - /// 返回设备类型,如果无法获取则返回未知类型 - DeviceType getCurrentDeviceType() { - try { - final deviceName = getDeviceName(); - if (deviceName == 'unknownEquipment'.tr) { - return DeviceType.unknown; - } - - // 通过AppConfig获取产品信息 - final product = AppConfig.getproduct(deviceName); - if (product != null) { - // 根据产品的devicetype字段返回对应的DeviceType - switch (product.devicetype) { - case 1: - return DeviceType.classicBluetoothHeadset; - case 2: - return DeviceType.bleBluetoothDoubleHeadset; - case 3: - return DeviceType.bleBluetoothSingleHeadset; - case 4: - return DeviceType.smartVoiceRecorder; - case 5: - return DeviceType.smartEye; - default: - return DeviceType.unknown; - } - } - - return DeviceType.unknown; - } catch (e) { - Logger.e(_tag, '获取设备类型失败: $e'); - return DeviceType.unknown; - } - } - - /// 判断当前设备是否为单端耳机 - bool isSingleHeadset() { - return getCurrentDeviceType() == DeviceType.bleBluetoothSingleHeadset || - getCurrentDeviceType() == DeviceType.smartVoiceRecorder || - getCurrentDeviceType() == DeviceType.smartEye; - } + String getDeviceId() => DeviceHub.to.primaryInfo.value?.macAddress ?? + DeviceHub.to.primaryInfo.value?.id ?? + 'unknown'.tr; String getVersionText() { - return deviceInfo.value?.firmwareVersion.isNotEmpty == true - ? deviceInfo.value!.firmwareVersion - : 'unknown'.tr; + final v = DeviceHub.to.primaryInfo.value?.firmwareVersion ?? ''; + return v.isNotEmpty ? v : 'unknown'.tr; } - // 移除了电池信息定时刷新相关方法 - - /// 检查OTA固件升级 - /// 在BLE连接成功后调用,检查是否需要升级 Future _checkOtaUpgrade() async { - Logger.d(_tag, '触发OTA升级检查...'); - - // 打印当前OTA检查状态(用于调试) - final status = _otaCheckService.getCheckStatus(); - Logger.d(_tag, 'OTA检查状态: $status'); - - // 使用全局OTA检查服务执行检查 - final success = - await _otaCheckService.performOtaCheck(_isFullyConnected.value); - - if (success) { - Logger.d(_tag, 'OTA检查已成功执行'); - } else { - Logger.d(_tag, 'OTA检查被跳过或执行失败'); - } - } - - /// 调试方法:获取OTA检查状态 - /// 可以在开发阶段用于调试 - Map getOtaCheckStatus() { - return _otaCheckService.getCheckStatus(); - } - - /// 获取当前设备的产品图片路径 - /// 如果没有配置产品图片或获取失败,返回null使用默认图片 - String? getCurrentDeviceImage() { - try { - final deviceName = getDeviceName(); - if (deviceName == 'unknownEquipment'.tr) { - Logger.d(_tag, '设备未知,使用默认图片'); - return null; - } - - // 通过AppConfig获取产品信息 - if (!AppConfig.isInitialized()) { - Logger.w(_tag, 'AppConfig未初始化,使用默认图片'); - return null; - } - - final product = AppConfig.getproduct(deviceName); - if (product != null && - product.productimage != null && - product.productimage!.isNotEmpty) { - Logger.d(_tag, '获取到设备产品图片: ${product.productimage}'); - _saveLastConnectedDeviceImage(product.productimage); - return product.productimage; - } else { - Logger.d(_tag, '设备 "$deviceName" 未配置产品图片,使用默认图片'); - return null; - } - } catch (e) { - Logger.e(_tag, '获取设备产品图片失败: $e'); - return null; - } + final success = await _otaCheckService.performOtaCheck(isFullyConnected); + Logger.d(_tag, success ? 'OTA检查已成功执行' : 'OTA检查被跳过或执行失败'); } - /// 获取设备图片的完整资源路径 - /// 处理网络图片URL和本地资源路径 - String getDeviceImagePath(bool isDarkMode) { - final productImage = getCurrentDeviceImage(); - - if (productImage != null) { - // 如果是网络图片URL - if (productImage.startsWith('http://') || - productImage.startsWith('https://')) { - return productImage; - } - // 如果是本地资源路径,确保以assets/开头 - else if (productImage.startsWith('assets/')) { - return productImage; - } - // 如果只是文件名,添加assets/images/前缀 - else { - return 'assets/images/$productImage'; - } - } - - // 使用默认耳机图片 - return 'assets/images/defaultPicture.png'; - } - - /// 判断是否为网络图片 - bool isNetworkImage(String imagePath) { - return imagePath.startsWith('http://') || imagePath.startsWith('https://'); - } + Map getOtaCheckStatus() => _otaCheckService.getCheckStatus(); } diff --git a/apps/client/lib/modules/login/controllers/login_controller.dart b/apps/client/lib/modules/login/controllers/login_controller.dart index 6dcd8eb2..89814752 100644 --- a/apps/client/lib/modules/login/controllers/login_controller.dart +++ b/apps/client/lib/modules/login/controllers/login_controller.dart @@ -789,7 +789,6 @@ class LoginController extends GetxController { 'getAppConfig: 产品[$i] ID=${product.id}, 设备名称="${product.devicename}"'); Logger().d( 'getAppConfig: 产品[$i] 厂商ID=${product.factoryid}, 设备类型=${product.devicetype}'); - Logger().d('getAppConfig: 产品[$i] 扫描UUID="${product.scanuuid}"'); Logger().d( 'getAppConfig: 产品[$i] 产品图片="${product.productimage ?? "未设置"}"'); Logger().d('getAppConfig: 产品[$i] 版本="${product.version ?? "未设置"}"'); @@ -819,9 +818,7 @@ class LoginController extends GetxController { // 验证AppConfig中的产品数据 final productNames = AppConfig.allproductNames(); - final productUuids = AppConfig.allproductUuids(); Logger().d('getAppConfig: 可用产品名称列表 = $productNames'); - Logger().d('getAppConfig: 可用产品UUID列表 = $productUuids'); Logger().d('getAppConfig: 应用配置获取和初始化成功完成'); diff --git a/apps/client/lib/modules/main_tab/views/tabs/ai_tab.dart b/apps/client/lib/modules/main_tab/views/tabs/ai_tab.dart index 3fbccb0a..3b87bd74 100644 --- a/apps/client/lib/modules/main_tab/views/tabs/ai_tab.dart +++ b/apps/client/lib/modules/main_tab/views/tabs/ai_tab.dart @@ -82,10 +82,8 @@ class AiTab extends StatelessWidget { final modules = service.enabledModules; final bool editing = tabCtrl.isEditingAi.value; // 三条链路任意一条连上都算已连接:之前只看了杰理那条, - // 恒玄耳机/蓝讯支架连上后依赖设备的卡片还是灰的。 - final bool connected = home.isFullyConnectedRx.value || - DeviceConnection.holderConnected || - DeviceConnection.besConnected; + // 恒玄耳机/EaiRec 支架连上后依赖设备的卡片还是灰的。 + final bool connected = DeviceConnection.any; if (modules.isEmpty) return _buildEmpty(isDarkMode, tabCtrl); diff --git a/apps/client/lib/modules/main_tab/views/tabs/device_tab.dart b/apps/client/lib/modules/main_tab/views/tabs/device_tab.dart index 2ec9333a..68b054b7 100644 --- a/apps/client/lib/modules/main_tab/views/tabs/device_tab.dart +++ b/apps/client/lib/modules/main_tab/views/tabs/device_tab.dart @@ -1,39 +1,36 @@ +import 'package:device_plugin_interface/device_plugin_interface.dart'; import 'package:flutter/material.dart'; -import '../../../../core/utils/device_connection.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:echomeet_device_sdk/echomeet_device_sdk.dart'; import 'package:get/get.dart'; +import '../../../../core/theme/app_palette.dart'; +import '../../../../core/utils/device_connection.dart'; import '../../../../data/models/user_Info.dart'; +import '../../../../devices/device_hub.dart'; import '../../../../routes/app_routes.dart'; -import '../../../home/controllers/home_controller.dart'; -import '../../../../data/services/holder_device_service.dart'; -import '../../../../data/services/bes_bluetooth_service.dart'; import '../widgets/battery_indicator.dart'; import '../widgets/tab_scaffold.dart'; -import '../../../../core/theme/app_palette.dart'; /// 设备页 /// /// 顶部标题栏左侧是「添加设备」的圆形加号;下面是设备图片展示区,图片四角 -/// 叠信息:右上=连接状态,左下=MAC + 授权码,右下=电量(单/双电池自适应)。 +/// 叠信息:右上=连接状态,左下=授权码,右下=MAC + 电量(单/双电池自适应)。 +/// +/// **不认厂商**:所有信息来自 [DeviceHub] 的主设备快照([DeviceInfo]), +/// 电量按 [DeviceBattery] 里有什么显示什么。 class DeviceTab extends StatelessWidget { const DeviceTab({Key? key}) : super(key: key); /// 设备图片区高度:不论连没连上都占住,避免连接前后布局跳动 static const double _imageAreaHeight = 300; - /// 底部信息(左下 MAC / 右下电量)的专属高度。 - /// - /// 这两块原先都贴在 `bottom: 0`,与居中的耳机主图压在一起、挡住图片下沿。 - /// 这里把它们下移到图片区之外:图片仍在上方 [_imageAreaHeight] 内居中 - /// (位置和大小都不变),整块区域高度加上这一段。 + /// 底部信息(左下授权码 / 右下电量)的专属高度,免得压在耳机主图上 static const double _bottomInfoInset = 28; @override Widget build(BuildContext context) { final bool isDarkMode = Theme.of(context).brightness == Brightness.dark; - final HomeController controller = Get.find(); + final hub = DeviceHub.to; return TabScaffold( slogan: 'sloganDevice'.tr, @@ -41,22 +38,14 @@ class DeviceTab extends StatelessWidget { leading: _buildAddButton(isDarkMode), titleOnRight: true, child: Obx(() { - // 三条设备通路都算「已连接」,彼此独立: - // 杰理耳机(BleManager)+ 蓝讯支架(echomeet SDK)+ 恒玄耳机(经典蓝牙) - final bool holderConnected = - Get.isRegistered() && - HolderDeviceService.to.connection.value == - EchoMeetConnectionState.connected; - final bool besConnected = Get.isRegistered() && - BesBluetoothService.to.deviceStatus.value == 2; - final bool connected = controller.isFullyConnectedRx.value || - holderConnected || - besConnected; + // revision 随任何会话的 info 变化 +1,读一下让 Obx 收集到它 + hub.revision.value; + final bool connected = hub.anyConnected.value; + final DeviceInfo? info = hub.primaryInfo.value; return ListView( padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), children: [ - _buildImageArea( - isDarkMode, connected, holderConnected, besConnected, controller), + _buildImageArea(isDarkMode, connected, info), SizedBox(height: 20.h), _buildEntry( isDarkMode: isDarkMode, @@ -67,13 +56,18 @@ class DeviceTab extends StatelessWidget { onTap: () => Get.toNamed(Routes.myDevices), ), SizedBox(height: 12.h), + // 固件升级入口**始终显示**:进去后由 DeviceOtaController 按 + // 「有没有在线设备 / 它有没有 otaPort」给出具体提示。 + // ⚠️ 别再按 `hub.has(DeviceCapability.ota)` 来显隐——那样写有个洞: + // 设备连着、但它不支持 OTA 时,「有能力」和「没连设备」两个分支 + // 都不满足,入口会**凭空消失**(2026-09-10 支架就这么丢过入口)。 _buildEntry( isDarkMode: isDarkMode, icon: Icons.system_update_alt, iconColor: AppPalette.warning, title: 'firmwareUpgrade'.tr, // 固件升级 - subtitle: 'bleHeadsetFirmwareUpgrade'.tr, // BLE耳机固件版本升级 - onTap: () => Get.toNamed(Routes.OTA_UPGRADE), + subtitle: 'bleHeadsetFirmwareUpgrade'.tr, + onTap: () => Get.toNamed(Routes.otaUpgrade), ), ], ); @@ -93,13 +87,10 @@ class DeviceTab extends StatelessWidget { width: 30.w, height: 30.w, decoration: BoxDecoration( - // 淡蓝底 + 深蓝加号:白色加号在 accentLight 上对比度只有 1.2:1, - // 换成 accent 才看得清(3.8:1,过了图形元素 3:1 的线)。 color: AppPalette.accentLight, shape: BoxShape.circle, boxShadow: [ BoxShadow( - // 底色淡了,投影跟着收一档,否则比按钮本身还重 color: AppPalette.accent.withOpacity(0.18), blurRadius: 8, offset: const Offset(0, 2), @@ -123,110 +114,56 @@ class DeviceTab extends StatelessWidget { } /// 设备图片展示区 + 四角信息浮层 - Widget _buildImageArea( - bool isDarkMode, - bool connected, - bool holderOn, - bool besOn, - HomeController controller, - ) { + Widget _buildImageArea(bool isDarkMode, bool connected, DeviceInfo? info) { return SizedBox( height: (_imageAreaHeight + _bottomInfoInset).h, child: Stack( children: [ - // 图片只占上方 _imageAreaHeight,底部那段留给 MAC / 电量, - // 免得信息压在耳机主图上 Positioned( left: 0, right: 0, top: 0, bottom: _bottomInfoInset.h, - child: Center( - child: _buildImage( - isDarkMode, connected, holderOn, besOn, controller)), + child: Center(child: _buildImage(connected)), ), - // 右上:连接状态 Positioned( right: 0, top: 0, child: _buildStatusChip(isDarkMode, connected), ), - // 左下:MAC + 授权码(支架模式下整块隐藏,信息在右下角) Positioned( left: 0, bottom: 0, - child: _buildIdentityInfo( - isDarkMode, connected, holderOn, besOn, controller), + child: _buildIdentityInfo(isDarkMode, connected, info), ), - // 右下:电量 Positioned( right: 0, bottom: 0, - child: _buildBatteryInfo( - isDarkMode, connected, holderOn, besOn, controller), + child: _buildBatteryInfo(isDarkMode, connected, info), ), ], ), ); } - Widget _buildImage(bool isDarkMode, bool connected, bool holderOn, - bool besOn, HomeController controller) { - // 蓝讯支架不在 AppConfig 的杰理产品表里,getDeviceImagePath 查不到会退回 - // defaultPicture(那张蓝色机器人图),这里直接用产品实拍图 - if (holderOn) { - // 按当前连接设备取主图——连哪台就显示哪台。 - // 取图逻辑统一在 DeviceConnection,固件升级页用的是同一份。 - return Image.asset( - DeviceConnection.currentAssetImage(), - fit: BoxFit.contain, - errorBuilder: (_, __, ___) => const SizedBox.shrink(), - ); - } - if (besOn) { - return Image.asset( + Widget _buildImage(bool connected) { + // 按当前(或最近连过的)设备取主图,取图逻辑统一在 DeviceConnection。 + // 断连后仍显示最近连接过的那台设备的图,只是整体压暗一点表示未连接; + // 从没连过任何设备时展示的是通用图,再压暗会让人以为是坏图。 + final bool dim = !connected && DeviceConnection.hasKnownDevice; + return Opacity( + opacity: dim ? 0.55 : 1.0, + child: Image.asset( DeviceConnection.currentAssetImage(), fit: BoxFit.contain, errorBuilder: (_, __, ___) => const SizedBox.shrink(), - ); - } - if (!connected) { - // 断连后仍显示最近连接过的那台设备的图,只是整体压暗一点表示未连接; - // 从没连过任何设备时才退回默认产品图。 - // 压暗只对「连过、现在断了」生效;从没连过设备时展示的是通用图, - // 再压暗会让人以为是坏图。 - final bool known = DeviceConnection.hasKnownDevice; - return Opacity( - opacity: known ? 0.55 : 1.0, - child: Image.asset( - DeviceConnection.currentAssetImage(), - fit: BoxFit.contain, - errorBuilder: (_, __, ___) => const SizedBox.shrink(), - ), - ); - } - final String path = controller.getDeviceImagePath(isDarkMode); - final bool isNetwork = controller.isNetworkImage(path); - if (!isNetwork) return Image.asset(path, fit: BoxFit.contain); - return Image.network( - path, - fit: BoxFit.contain, - // 网络图加载失败/加载中都退回本地参考图,避免出现破图图标; - // 手机支架已下架,通用兜底图统一用耳机图 - errorBuilder: (_, __, ___) => Image.asset( - DeviceConnection.currentAssetImage(), - fit: BoxFit.contain, ), - loadingBuilder: (context, child, progress) => progress == null - ? child - : const Center(child: CircularProgressIndicator(strokeWidth: 2)), ); } /// 右上角:设备已连接 / 未连接 Widget _buildStatusChip(bool isDarkMode, bool connected) { - final Color c = - connected ? AppPalette.success : AppPalette.brand400; + final Color c = connected ? AppPalette.success : AppPalette.brand400; return Container( padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 5.h), decoration: BoxDecoration( @@ -256,33 +193,14 @@ class DeviceTab extends StatelessWidget { ); } - /// 左下角:MAC 地址 + 授权码(license) - Widget _buildIdentityInfo(bool isDarkMode, bool connected, bool holderOn, - bool besOn, HomeController controller) { - if (!connected) return const SizedBox.shrink(); - // 支架 / 恒玄耳机模式下 MAC 已在右下角显示,左下角不再重复 - if (holderOn || besOn) return const SizedBox.shrink(); - final Color textColor = - isDarkMode ? Colors.white70 : AppPalette.brand500; - final String mac = controller.getDeviceId(); - final String license = _licenseForMac(mac); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - _infoLine(Icons.memory, mac, textColor), - // ⚠️ 没有授权码就整行不显示,**不要**退回显示「授权码未知」。 - // 经典蓝牙耳机(恒玄)这条链路压根没有授权码:绑定时 code 传空, - // 服务端是按 MAC 去 license 表反查的(api_binddevice.go), - // 所以 DBUserDivice.License 恒为空串。显示「未知」会让人以为 - // 「本该有、只是没读到」,跑去查一个根本不存在的东西。 - if (license.isNotEmpty) ...[ - SizedBox(height: 3.h), - _infoLine(Icons.vpn_key_outlined, license, textColor), - ], - ], - ); + /// 左下角:授权码(license)。没有就整行不显示——经典蓝牙耳机压根没有授权码, + /// 显示「未知」会让人以为「本该有、只是没读到」。 + Widget _buildIdentityInfo(bool isDarkMode, bool connected, DeviceInfo? info) { + if (!connected || info == null) return const SizedBox.shrink(); + final Color textColor = isDarkMode ? Colors.white70 : AppPalette.brand500; + final String license = _licenseForMac(info.macAddress ?? info.id); + if (license.isEmpty) return const SizedBox.shrink(); + return _infoLine(Icons.vpn_key_outlined, license, textColor); } Widget _infoLine(IconData icon, String text, Color color) { @@ -303,152 +221,83 @@ class DeviceTab extends StatelessWidget { ); } - /// 已绑定设备列表里按 MAC 找授权码(忽略冒号和大小写) + /// 已绑定设备列表里按 MAC 找授权码(忽略冒号和大小写)。 + /// + /// ⚠️ 授权码**等于 MAC** 时返回空串——那是后台「导入 MAC」模式留下的占位值, + /// 照显示会在设备页上出现两行一模一样的串(一行钥匙图标、一行 MAC), + /// 看着像同一个 MAC 显示了两遍。判据见 [UserDevice.hasRealLicense], + /// 与「我的设备」页共用同一份规则。 String _licenseForMac(String mac) { if (!User.isLoggedIn()) return ''; final key = mac.replaceAll(':', '').toUpperCase(); if (key.isEmpty) return ''; for (final d in User.instance.devices) { if (d.devicemac.replaceAll(':', '').toUpperCase() == key) { - return d.license; + return d.hasRealLicense ? d.license : ''; } } return ''; } - /// 右下角:电量。双电池(左右耳都有数据)显示两个电池,否则显示一个。 - Widget _buildBatteryInfo(bool isDarkMode, bool connected, bool holderOn, - bool besOn, HomeController controller) { - if (!connected) return const SizedBox.shrink(); - return Obx(() { - // 恒玄耳机:电量随 `BB 0A` 状态帧上报(左/右/仓分开,带充电位) - if (besOn) { - final Color c = - isDarkMode ? Colors.white70 : const Color(0xFF444444); - final bes = BesBluetoothService.to; - // ⚠️ 别直接用 connectedDeviceId:那在 iOS 上是 CoreBluetooth 的 - // peripheral UUID(每台 iPhone 都不一样),显示出来根本不是 MAC。 - // 耳机在 `BB 0A` 属性 7 里自报的地址两端一致,优先用它; - // 它要等一帧状态回包才有值,那之前先拿 connectedDeviceId 顶着 - // (Android 上本来就等于最终值,iOS 上会在收到帧后自动刷成真 MAC)。 - final reported = bes.deviceMac.value; - final mac = reported.isNotEmpty ? reported : bes.connectedDeviceId.value; - final battery = bes.batteryLevel.value; - final left = bes.batteryLeft.value; - final right = bes.batteryRight.value; - final box = bes.batteryCase.value; - if (mac.isEmpty && battery < 0) { - return const SizedBox.shrink(); - } - // 固件版本不在这里显示——固件升级页(Routes.OTA_UPGRADE)已经有了。 - // 也不套半透明底:直接压在耳机主图上。 - return Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - if (mac.isNotEmpty) _infoLine(Icons.memory, mac, c), - // 电量一行排开,顺序固定 C → L → R。 - // 每个都可能缺:盒电量只在耳机入盒时上报(属性 3 是可选的), - // 左右耳只有单侧数据时退化成一个不带标的电池。 - if (box >= 0 || left >= 0 || right >= 0 || battery >= 0) ...[ - SizedBox(height: 4.h), - Row( - mainAxisSize: MainAxisSize.min, - // 用 spacing 而不是手动插 SizedBox:只有 C 一个电池时, - // 尾随的间距会把它整体推离右边缘。 - spacing: 8.w, - children: [ - if (box >= 0) - BatteryIndicator( - level: box, - label: 'C', - isDarkMode: isDarkMode, - charging: bes.chargingCase.value, - ), - if (left >= 0 && right >= 0) ...[ - BatteryIndicator( - level: left, - label: 'L', - isDarkMode: isDarkMode, - charging: bes.chargingLeft.value, - ), - BatteryIndicator( - level: right, - label: 'R', - isDarkMode: isDarkMode, - charging: bes.chargingRight.value, - ), - ] else if (battery >= 0) - BatteryIndicator( - level: battery, - isDarkMode: isDarkMode, - charging: - bes.chargingLeft.value || bes.chargingRight.value, - ), - ], - ), - ], - ], - ); - } - // 蓝讯支架是单电池设备,直接用 SDK 上报的电量 - if (holderOn) { - final info = HolderDeviceService.to.deviceInfo.value; - final mac = HolderDeviceService.to.connectedAddress; - return Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - if (mac.isNotEmpty) ...[ - _infoLine(Icons.memory, mac, - isDarkMode ? Colors.white70 : const Color(0xFF444444)), - SizedBox(height: 4.h), - ], - BatteryIndicator( - level: info?.batteryLevel ?? 0, - isDarkMode: isDarkMode, - charging: info?.isCharging ?? false, - ), - ], - ); - } - - final int left = HomeController.leftEarBattery.value; - final int right = HomeController.rightEarBattery.value; - final bool dual = left > 0 || right > 0; - - if (dual) { - return Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - BatteryIndicator( - level: left, - label: 'L', - isDarkMode: isDarkMode, - charging: controller.leftEarCharging.value, - ), - SizedBox(height: 4.h), - BatteryIndicator( - level: right, - label: 'R', - isDarkMode: isDarkMode, - charging: controller.rightEarCharging.value, - ), - ], - ); - } + /// 右下角:MAC + 电量。电量按快照里有什么显示什么: + /// C → L → R 一行排开;只有单侧或单体设备退化成一个不带标的电池。 + Widget _buildBatteryInfo(bool isDarkMode, bool connected, DeviceInfo? info) { + if (!connected || info == null) return const SizedBox.shrink(); + final Color c = isDarkMode ? Colors.white70 : const Color(0xFF444444); + // ⚠️ 别直接用 id:那在 iOS 上是 CoreBluetooth 的 peripheral UUID。 + // macAddress 是设备自报/系统给的真 MAC,拿不到时先拿 id 顶着。 + final mac = info.macAddress ?? info.id; + final b = info.battery; + final int? box = b.caseBox; + final int? left = b.left; + final int? right = b.right; + final int? single = b.summary; + if (mac.isEmpty && single == null) return const SizedBox.shrink(); - // 单电池:优先整机电量,没有就用充电仓电量 - final info = controller.deviceInfo.value; - final int single = - (info?.batteryLevel ?? 0) > 0 ? info!.batteryLevel : controller.caseBattery.value; - return BatteryIndicator( - level: single, - isDarkMode: isDarkMode, - charging: controller.caseCharging.value, - ); - }); + return Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + if (mac.isNotEmpty) _infoLine(Icons.memory, mac, c), + if (single != null) ...[ + SizedBox(height: 4.h), + Row( + mainAxisSize: MainAxisSize.min, + spacing: 8.w, + children: [ + if (box != null) + BatteryIndicator( + level: box, + label: 'C', + isDarkMode: isDarkMode, + charging: b.chargingCase, + ), + if (left != null && right != null) ...[ + BatteryIndicator( + level: left, + label: 'L', + isDarkMode: isDarkMode, + charging: b.chargingLeft, + ), + BatteryIndicator( + level: right, + label: 'R', + isDarkMode: isDarkMode, + charging: b.chargingRight, + ), + ] else + BatteryIndicator( + level: single, + isDarkMode: isDarkMode, + charging: b.chargingLeft || + b.chargingRight || + b.chargingSingle, + ), + ], + ), + ], + ], + ); } Widget _buildEntry({ @@ -460,10 +309,8 @@ class DeviceTab extends StatelessWidget { Color iconColor = AppPalette.accent, }) { final Color cardBg = isDarkMode ? AppPalette.brand800 : Colors.white; - final Color titleColor = - isDarkMode ? Colors.white : AppPalette.brand900; - final Color subColor = - isDarkMode ? Colors.white60 : AppPalette.brand400; + final Color titleColor = isDarkMode ? Colors.white : AppPalette.brand900; + final Color subColor = isDarkMode ? Colors.white60 : AppPalette.brand400; return GestureDetector( behavior: HitTestBehavior.opaque, onTap: onTap, diff --git a/apps/client/lib/modules/main_tab/views/widgets/module_card.dart b/apps/client/lib/modules/main_tab/views/widgets/module_card.dart index 9be35771..119c31f6 100644 --- a/apps/client/lib/modules/main_tab/views/widgets/module_card.dart +++ b/apps/client/lib/modules/main_tab/views/widgets/module_card.dart @@ -1,16 +1,14 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import '../../../../routes/app_routes.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import '../../../../core/utils/ai_navigation.dart'; import '../../../../core/utils/id_verify_guard.dart'; import '../../../../core/utils/device_connection.dart'; import '../../../../core/utils/toast_throttle.dart'; -import '../../../../data/services/bes_bluetooth_service.dart'; +import '../../../../devices/device_hub.dart'; import '../../../../data/models/agent_module.dart'; -import '../../../home/controllers/home_controller.dart'; +import '../../../module_registry.dart'; import '../../../../core/theme/app_palette.dart'; /// 模块卡片的统一渲染 + 点击分发。 @@ -301,7 +299,7 @@ class ModuleSquareCard extends StatelessWidget { } } -/// 模块点击分发:复用 HomeController 里已有的跳转逻辑(含未连接设备的提示) +/// 模块点击分发:闸门在这里,跳转交给模块描述符 void launchModule(AgentModule module) { // 所有功能一律要求先实名(**游客同样走这条**,不再按游客身份拦死): // 未实名时拦下并直接弹认证窗,认证通过后用户再点一次即可 @@ -328,42 +326,18 @@ void launchModule(AgentModule module) { } // 每次进功能都刷一次耳机状态(版本/按键/EQ)——耳机可能在后台被摘下、 // 重连过或改过配置,只在连接时查一次会用到陈旧数据。 - if (DeviceConnection.besConnected) { - unawaited(BesBluetoothService.to.refreshDeviceState()); + if (DeviceConnection.any) { + unawaited(DeviceHub.to.refreshAll()); } - final home = Get.find(); - switch (module.id) { - case AgentModules.meeting: - home.openMeet(); - break; - case AgentModules.emaiAssistant: - // 与原来那颗 AI 球同一套跳转逻辑(按 agentType 走移动精灵或通用 agent 页) - navigateToAIAssistant(); - break; - case AgentModules.callRecording: - home.openCallRecording(); - break; - case AgentModules.fieldRecording: - home.openFieldRecording(); - break; - case AgentModules.textTranslation: - Get.toNamed(Routes.textTranslation); - break; - case AgentModules.pictureTranslation: - Get.toNamed(Routes.pictureTranslation); - break; - case AgentModules.simultaneous: - case AgentModules.faceToFace: - case AgentModules.call: - case AgentModules.audioVideo: - home.openTranslationFeature(module.id); - break; - default: - Get.snackbar( - module.title.tr, - 'featureNotWired'.tr, - snackPosition: SnackPosition.TOP, - duration: const Duration(seconds: 2), - ); + // 跳转由模块描述符自带(onLaunch / entryRoute),不再在这里 switch。 + // 找不到描述符或描述符没配跳转 = 模块忘了接线,直接提示而不是静默。 + final desc = ModuleRegistry.byId(module.id); + if (desc == null || !desc.launch()) { + Get.snackbar( + module.title.tr, + 'featureNotWired'.tr, + snackPosition: SnackPosition.TOP, + duration: const Duration(seconds: 2), + ); } } diff --git a/apps/client/lib/modules/meeting/controllers/meeting_home_controller.dart b/apps/client/lib/modules/meeting/controllers/meeting_home_controller.dart index 31f5f63a..55edea9a 100644 --- a/apps/client/lib/modules/meeting/controllers/meeting_home_controller.dart +++ b/apps/client/lib/modules/meeting/controllers/meeting_home_controller.dart @@ -12,7 +12,6 @@ import 'package:permission_handler/permission_handler.dart'; import '../../../core/utils/logger.dart'; import '../../../core/utils/synchrodata.dart'; -import '../../../data/services/ble_manager.dart'; import '../../../data/services/db/sqflite_api.dart'; import '../../../core/utils/permission_util.dart'; @@ -105,8 +104,6 @@ class MeetingHomeController extends GetxController { exitSelectionMode(); } - // 蓝牙服务 - final bleManager = Get.find(); late final Worker _updateListStateListener; late final Worker _localImportListener; diff --git a/apps/client/lib/modules/meeting/controllers/meeting_record_controller.dart b/apps/client/lib/modules/meeting/controllers/meeting_record_controller.dart index 5888dac9..b563f692 100644 --- a/apps/client/lib/modules/meeting/controllers/meeting_record_controller.dart +++ b/apps/client/lib/modules/meeting/controllers/meeting_record_controller.dart @@ -18,9 +18,8 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import '../../../routes/app_routes.dart'; import '../../../data/services/asr_service.dart'; -import '../../../data/services/ble_manager.dart'; import '../../../data/services/meeting/meeting_task_service.dart'; -import '../utils/jieli_call_recorder.dart'; +import '../../../data/services/device_stereo_recorder.dart'; /// 会议记录状态枚举 enum TimerStatus { @@ -335,7 +334,6 @@ class MeetingRecordController extends GetxController // 服务 final AsrService _asrService = Get.find(); - final BleManager _bleManager = Get.find(); // 流订阅 StreamSubscription? _recognitionSubscription; @@ -373,7 +371,7 @@ class MeetingRecordController extends GetxController // 移除了未使用的变量和TabController StreamSubscription? _audioDataSubscription; - JieliCallRecorder? _jieliCallRecorder; + DeviceStereoRecorder? _jieliCallRecorder; double _smoothedRms = 0.0; double _latestRms = 0.0; Timer? _waveformTimer; @@ -481,8 +479,6 @@ class MeetingRecordController extends GetxController if (Platform.isAndroid) { // Android 关掉 MediaProjection 前台服务;onClose 不能 await,所以 fire-and-forget。 unawaited(_asrService.stopScreenCapture()); - } else { - _bleManager.closeCodec(); } } final pendingJieli = _jieliCallRecorder; @@ -617,10 +613,9 @@ class MeetingRecordController extends GetxController } if (audioType.value == 2) { - // 通话录音:走 device_jieli 设备录音通路(deviceRecordStart → - // MODE_CALL_TRANSLATION_WITH_STEREO + ch=2 + STRATEGY_DEVICE_ALWAYS_RECORDING), - // 双声道交织 PCM(L=本端 / R=对端)直写 stereo WAV,不依赖手机真实通话状态。 - _jieliCallRecorder = JieliCallRecorder( + // 通话录音:走设备的通话双路通路(需要 callAudioTap 能力), + // 双声道交织 PCM(L=本端 / R=对端)直写 stereo WAV。 + _jieliCallRecorder = DeviceStereoRecorder( onWavePcm: _processAudioData, ); final ok = await _jieliCallRecorder!.start(filePath); @@ -687,15 +682,12 @@ class MeetingRecordController extends GetxController case 1: _asrService.setAudioConfig(sampleRate: 16000, channels: 1); // Android 上音视频录音改走 MediaProjection(在 _startRecording 已发起 - // 系统授权 + 启动前台服务),不再依赖蓝牙耳机的 A2DP 解码通路。 - if (!Platform.isAndroid) { - _bleManager.openDecoder(); - } + // 系统授权 + 启动前台服务);iOS 走录屏广播扩展。 break; case 2: // 通话录音走 device_jieli 设备录音通路(deviceRecordStart, // MODE_CALL_TRANSLATION_WITH_STEREO + ch=2 + ALWAYS_RECORDING), - // 由 JieliCallRecorder 在 Dart 层接管 stereo PCM 写入与 WAV 文件生成, + // 由 DeviceStereoRecorder 在 Dart 层接管 stereo PCM 写入与 WAV 文件生成, // 不再依赖 BleManager.openCallRecordDecoder(当前为空壳实现)。 break; } @@ -828,8 +820,6 @@ class MeetingRecordController extends GetxController if (audioType.value == 1) { if (Platform.isAndroid) { await _asrService.stopScreenCapture(); - } else { - _bleManager.closeCodec(); } } @@ -896,8 +886,6 @@ class MeetingRecordController extends GetxController if (audioType.value == 1) { if (Platform.isAndroid) { await _asrService.stopScreenCapture(); - } else { - _bleManager.closeCodec(); } } diff --git a/apps/client/lib/modules/meeting/controllers/mind_map_controller.dart b/apps/client/lib/modules/meeting/controllers/mind_map_controller.dart index 8b26f20d..229e704f 100644 --- a/apps/client/lib/modules/meeting/controllers/mind_map_controller.dart +++ b/apps/client/lib/modules/meeting/controllers/mind_map_controller.dart @@ -27,6 +27,8 @@ class MindMapController extends GetxController { @override void onInit() { super.onInit(); + final String summaryJs = + _jsString(_meetingDetailsController.meetingDetails.value.summary); String html = ''' @@ -120,26 +122,38 @@ class MindMapController extends GetxController { @@ -208,10 +232,20 @@ class MindMapController extends GetxController { _summaryNumberListener = ever(_meetingDetailsController.summaryNumberModifications, (value) { webViewController.runJavaScript( - 'updateMarkmap(`${_meetingDetailsController.meetingDetails.value.summary}`)'); + 'updateMarkmap(${_jsString(_meetingDetailsController.meetingDetails.value.summary)})'); }); } + /// 把任意文本编码成一个合法的 JS 字符串字面量。 + /// + /// ⚠️ 总结正文是大模型产出的 Markdown,里头出现反引号(行内代码、甚至整段 + /// ```markdown 包裹)是常事。原先直接拼进 JS 模板串 `${summary}`,一个反引号 + /// 就让整个 ` 会提前截断脚本块。 + static String _jsString(String value) => + jsonEncode(value).replaceAll(' HomeController.to.openMeet(), + pages: [ + GetPage( + name: Routes.meeting, + page: () => const MeetingView(), + binding: MeetingBinding(), + transition: Transition.rightToLeft, + transitionDuration: const Duration(milliseconds: 250), + ), + GetPage( + name: Routes.meetingDetails, + page: () => const MeetingDetailsView(), + binding: MeetingDetailsBinding(), + transition: Transition.rightToLeft, + transitionDuration: const Duration(milliseconds: 250), + ), + GetPage( + name: Routes.meetingConnect, + page: () => const MeetingConnectView(), + binding: MeetingConnectBinding(), + transition: Transition.rightToLeft, + transitionDuration: const Duration(milliseconds: 250), + ), + GetPage( + name: Routes.meetingRecord, + page: () => const MeetingRecordView(), + binding: MeetingRecordBinding(), + popGesture: false, + transition: Transition.rightToLeft, + transitionDuration: const Duration(milliseconds: 250), + ), + ], +); diff --git a/apps/client/lib/modules/meeting/views/meeting_home_view.dart b/apps/client/lib/modules/meeting/views/meeting_home_view.dart index 650a0857..8266526b 100644 --- a/apps/client/lib/modules/meeting/views/meeting_home_view.dart +++ b/apps/client/lib/modules/meeting/views/meeting_home_view.dart @@ -5,6 +5,7 @@ import 'package:get/get.dart'; import 'package:haptic_feedback/haptic_feedback.dart'; import '../../../core/theme/app_colors.dart'; +import '../../../data/services/device_file_import_service.dart'; import '../../../routes/app_routes.dart'; import '../controllers/meeting_home_controller.dart'; import '../model/meeting_model.dart'; @@ -59,6 +60,7 @@ class _MeetingHomeViewState extends State ], ), ), + _buildDeviceSyncBanner(isDarkMode), Expanded( child: _buildBody(context, isDarkMode), ), @@ -237,6 +239,61 @@ class _MeetingHomeViewState extends State ); } + /// 「正在从设备同步录音」条。空闲时整条不占位。 + /// + /// ⚠️ 这条**不是装饰**:支架的录音在 TF 卡上,靠 BLE 拉,一个十几分钟的录音 + /// 要好几分钟。没有进度提示的话,用户看到的就是「连上了、列表里什么都没有」, + /// 和坏了没有区别。 + Widget _buildDeviceSyncBanner(bool isDarkMode) { + if (!Get.isRegistered()) { + return const SizedBox.shrink(); + } + final svc = DeviceFileImportService.to; + return Obx(() { + if (!svc.isImporting.value) return const SizedBox.shrink(); + final pct = svc.progress.value; + final name = svc.currentFile.value; + final left = svc.pending.value; + return Container( + margin: EdgeInsets.symmetric(horizontal: 12.w), + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h), + decoration: BoxDecoration( + color: isDarkMode + ? MeetingUIUtils.getTranslucentWhite(0.05) + : MeetingUIUtils.getCardColor(isDarkMode), + borderRadius: BorderRadius.circular(12.r), + ), + child: Row( + children: [ + SizedBox( + width: 14.w, + height: 14.w, + // 设备没给总长度时 progress 是 -1,交给不确定态转圈,别画一个假的 0% + child: CircularProgressIndicator( + strokeWidth: 2, + value: pct >= 0 ? pct.clamp(0.0, 1.0) : null, + ), + ), + SizedBox(width: 10.w), + Expanded( + child: Text( + '${'importing'.tr} $name' + '${left > 1 ? ' ($left)' : ''}' + '${pct >= 0 ? ' ${(pct * 100).toStringAsFixed(0)}%' : ''}', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 12.sp, + color: isDarkMode ? Colors.white70 : Colors.black54, + ), + ), + ), + ], + ), + ); + }); + } + Widget _buildConnect(bool isDarkMode) { return GestureDetector( onTap: () { diff --git a/apps/client/lib/modules/module_descriptor.dart b/apps/client/lib/modules/module_descriptor.dart new file mode 100644 index 00000000..d7afba20 --- /dev/null +++ b/apps/client/lib/modules/module_descriptor.dart @@ -0,0 +1,75 @@ +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../data/models/agent_module.dart'; +export '../data/models/assistant_directive.dart' show DirectiveHandler; +import '../data/models/assistant_directive.dart'; + +/// Agent 能力模块的描述符——**模块自带行为**,不再靠中心 switch。 +/// +/// 一个模块 = `lib/modules//module.dart` 里导出的一个描述符, +/// 在 [ModuleRegistry] 里登记一行即可: +/// - 卡片元数据(沿用 [AgentModule]:标题/副标题/图标/渐变) +/// - [pages]:模块自带的路由,`AppPages` 会把它们拼进总表 +/// - [entryRoute] / [onLaunch]:卡片点击去哪(二选一,优先 onLaunch) +/// - [requiredCapabilities]:需要在线设备具备的能力,空 = 不依赖设备 +/// - [directives]:本模块能落地的端侧指令 +/// - [translations]:模块自带的文案(按 locale,如 `zh_CN` / `en_US`), +/// 与全局语言文件合并;新模块不必再去改 41 个语言文件 +/// - [registerServices]:需要常驻服务时在这里 `Get.put` +/// +/// `test/module_registry_test.dart` 守着:id 唯一、entryRoute 已注册、 +/// 标题文案有落点。 +class AgentModuleDescriptor extends AgentModule { + AgentModuleDescriptor({ + required super.id, + required super.title, + super.subtitle, + required super.icon, + required super.gradient, + this.requiredCapabilities = const {}, + super.comingSoon = false, + this.pages = const [], + this.entryRoute, + this.onLaunch, + this.directives = const {}, + this.translations = const {}, + this.registerServices, + super.bailianAppId, + }) : super(requiresDevice: requiredCapabilities.isNotEmpty); + + /// 需要在线设备具备的能力;空集合 = 手机自己就能用 + final Set requiredCapabilities; + + /// 模块自带的页面 + final List pages; + + /// 卡片点击跳转的路由(无 [onLaunch] 时用) + final String? entryRoute; + + /// 卡片点击的自定义动作(带闸门/提示逻辑的模块用它) + final VoidCallback? onLaunch; + + /// 端侧指令 → 处理器 + final Map directives; + + /// 模块自带文案:`{'zh_CN': {...}, 'en_US': {...}}` + final Map> translations; + + /// 常驻服务注册钩子(InitialBinding 之后调用一次) + final void Function()? registerServices; + + /// 卡片点击:优先 [onLaunch],其次 [entryRoute];都没有返回 false 让调用方兜底 + bool launch() { + if (onLaunch != null) { + onLaunch!(); + return true; + } + if (entryRoute != null) { + Get.toNamed(entryRoute!); + return true; + } + return false; + } +} diff --git a/apps/client/lib/modules/module_registry.dart b/apps/client/lib/modules/module_registry.dart new file mode 100644 index 00000000..9352832d --- /dev/null +++ b/apps/client/lib/modules/module_registry.dart @@ -0,0 +1,128 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../core/utils/logger.dart'; +import '../data/models/agent_module.dart'; +import 'call_recording/module.dart'; +import 'emai/module.dart'; +import 'meeting/module.dart'; +import 'module_descriptor.dart'; +import 'picture_translation/module.dart'; +import 'smartcar/module.dart'; +import 'text_translation/module.dart'; +import 'translation/module.dart'; + +/// **Agent 模块的唯一注册点。** +/// +/// 新增一个能力模块: +/// 1. 建 `lib/modules//`,在 `module.dart` 里导出一个 [AgentModuleDescriptor]; +/// 2. 在下面 [all] 里加一行。 +/// +/// 路由、卡片跳转、端侧指令、文案、常驻服务都由描述符自带, +/// 不用再去改 `app_pages.dart` / `module_card.dart` / `assistant_directive_service.dart` +/// / 41 个语言文件。 +class ModuleRegistry { + ModuleRegistry._(); + + static final List all = [ + meetingModule, + emaiModule, + ...translationModules, + ...callRecordingModules, + textTranslationModule, + pictureTranslationModule, + smartcarModule, + // ---------- 规划中(占位,方便测试增删) ---------- + AgentModuleDescriptor( + id: 'englishChat', + title: 'agentEnglishChat', + subtitle: 'agentEnglishChatDesc', + icon: Icons.chat_bubble_outline, + gradient: const [Color(0xFF7E57C2), Color(0xFF5E35B1)], + comingSoon: true, + ), + AgentModuleDescriptor( + id: 'englishStudy', + title: 'agentEnglishStudy', + subtitle: 'agentEnglishStudyDesc', + icon: Icons.menu_book, + gradient: const [Color(0xFF29B6F6), Color(0xFF0288D1)], + comingSoon: true, + ), + AgentModuleDescriptor( + id: 'kidsStory', + title: 'agentKidsStory', + subtitle: 'agentKidsStoryDesc', + icon: Icons.auto_stories, + gradient: const [Color(0xFFFF7043), Color(0xFFF4511E)], + comingSoon: true, + ), + ]; + + /// 启动时调用一次:把注册表交给 data 层的 [AgentModules], + /// AgentModuleService / 广场页 / 设备品类默认编排都从那里读。 + static void install() { + AgentModules.all = all; + } + + static AgentModuleDescriptor? byId(String id) { + for (final m in all) { + if (m.id == id) return m; + } + return null; + } + + /// 全部模块自带的页面(按 name 去重:同一模块的多个描述符共用一组页面) + static List get pages { + final seen = {}; + final out = []; + for (final m in all) { + for (final p in m.pages) { + if (seen.add(p.name)) out.add(p); + } + } + return out; + } + + /// 端侧指令 → 处理器。同名指令后注册的覆盖先注册的并报警。 + static Map get directiveHandlers { + final out = {}; + for (final m in all) { + for (final e in m.directives.entries) { + if (out.containsKey(e.key)) { + Logger.w('ModuleRegistry', '指令 ${e.key} 被 ${m.id} 重复注册,以后者为准'); + } + out[e.key] = e.value; + } + } + return out; + } + + /// 把各模块自带文案合并进全局语言表(模块的覆盖全局的同名 key)。 + static Map> mergeTranslations( + Map> base) { + final out = >{ + for (final e in base.entries) e.key: Map.from(e.value), + }; + for (final m in all) { + for (final loc in m.translations.entries) { + out.putIfAbsent(loc.key, () => {}).addAll(loc.value); + } + } + return out; + } + + /// 各模块的常驻服务注册。只跑一次。 + static bool _servicesRegistered = false; + static void registerServices() { + if (_servicesRegistered) return; + _servicesRegistered = true; + for (final m in all) { + try { + m.registerServices?.call(); + } catch (e) { + Logger.e('ModuleRegistry', '模块 ${m.id} 注册服务失败: $e'); + } + } + } +} diff --git a/apps/client/lib/modules/my_devices/controllers/my_devices_controller.dart b/apps/client/lib/modules/my_devices/controllers/my_devices_controller.dart index d7afca18..a9eed596 100644 --- a/apps/client/lib/modules/my_devices/controllers/my_devices_controller.dart +++ b/apps/client/lib/modules/my_devices/controllers/my_devices_controller.dart @@ -1,22 +1,22 @@ import 'dart:async'; +import 'package:device_plugin_interface/device_plugin_interface.dart'; import 'package:get/get.dart'; import '/core/utils/logger.dart'; import '/data/models/user_Info.dart'; -import '/data/services/ble_manager.dart'; -import '/data/services/bes_bluetooth_service.dart'; -import '/data/services/bes_device_auth.dart'; import '/data/services/network/api.dart'; +import '/devices/device_auth.dart'; +import '/devices/device_hub.dart'; import '/routes/app_routes.dart'; /// 用户已绑定设备管理页:拉取用户绑定列表、解绑。 +/// +/// 连接状态**只看本地蓝牙**([DeviceHub]),不问服务端——连接是此刻的链路状态, +/// 服务端存的是绑定关系,两回事。 class MyDevicesController extends GetxController { static const String _tag = 'MyDevicesController'; - late final BleManager _bleManager; - - /// 按设备类型分组的已绑定设备 /// 已绑定设备的平铺列表(一行一个产品,页面直接用这个) final RxList allDevices = [].obs; @@ -26,44 +26,31 @@ class MyDevicesController extends GetxController { final RxBool isLoading = false.obs; - /// 连接状态监听句柄,[onClose] 里要断掉 - final List _workers = []; + Worker? _revisionWorker; @override void onInit() { super.onInit(); - _bleManager = Get.find(); _refreshFromUser(); Future.microtask(loadDevices); - // 排序把「在线的排最前」,而在线与否是随时会变的链路状态——耳机可能在 - // 用户停在本页时才连上、或者被摘下断开。列表本身在 Obx 里,但 Obx 只 - // 收集到 allDevices 这一个可观察对象,**排序结果不会自己重算**, - // 必须在连接状态变化时重新跑一遍 _refreshFromUser。 - if (Get.isRegistered()) { - final bes = BesBluetoothService.to; - _workers.add(ever(bes.deviceStatus, (_) => _refreshFromUser())); - // deviceStatus 只说「连上了」,连的是哪台要看这两个:Android 上是 - // connectedDeviceId,iOS 上只能等耳机自报的 deviceMac 到达。 - _workers.add(ever(bes.connectedDeviceId, (_) => _refreshFromUser())); - _workers.add(ever(bes.deviceMac, (_) => _refreshFromUser())); - } + // 排序把「在线的排最前」,而在线与否是随时会变的链路状态——设备可能在 + // 用户停在本页时才连上、或者被摘下断开;iOS 上耳机自报的 MAC 也是晚一帧 + // 才到。列表本身在 Obx 里只收集到 allDevices,**排序结果不会自己重算**, + // 必须在设备状态变化时重新跑一遍 _refreshFromUser。 + _revisionWorker = ever(DeviceHub.to.revision, (_) => _refreshFromUser()); } @override void onClose() { - for (final w in _workers) { - w.dispose(); - } - _workers.clear(); + _revisionWorker?.dispose(); super.onClose(); } /// 从服务端拉取最新的设备列表,并刷新 [User.instance.devices]。 Future loadDevices() async { if (!User.isLoggedIn()) return; - // 本地已有数据就不要遮罩:onInit 里 _refreshFromUser() 已经拿本地列表渲染过 - // 一次了,再盖一层 loading 只会让用户对着转圈干等网络往返。 + // 本地已有数据就不要遮罩 isLoading.value = User.instance.devices.isEmpty; try { final response = await Api.getdevices(); @@ -85,19 +72,13 @@ class MyDevicesController extends GetxController { isLoading.value = false; } - // 补校当前连着的恒玄耳机(顺带完成绑定登记)。 - // 「先连耳机、后登录」是很常见的顺序,那时候连接事件里的登记会因为未登录 - // 而跳过;不在这里补一次,这台设备就要等下次重连才会出现在列表里。 - // - // ⚠️ 但**不能串在 getdevices 前面**:首次连接时白名单没命中,它会真的去打 - // user_binddevice(带 10s 超时),整个页面就得干等这一趟——表现就是 - // 「点设备页半天没响应」。放到列表渲染之后跑,页面立刻可见。 - // 它登记成功时会直接把设备塞进 User.instance.devices,所以回来刷一次就够, - // 不必再拉一遍 getdevices。 - unawaited(BesDeviceAuth.verifyConnected().then((_) => _refreshFromUser())); + // 补校当前连着的设备(顺带完成绑定登记)。「先连耳机、后登录」时连接事件里的 + // 登记会因为未登录而跳过;不在这里补一次,这台设备就要等下次重连才会出现。 + // ⚠️ 不能串在 getdevices 前面:首次连接会真的去打 user_binddevice(10s 超时)。 + unawaited(DeviceAuth.verifyConnected().then((_) => _refreshFromUser())); } - /// 解绑设备:调接口成功后从本地列表移除;如果是当前连接的设备,断开并跳到扫描页。 + /// 解绑设备:调接口成功后从本地列表移除;如果是当前连接的设备,断开并回主框架。 Future unbindDevice(UserDevice device) async { try { final response = await Api.unbinddevice({'id': device.id}); @@ -106,41 +87,22 @@ class MyDevicesController extends GetxController { User.instance.removeUserDevice(device.id); // 解绑要把这台在本地留下的痕迹一次清干净,两处缺一不可: - // 1. 确权白名单——不清的话下次连上会命中缓存、跳过 binddevice, - // 这台设备再也回不到列表里; - // 2. 已配对列表 + lastDevice——不清的话 tryAutoConnect 和原生 ACL 广播 - // 还会把它自动连回来,用户「解绑了但它还连着」。 - // removePairedDevice 内部会顺带断开当前连接。 - await BesDeviceAuth.forget(device.devicemac); - - // 解绑的是不是当前连着的那台恒玄耳机。 - // ⚠️ 判据不能只看 connectedDeviceId:iOS 上那是 CoreBluetooth 的 - // peripheral UUID,跟服务端记录里的真 MAC 永远对不上。耳机自报的 - // deviceMac 才是能把两边对应起来的值。必须在 removePairedDevice - // **之前**取,那之后连接已经被断开、这两个值都清空了。 - bool besWasCurrent = false; - if (device.devicemac.isNotEmpty && - Get.isRegistered()) { - final bes = BesBluetoothService.to; - final String t = device.devicemac.toUpperCase(); - besWasCurrent = bes.isConnected && - (bes.connectedDeviceId.value.toUpperCase() == t || - bes.deviceMac.value.toUpperCase() == t); - await bes.removePairedDevice(device.devicemac); + // 1. 确权白名单——不清的话下次连上会命中缓存、跳过 binddevice; + // 2. 各厂商的已配对列表——不清的话自动回连还会把它连回来。 + await DeviceAuth.forget(device.devicemac); + + // 解绑的是不是当前连着的那台:必须在 forgetDevice **之前**判,那之后连接已断 + final wasCurrent = isConnected(device); + final hub = DeviceHub.to; + for (final p in hub.plugins) { + // 每家插件按自己的标识删(恒玄同时认本地 id 与耳机自报 MAC) + await p.forgetDevice(device.devicemac); } _refreshFromUser(); - final bool jieliWasCurrent = device.devicemac.isNotEmpty && - _bleManager.currentDeviceAddress == device.devicemac; - if (jieliWasCurrent) { - await _bleManager.disconnect(); - } - // 恒玄那条的断开已由 removePairedDevice 做完,这里只负责离开本页 - if (jieliWasCurrent || besWasCurrent) { + if (wasCurrent) { Logger.i(_tag, '解绑的设备就是当前连接,已断开,回到主框架'); await Future.delayed(const Duration(milliseconds: 300)); - // 本页已去掉「添加设备」入口,解绑当前设备后回主框架, - // 让用户从设备页左上角重新走「选择设备 → 扫描」流程 Get.offAllNamed(Routes.home); } } catch (e) { @@ -160,40 +122,27 @@ class MyDevicesController extends GetxController { } devicesByType.value = grouped; devicesByType.refresh(); - // 在线的排最前,其余保持服务端返回的顺序。 - // - // ⚠️ 刻意用「两个桶拼起来」而不是 List.sort:Dart 的 sort **不保证稳定** - // (长度 <32 走插入排序碰巧稳定,再长就切到快排),拿它按 0/1 排会让 - // 离线设备的相对顺序每次刷新都可能变,看着像列表在乱跳。 + // 在线的排最前,其余保持服务端顺序。刻意用「两个桶拼起来」而不是 List.sort: + // Dart 的 sort 不保证稳定,拿它按 0/1 排会让离线设备的相对顺序每次刷新都变。 allDevices.assignAll([...online, ...offline]); } - /// 当前是不是正连着这一台。**只看本地蓝牙状态,不问服务端**—— - /// 连接是此刻的链路状态,服务端存的是绑定关系,两回事。 - /// - /// ⚠️ 原来只查了 [BleManager](杰理链路),而本项目实际用的是恒玄耳机, - /// 于是这里对所有设备恒为 false,列表上永远显示"未连接"。 + /// 当前是不是正连着这一台:比服务端记的 MAC 与在线会话的真实 MAC / 本地 id。 bool isConnected(UserDevice device) { if (device.devicemac.isEmpty) return false; final mac = device.devicemac.toUpperCase(); - if (Get.isRegistered()) { - final bes = BesBluetoothService.to; - // ⚠️ 两个值都要比,判据与 unbindDevice 里那段保持一致: - // connectedDeviceId 在 Android 上就是 MAC,在 iOS 上却是 CoreBluetooth - // 的 peripheral UUID,跟服务端记的真 MAC 永远对不上;耳机在 `BB 0A` - // 属性 7 里自报的 deviceMac 才是两端都能对上的那个。 - // 只比前者的话,iOS 上这里恒为 false —— 列表全显示未连接、排序也白排。 - if (bes.isConnected && - (bes.connectedDeviceId.value.toUpperCase() == mac || - bes.deviceMac.value.toUpperCase() == mac)) { - return true; - } + for (final s in DeviceHub.to.sessions) { + final info = s.info; + if ((info.macAddress ?? '').toUpperCase() == mac) return true; + if (info.id.toUpperCase() == mac) return true; + final localId = (info.metadata['localId'] as String?) ?? ''; + if (localId.isNotEmpty && localId.toUpperCase() == mac) return true; } - return _bleManager.isConnected && - _bleManager.currentDeviceAddress?.toUpperCase() == mac; + return false; } + /// 本页已去掉「添加设备」入口,跳品类选择页 void goToScan() { - Get.toNamed(Routes.devices); + Get.toNamed(Routes.deviceCategory); } } diff --git a/apps/client/lib/modules/my_devices/views/my_devices_view.dart b/apps/client/lib/modules/my_devices/views/my_devices_view.dart index 06520a06..7716b409 100644 --- a/apps/client/lib/modules/my_devices/views/my_devices_view.dart +++ b/apps/client/lib/modules/my_devices/views/my_devices_view.dart @@ -484,7 +484,7 @@ class MyDevicesView extends GetView { ), ], ), - if (_hasRealLicense(device) || device.cmei.isNotEmpty) ...[ + if (device.hasRealLicense || device.cmei.isNotEmpty) ...[ SizedBox(height: 14.h), Container( padding: EdgeInsets.all(12.w), @@ -496,12 +496,12 @@ class MyDevicesView extends GetView { ), child: Column( children: [ - if (_hasRealLicense(device)) + if (device.hasRealLicense) _buildFieldRow( label: 'licenseCode'.tr, value: device.license, isDark: isDark), - if (_hasRealLicense(device) && device.cmei.isNotEmpty) + if (device.hasRealLicense && device.cmei.isNotEmpty) SizedBox(height: 8.h), if (device.cmei.isNotEmpty) _buildFieldRow( @@ -515,20 +515,6 @@ class MyDevicesView extends GetView { ); } - /// 这台设备有没有「值得展示」的授权码。 - /// - /// ⚠️ 光判非空不够:服务端绑定时写的是**从 license 表查到的** code - /// (api_binddevice.go 的 `License: model.Code`,不是客户端传的空串), - /// 而后台「导入 MAC」模式建的授权码,code 就是 MAC 串本身。 - /// 于是界面上会出现 MAC 一行、授权码一行、两行值一模一样——看着像 bug。 - /// 这种占位值不展示;真授权码(如 71E5E5C3A797C043B5A7)照常展示。 - bool _hasRealLicense(UserDevice device) { - final lic = device.license.trim(); - if (lic.isEmpty) return false; - String norm(String v) => v.replaceAll(':', '').replaceAll('-', '').toUpperCase(); - return norm(lic) != norm(device.devicemac); - } - Widget _buildFieldRow({ required String label, required String value, diff --git a/apps/client/lib/modules/ota_upgrade/bindings/ota_upgrade_binding.dart b/apps/client/lib/modules/ota_upgrade/bindings/ota_upgrade_binding.dart index eabd8a5f..254023e7 100644 --- a/apps/client/lib/modules/ota_upgrade/bindings/ota_upgrade_binding.dart +++ b/apps/client/lib/modules/ota_upgrade/bindings/ota_upgrade_binding.dart @@ -1,11 +1,11 @@ import 'package:get/get.dart'; -import '../controllers/bes_ota_upgrade_controller.dart'; +import '../controllers/device_ota_controller.dart'; class OtaUpgradeBinding extends Bindings { @override void dependencies() { // 本项目只有恒玄耳机,固件升级走 BES 链路。杰理那版 OtaUpgradeController // 依赖 BleManager/Jielihome,已不再由路由装配。 - Get.lazyPut(() => BesOtaUpgradeController()); + Get.lazyPut(() => DeviceOtaController()); } } diff --git a/apps/client/lib/modules/ota_upgrade/controllers/device_ota_controller.dart b/apps/client/lib/modules/ota_upgrade/controllers/device_ota_controller.dart new file mode 100644 index 00000000..0ef9913e --- /dev/null +++ b/apps/client/lib/modules/ota_upgrade/controllers/device_ota_controller.dart @@ -0,0 +1,421 @@ +import 'dart:async'; + +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:wakelock_plus/wakelock_plus.dart'; + +import '../../../core/utils/logger.dart'; +import '../../../core/utils/version_compare.dart'; +import '../../../data/models/appconfig.dart'; +import '../../../data/models/appconfig_model.dart'; +import '../../../data/models/user_Info.dart'; +import '../../../data/services/network/api.dart'; +import '../../../devices/device_hub.dart'; +import 'ota_download_service.dart'; + +/// OTA 升级阶段(驱动页面 UI)。 +class OtaPhase { + static const idle = 0; // 待升级 + static const downloading = 1; // 下载固件中 + static const upgrading = 2; // 蓝牙推送中 + static const success = 3; // 升级成功 + static const failed = 4; // 升级失败 +} + +/// 固件 OTA 升级控制器——**厂商无关**。 +/// +/// 厂商差异全在 [DeviceOtaPort](恒玄要断 app 层 SPP 再由插件自管连接、完了再回连), +/// 这里只做:读产品配置 → 下载固件 → 交给端口推送 → 看门狗/常亮/终态锁定。 +/// +/// 流程:读产品配置 → 下载固件 → `port.start(file)` → 设备重启。 +class DeviceOtaController extends GetxController { + static const _tag = 'DeviceOtaController'; + + /// 看门狗超时:升级阶段超过该时长无任何进度或状态推进,即判定卡死失败。 + /// 兜底原生侧「既不推进也不上报 onError」导致 UI 永久停在升级中的情况。 + static const Duration _watchdogTimeout = Duration(seconds: 90); + + String _downloadUrl = ''; + bool _disposed = false; + CancelToken? _downloadCancelToken; + Timer? _watchdog; + + final OtaDownloadService _downloadService = OtaDownloadService(); + DeviceSession? _session; + DeviceOtaPort? _port; + StreamSubscription? _portSub; + StreamSubscription? _hubSub; + + // ---- 响应式状态 ---- + final RxString currentVersion = ''.obs; + final RxString latestVersion = ''.obs; + final RxString updateDescription = ''.obs; + final RxBool isUpdateAvailable = false.obs; + final RxBool isConnected = true.obs; + + /// 设备名快照:升级中 app 层连接会被端口主动断开,页面用自己的快照 + final RxString deviceName = ''.obs; + + final RxInt phase = OtaPhase.idle.obs; + final RxDouble downloadProgress = 0.0.obs; // 0~1 + final RxDouble otaProgress = 0.0.obs; // 0~1 + final RxString detailedStatus = ''.obs; + + Worker? _sessionsWorker; + + bool get isBusy => + phase.value == OtaPhase.downloading || phase.value == OtaPhase.upgrading; + + @override + void onInit() { + super.onInit(); + final hub = DeviceHub.to; + _bindSession(hub.sessionWith(DeviceCapability.ota)); + // 跟踪 app 层连接状态(仅用于展示与按钮可用性)。 + // 注意:OTA 连接由端口自管、掉线会经 progressStream 上报;开始升级时 app 层 + // 连接是端口主动断开的,不能拿它的断开去中止 OTA。 + _sessionsWorker = ever>(hub.sessions, (_) { + final s = hub.sessionWith(DeviceCapability.ota); + isConnected.value = s != null; + if (s != null && !identical(s, _session)) _bindSession(s); + }); + _hubSub = hub.sessionEvents.listen((e) { + if (e.type != DeviceSessionEventType.deviceInfoUpdated) return; + final s = _session; + if (s == null || e.deviceId != s.deviceId) return; + final fw = e.deviceInfo?.firmwareVersion ?? ''; + // 开始升级时主动断开会把版本清空,空值忽略,保留页面上已知的版本 + if (fw.isNotEmpty && fw != currentVersion.value) { + currentVersion.value = fw; + _refreshUpdateAvailable(); + } + final n = e.deviceInfo?.name ?? ''; + if (n.isNotEmpty && n != deviceName.value) { + deviceName.value = n; + _loadProductConfig(); + } + }); + unawaited(_ensureBoundDevicesLoaded()); + } + + /// 产品匹配要用绑定关系里的 productid(见 [_findProduct]),而 + /// `User.instance.devices` 只有在连接时登记成功、或用户进过「设备管理」页 + /// 之后才有值。**直接从设备页进固件升级时它可能是空的**,那样就退回名字匹配、 + /// 又匹配不上,页面照旧报「未找到产品配置」。所以这里补拉一次。 + Future _ensureBoundDevicesLoaded() async { + if (!User.isLoggedIn()) return; + if (User.instance.devices.isNotEmpty) return; + try { + final resp = await Api.getdevices(); + final list = resp?['devices'] as List?; + if (list == null || list.isEmpty) return; + User.instance.devices = list + .map((e) => UserDevice.fromJson(e as Map)) + .toList(); + if (_disposed) return; + Logger.i(_tag, '补拉已绑定设备 ${User.instance.devices.length} 条,重算产品配置'); + _loadProductConfig(); + } catch (e) { + // 拉不到就退回名字匹配,不影响页面其它部分 + Logger.w(_tag, '补拉已绑定设备失败: $e'); + } + } + + void _bindSession(DeviceSession? s) { + _session = s; + isConnected.value = s != null; + if (s == null) return; + final fw = s.info.firmwareVersion ?? ''; + if (fw.isNotEmpty) currentVersion.value = fw; + if (s.info.name.isNotEmpty) deviceName.value = s.info.name; + _loadProductConfig(); + } + + @override + void onClose() { + _disposed = true; + _downloadCancelToken?.cancel('page closed'); + _cancelWatchdog(); + _setKeepScreenOn(false); + _portSub?.cancel(); + _sessionsWorker?.dispose(); + _hubSub?.cancel(); + // 端口负责释放链路并把设备交还给正常会话(恒玄:stopOta 后延时回连) + _port?.close(); + _port = null; + super.onClose(); + } + + /// 从后端产品配置取最新固件版本与下载地址(按设备名匹配产品)。 + void _loadProductConfig() { + final product = _findProduct(deviceName.value); + if (product == null) { + Logger.w(_tag, '未找到设备对应的产品配置: ${deviceName.value}'); + latestVersion.value = ''; + updateDescription.value = ''; + _downloadUrl = ''; + } else { + latestVersion.value = product.version?.split('+').first.trim() ?? ''; + updateDescription.value = product.updatedescription ?? ''; + _downloadUrl = product.updatepackageaddress ?? ''; + Logger.i( + _tag, + '产品配置: name=${product.devicename} pid=${product.id} ' + '服务端最新=${product.version} → 解析后=${latestVersion.value} ' + '设备当前=${currentVersion.value} ' + '产品表共${AppConfig.config.products.length}个'); + } + _refreshUpdateAvailable(); + } + + bool get _allowDowngrade => + _findProduct(deviceName.value)?.updateonmismatch ?? false; + + /// 找这台设备对应的产品配置。**先按绑定关系里的 productid,再退回名字匹配。** + /// + /// ⚠️ 名字匹配靠不住:支架广播名是 `Echomeet`,产品表里叫 `EaiRec`, + /// 两者互不包含 —— 于是固件升级页恒报「未找到设备对应的产品配置」, + /// 一次服务端读取都不会发生(2026-09-10 真机复现)。 + /// `user_binddevice` / `user_getdevices` 返回的 `productid` 是服务端 + /// 从全局 `device_mac` 表命中行读出来的**权威值**,按 MAC 对得上就用它。 + /// + /// ⚠️ 不要用 [AppConfig.getproduct]——它内部 `firstWhere` 没有 orElse, + /// 查不到直接抛 StateError,而调用点写的都是 `if (product == null)`。 + DBProduct? _findProduct(String name) { + if (!AppConfig.isInitialized()) return null; + final products = AppConfig.config.products; + if (products.isEmpty) return null; + + // ① 绑定关系里的 productid(权威) + final pid = _boundProductId(); + if (pid != null) { + for (final p in products) { + if (p.id == pid) return p; + } + Logger.w(_tag, '绑定关系给的 pid=$pid 不在本应用产品表里,退回按名字匹配'); + } + + // ② 设备名与产品名互相包含(老口径,保留给还没绑上的设备) + final n = name.trim().toUpperCase(); + if (n.isNotEmpty && n != 'UNKNOWNEQUIPMENT') { + for (final p in products) { + final pn = p.devicename.trim().toUpperCase(); + if (pn.isEmpty) continue; + if (pn.contains(n) || n.contains(pn)) return p; + } + } + return null; + } + + /// 当前设备在「我的设备」里登记的 productid。没登录/没绑定/拿不到 MAC 返回 null。 + /// + /// MAC 比对忽略冒号与大小写:服务端存的和设备上报的写法不一定一致。 + int? _boundProductId() { + if (!User.isLoggedIn()) return null; + final info = _session?.info; + final mac = (info?.macAddress ?? info?.id ?? '') + .replaceAll(':', '') + .toUpperCase(); + if (mac.isEmpty) return null; + for (final d in User.instance.devices) { + if (d.devicemac.replaceAll(':', '').toUpperCase() == mac) { + return d.productid; + } + } + return null; + } + + void _refreshUpdateAvailable() { + final cur = currentVersion.value.trim(); + final latest = latestVersion.value.trim(); + if (latest.isEmpty) { + isUpdateAvailable.value = false; + return; + } + // 读不到当前版本时允许升级(未知 → 允许) + if (cur.isEmpty) { + isUpdateAvailable.value = true; + return; + } + // 判定口径由后台产品配置决定:updateonmismatch=true → 不一致就允许(可刷回旧固件); + // false/null → 只有服务端版本更高才允许(正式,默认) + isUpdateAvailable.value = + _allowDowngrade ? latest != cur : _isNewer(latest, cur); + } + + /// 入口:开始升级(下载 → 交给端口推送)。 + Future startUpdate() async { + if (isBusy) return; + final session = _session ?? DeviceHub.to.sessionWith(DeviceCapability.ota); + if (session == null || session.state != DeviceConnectionState.ready) { + _snack('otaError'.tr, 'otaNeedConnect'.tr); + return; + } + final port = session.otaPort(); + if (port == null) { + _snack('otaError'.tr, 'otaNeedConnect'.tr); + return; + } + _session = session; + + if (_downloadUrl.isEmpty) { + _loadProductConfig(); + if (_downloadUrl.isEmpty) { + _snack('otaError'.tr, 'otaVersionInfoFailed'.tr); + return; + } + } + + final cancelToken = CancelToken(); + _downloadCancelToken = cancelToken; + + try { + _setKeepScreenOn(true); + phase.value = OtaPhase.downloading; + downloadProgress.value = 0; + otaProgress.value = 0; + detailedStatus.value = 'otaPreparing'.tr; + + // 1) 下载固件(端口 start 时才断链路,下载期间设备照常连着) + final filePath = await _downloadService.downloadFirmware( + downloadUrl: _downloadUrl, + cancelToken: cancelToken, + onProgress: (p) => downloadProgress.value = p, + onStatusUpdate: (s) => detailedStatus.value = s, + ); + if (_disposed || cancelToken.isCancelled) return; + + // 2) 交给端口推送 + phase.value = OtaPhase.upgrading; + detailedStatus.value = 'otaConnectingDevice'.tr; + _port = port; + _portSub?.cancel(); + _portSub = port.progressStream.listen(_onProgress, onError: (Object e) { + _onUpgradeError(e.toString()); + }); + _armWatchdog(); + await port.start(DeviceOtaFileRequest(filePath: filePath)); + } catch (e, st) { + if (_disposed || (e is DioException && CancelToken.isCancel(e))) return; + Logger.e(_tag, '升级流程异常', e, st); + _onUpgradeError(e.toString()); + } + } + + void _onProgress(DeviceOtaProgress p) { + // 进入终态即锁定,迟到的事件一律忽略 + if (phase.value == OtaPhase.success || phase.value == OtaPhase.failed) { + return; + } + _armWatchdog(); + switch (p.state) { + case DeviceOtaState.transferring: + phase.value = OtaPhase.upgrading; + if (p.percent >= 0) _updateProgress(p.percent / 100); + break; + case DeviceOtaState.done: + _onUpgradeSuccess(); + break; + case DeviceOtaState.failed: + _onUpgradeError(p.errorMessage ?? p.errorCode ?? 'failed'); + break; + case DeviceOtaState.cancelled: + _cancelWatchdog(); + _setKeepScreenOn(false); + phase.value = OtaPhase.idle; + detailedStatus.value = ''; + break; + default: + break; + } + } + + /// 取消升级。 + void cancel() { + _downloadCancelToken?.cancel('user cancelled'); + _cancelWatchdog(); + _port?.cancel(); + _setKeepScreenOn(false); + phase.value = OtaPhase.idle; + detailedStatus.value = ''; + downloadProgress.value = 0; + otaProgress.value = 0; + } + + void _armWatchdog() { + if (_disposed) return; + _watchdog?.cancel(); + _watchdog = Timer(_watchdogTimeout, _onWatchdogTimeout); + } + + void _cancelWatchdog() { + _watchdog?.cancel(); + _watchdog = null; + } + + void _onWatchdogTimeout() { + if (_disposed) return; + if (phase.value == OtaPhase.upgrading) { + Logger.w(_tag, 'OTA 看门狗超时:${_watchdogTimeout.inSeconds}s 无进度推进'); + _onUpgradeError('otaTimeout'.tr); + } + } + + void _setKeepScreenOn(bool on) { + try { + on ? WakelockPlus.enable() : WakelockPlus.disable(); + } catch (e) { + Logger.w(_tag, '设置屏幕常亮失败: $e'); + } + } + + /// 进度的单一写入口:只在单调递增时刷新 + void _updateProgress(double p) { + if (p <= otaProgress.value) return; + otaProgress.value = p; + detailedStatus.value = 'otaUpgrading'.trParams({ + 'percent': (p * 100).toStringAsFixed(2), + }); + } + + void _onUpgradeSuccess() { + _cancelWatchdog(); + _setKeepScreenOn(false); + phase.value = OtaPhase.success; + otaProgress.value = 1.0; + detailedStatus.value = 'otaSuccessReboot'.tr; + currentVersion.value = latestVersion.value; + isUpdateAvailable.value = false; + } + + void _onUpgradeError(String? message) { + if (phase.value == OtaPhase.failed) return; + _cancelWatchdog(); + _setKeepScreenOn(false); + phase.value = OtaPhase.failed; + _port?.cancel(); + detailedStatus.value = 'otaFailed'.tr; + _snack( + 'otaFailed'.tr, + message?.isNotEmpty == true + ? message! + : 'otaFailedWithCode'.trParams({'code': '-1'}), + ); + } + + void _snack(String title, String msg) { + Get.snackbar( + title, + msg, + snackPosition: SnackPosition.TOP, + backgroundColor: Colors.red[400], + colorText: Colors.white, + margin: const EdgeInsets.all(12), + duration: const Duration(seconds: 3), + ); + } + + bool _isNewer(String a, String b) => VersionCompare.isNewer(a, b); +} diff --git a/apps/client/lib/modules/ota_upgrade/controllers/ota_download_service.dart b/apps/client/lib/modules/ota_upgrade/controllers/ota_download_service.dart index 48ff5ead..d63a47e4 100644 --- a/apps/client/lib/modules/ota_upgrade/controllers/ota_download_service.dart +++ b/apps/client/lib/modules/ota_upgrade/controllers/ota_download_service.dart @@ -8,10 +8,10 @@ import 'package:path_provider/path_provider.dart'; import '../../../core/utils/logger.dart'; -/// 恒玄(BES) OTA 固件下载服务 +/// OTA 固件下载服务(厂商无关) /// /// 用 Dio 把固件包下载到应用支持目录,提供进度/状态回调,并做"同名复用 + 清旧文件"。 -class BesOtaDownloadService { +class OtaDownloadService { static const _tag = 'BesOtaDownloadService'; static const _dirName = 'ota_upgrades'; @@ -27,7 +27,7 @@ class BesOtaDownloadService { late final Dio _dio; - BesOtaDownloadService() { + OtaDownloadService() { _dio = Dio( BaseOptions( connectTimeout: const Duration(seconds: 30), diff --git a/apps/client/lib/modules/ota_upgrade/views/device_ota_view.dart b/apps/client/lib/modules/ota_upgrade/views/device_ota_view.dart index b4045473..63977810 100644 --- a/apps/client/lib/modules/ota_upgrade/views/device_ota_view.dart +++ b/apps/client/lib/modules/ota_upgrade/views/device_ota_view.dart @@ -3,10 +3,10 @@ import '../../../core/utils/device_connection.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import '../controllers/bes_ota_upgrade_controller.dart'; +import '../controllers/device_ota_controller.dart'; -class BesOtaUpgradeView extends GetView { - const BesOtaUpgradeView({super.key}); +class DeviceOtaView extends GetView { + const DeviceOtaView({super.key}); static const _accent = Color(0xFF009688); static const _accentBg = Color(0xFFE0F2F1); diff --git a/apps/client/lib/modules/ota_upgrade/views/ota_upgrade_popup_view.dart b/apps/client/lib/modules/ota_upgrade/views/ota_upgrade_popup_view.dart index 350b1cc6..a82f5ccb 100644 --- a/apps/client/lib/modules/ota_upgrade/views/ota_upgrade_popup_view.dart +++ b/apps/client/lib/modules/ota_upgrade/views/ota_upgrade_popup_view.dart @@ -80,7 +80,7 @@ class OtaUpgradePopUp { ElevatedButton( onPressed: () { Get.back(); - Get.offAllNamed(Routes.devices); + Get.offAllNamed(Routes.deviceCategory); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.green[600], diff --git a/apps/client/lib/modules/picture_translation/module.dart b/apps/client/lib/modules/picture_translation/module.dart new file mode 100644 index 00000000..2ed396d0 --- /dev/null +++ b/apps/client/lib/modules/picture_translation/module.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../routes/app_routes.dart'; +import '../module_descriptor.dart'; +import 'bindings/picture_translation_binding.dart'; +import 'views/picture_translation_view.dart'; + +/// 拍照翻译 +final AgentModuleDescriptor pictureTranslationModule = AgentModuleDescriptor( + id: 'pictureTranslation', + title: 'agentPictureTranslation', + subtitle: 'agentPictureTranslationDesc', + icon: Icons.image_search, + gradient: const [Color(0xFFEC407A), Color(0xFFAD1457)], + entryRoute: Routes.pictureTranslation, + pages: [ + GetPage( + name: Routes.pictureTranslation, + page: () => const PictureTranslationView(), + binding: PictureTranslationBinding(), + transition: Transition.rightToLeft, + transitionDuration: const Duration(milliseconds: 250), + ), + ], +); diff --git a/apps/client/lib/modules/settings/controllers/settings_controller.dart b/apps/client/lib/modules/settings/controllers/settings_controller.dart index b172f861..f18d8fe2 100644 --- a/apps/client/lib/modules/settings/controllers/settings_controller.dart +++ b/apps/client/lib/modules/settings/controllers/settings_controller.dart @@ -1,7 +1,6 @@ import 'dart:async'; import '/data/services/background_launch_consent.dart'; -import '/data/services/bes_bluetooth_service.dart'; -import '/data/services/holder_device_service.dart'; +import '/devices/device_hub.dart'; import 'package:agent_service/agent_service.dart'; import 'package:get/get.dart'; @@ -66,12 +65,7 @@ class SettingsController extends GetxController { autoConnectEnabled.value = false; // 注销系统级后台扫描:不注销的话设备一靠近还是会把 App 唤醒 try { - if (Get.isRegistered()) { - await HolderDeviceService.to.disconnect(); - } - if (Get.isRegistered()) { - await BesBluetoothService.to.disconnectDevice(); - } + await DeviceHub.to.disconnectAll(); } catch (e) { debugPrint('关闭自动连接时断开设备失败: $e'); } diff --git a/apps/client/lib/modules/settings/views/settings_view.dart b/apps/client/lib/modules/settings/views/settings_view.dart index 47451c31..dc8a4277 100644 --- a/apps/client/lib/modules/settings/views/settings_view.dart +++ b/apps/client/lib/modules/settings/views/settings_view.dart @@ -537,26 +537,6 @@ class SettingsView extends GetView { // ? Colors.white.withOpacity(0.1) // : Colors.grey[200]), - Obx(() => controller.showDebugInfo.value - ? _buildSimpleNavigationSetting( - title: 'opus解码测试', - subtitle: '测试opus解码', - icon: Icons.bluetooth_searching, - iconBgColor: isDarkMode - ? Colors.green[900]!.withValues(alpha: 0.3) - : Colors.green[100]!, - iconColor: isDarkMode - ? Colors.green[300]! - : Colors.green[600]!, - titleColor: isDarkMode ? Colors.white : null, - subtitleColor: isDarkMode ? Colors.white70 : null, - onTap: () { - Get.toNamed(Routes.opusTest); - }, - isDarkMode: isDarkMode, - ) - : const SizedBox.shrink()), - Obx(() => controller.showDebugInfo.value ? _buildSimpleNavigationSetting( title: '恒玄蓝牙测试', diff --git a/apps/client/lib/modules/smartcar/bindings/smartcar_chat_binding.dart b/apps/client/lib/modules/smartcar/bindings/smartcar_chat_binding.dart new file mode 100644 index 00000000..db732f24 --- /dev/null +++ b/apps/client/lib/modules/smartcar/bindings/smartcar_chat_binding.dart @@ -0,0 +1,48 @@ +import 'package:get/get.dart'; + +import '../../../data/services/bailian_multimodal_service.dart'; +import '../../emai/controllers/emai_controller.dart'; + +/// Smartcar 车载助手的依赖装配。 +/// +/// 复用 EMAI 那套对话 UI 与控制器,只把「连哪个百炼应用」换掉: +/// 这里 put 一个带 Smartcar 专属 app_id 的 [BailianMultimodalService], +/// 再用它构造一个同 tag 的 [EmaiController]。 +/// +/// ⚠️ **两者都必须带 tag**:不带 tag 会覆盖掉全局那个 EMAI 用的实例, +/// 表现为退出车载助手后 EMAI 也连到了车载的应用上。 +/// `EmaiView(controllerTag: kSmartcarTag)` 靠同一个 tag 取到这里的控制器。 +/// +/// ⚠️ **service 必须是独立实例**,不能 `Get.find` 全局那个: +/// `BailianMultimodalService.start()` 第一件事就是 `stop()`,共用会让两个 agent +/// 互相把对方的会话掐掉,下行音频还会串到对方的播放器上。 +class SmartcarChatBinding extends Bindings { + @override + void dependencies() { + if (!Get.isRegistered(tag: kSmartcarTag)) { + Get.put( + BailianMultimodalService(appId: kSmartcarBailianAppId), + tag: kSmartcarTag, + permanent: true, + ); + } + Get.lazyPut( + () => EmaiController( + service: Get.find(tag: kSmartcarTag), + ), + tag: kSmartcarTag, + ); + } +} + +/// GetX 实例 tag:service 与 controller 共用这一个 +const String kSmartcarTag = 'smartcar'; + +/// Smartcar 车载助手在百炼里的多模态应用 ID(workspace 与 EMAI 同一个, +/// 所以不覆盖 workspaceId,让它走全局配置)。 +/// +/// ⚠️ 写死在客户端是**有意选的**(落地文档 6.3 方案 A):换 app_id 要发版。 +/// 等运营提出「要后台随时改」时,再改成从 `DBAgent.serviceData` 下发—— +/// 那时要给客户端手写镜像补 `source` / `serviceData` 两个字段,且**必须 nullable**, +/// 否则老后端不下发就整个 `fromJson` 抛 TypeError、应用配置全空白。 +const String kSmartcarBailianAppId = 'mm_dd1eb7cb06484aafb94a0b6b2dff'; diff --git a/apps/client/lib/modules/smartcar/module.dart b/apps/client/lib/modules/smartcar/module.dart new file mode 100644 index 00000000..9e044cbc --- /dev/null +++ b/apps/client/lib/modules/smartcar/module.dart @@ -0,0 +1,130 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../routes/app_routes.dart'; +import '../emai/views/emai_view.dart'; +import '../module_descriptor.dart'; +import 'bindings/smartcar_chat_binding.dart'; + +/// Smartcar 车载助手(Smartcar 车载香薰的随身对话 agent) +/// +/// 与 EMAI 共用同一套对话 UI 和控制器,差别只有一个:连的是百炼里**另一个应用** +/// (见 [kSmartcarBailianAppId])。所以这里直接复用 [EmaiView],靠 `controllerTag` +/// 取到 [SmartcarChatBinding] 装配的那份带专属 app_id 的实例。 +/// +/// ⚠️ **没有声明 `requiredCapabilities`**:这个 agent 手机自己就能聊,不必连着香薰 +/// (产品定位是"随时开聊")。设备连上时它会被自动铺到 AI 页首位,那是 +/// `AgentModules.defaultsByCategory[carAroma]` 的事,与本字段无关。 +/// +/// ⚠️ **对话记录与 EMAI 共用 `EmaiChatStore`**:设备按键唤醒的轮次由 +/// `DeviceAiSessionService` 写进那个 store,页面不开也能收;这里若另起一个 store, +/// 设备发起的对话就不会出现在本页上。要拆分历史得连 `DeviceAiSessionService` +/// 一起改,本期不做。 +final AgentModuleDescriptor smartcarModule = AgentModuleDescriptor( + id: 'smartcarChat', + title: 'agentSmartcar', + subtitle: 'agentSmartcarDesc', + // 卡片图标只支持 IconData(module_card 里是 Icon(module.icon) 套渐变块), + // 用不了产品图 Smartcar_icon.png。要用图得给 AgentModule 加字段并改 module_card, + // 那是耳机/支架共用的卡片组件,本期不动。 + icon: Icons.directions_car, + // 与「AI车载香薰」品类卡同色系(device_category.dart 的 carAroma) + gradient: const [Color(0xFFFFB74D), Color(0xFFE65100)], + entryRoute: Routes.smartcarChat, + // 设备按键唤醒时接的就是这个应用(不是 EMAI)——见 AgentModuleDescriptor.bailianAppId + bailianAppId: kSmartcarBailianAppId, + pages: [ + GetPage( + name: Routes.smartcarChat, + page: () => const EmaiView( + controllerTag: kSmartcarTag, + titleKey: 'agentSmartcar', + ), + binding: SmartcarChatBinding(), + transition: Transition.rightToLeft, + transitionDuration: const Duration(milliseconds: 250), + ), + ], + // 模块自带文案:不用再去改 41 个语言文件。 + // 缺某个语种时 GetX 回退到全局表,全局也没有就显示 key 本身, + // 所以至少要保证 zh_CN / en_US 有(module_registry_test 守着这两个)。 + translations: const { + 'zh_CN': { + 'agentSmartcar': 'Smartcar', + 'agentSmartcarDesc': '您的车载助手', + 'smartcarWelcome': '欢迎回来', + 'smartcarA2dpTitle': '需要连接蓝牙音频', + 'smartcarA2dpHint': 'AI 回复和音乐要经典蓝牙才能从设备里放出来。请到「设置 → 蓝牙」里配对 @name。', + }, + 'zh_TW': { + 'agentSmartcar': 'Smartcar', + 'agentSmartcarDesc': '您的車載助手', + 'smartcarWelcome': '歡迎回來', + 'smartcarA2dpTitle': '需要連接藍牙音訊', + 'smartcarA2dpHint': 'AI 回覆和音樂要經典藍牙才能從裝置裡播出來。請到「設定 → 藍牙」配對 @name。', + }, + 'zh_HK': { + 'agentSmartcar': 'Smartcar', + 'agentSmartcarDesc': '您的車載助手', + 'smartcarWelcome': '歡迎回來', + 'smartcarA2dpTitle': '需要連接藍牙音訊', + 'smartcarA2dpHint': 'AI 回覆和音樂要經典藍牙先可以喺裝置度播出嚟。請去「設定 → 藍牙」配對 @name。', + }, + 'en_US': { + 'agentSmartcar': 'Smartcar', + 'agentSmartcarDesc': 'Your in-car assistant', + 'smartcarWelcome': 'Welcome back', + 'smartcarA2dpTitle': 'Bluetooth audio not connected', + 'smartcarA2dpHint': 'Pair @name under Settings → Bluetooth so replies and music play from the device.', + }, + 'ja_JP': { + 'agentSmartcar': 'Smartcar', + 'agentSmartcarDesc': '車載アシスタント', + 'smartcarWelcome': 'おかえりなさい', + 'smartcarA2dpTitle': 'Bluetoothオーディオ未接続', + 'smartcarA2dpHint': '「設定 → Bluetooth」で @name をペアリングすると、応答と音楽が本体から再生されます。', + }, + 'ko_KR': { + 'agentSmartcar': 'Smartcar', + 'agentSmartcarDesc': '차량용 어시스턴트', + 'smartcarWelcome': '다시 오신 것을 환영합니다', + 'smartcarA2dpTitle': '블루투스 오디오 미연결', + 'smartcarA2dpHint': '설정 → 블루투스에서 @name 을(를) 페어링하면 응답과 음악이 기기에서 재생됩니다。', + }, + 'de_DE': { + 'agentSmartcar': 'Smartcar', + 'agentSmartcarDesc': 'Ihr Auto-Assistent', + 'smartcarWelcome': 'Willkommen zurück', + 'smartcarA2dpTitle': 'Bluetooth-Audio nicht verbunden', + 'smartcarA2dpHint': 'Koppeln Sie @name unter Einstellungen → Bluetooth, damit Antworten und Musik über das Gerät laufen.', + }, + 'fr_FR': { + 'agentSmartcar': 'Smartcar', + 'agentSmartcarDesc': 'Votre assistant automobile', + 'smartcarWelcome': 'Bon retour', + 'smartcarA2dpTitle': 'Audio Bluetooth non connecté', + 'smartcarA2dpHint': 'Associez @name dans Réglages → Bluetooth pour que les réponses et la musique sortent de l\'appareil.', + }, + 'es_ES': { + 'agentSmartcar': 'Smartcar', + 'agentSmartcarDesc': 'Tu asistente para el coche', + 'smartcarWelcome': 'Bienvenido de nuevo', + 'smartcarA2dpTitle': 'Audio Bluetooth no conectado', + 'smartcarA2dpHint': 'Empareja @name en Ajustes → Bluetooth para que las respuestas y la música suenen en el dispositivo.', + }, + 'pt_PT': { + 'agentSmartcar': 'Smartcar', + 'agentSmartcarDesc': 'O seu assistente para o carro', + 'smartcarWelcome': 'Bem-vindo de volta', + 'smartcarA2dpTitle': 'Áudio Bluetooth não ligado', + 'smartcarA2dpHint': 'Emparelhe @name em Definições → Bluetooth para que as respostas e a música saiam do dispositivo.', + }, + 'ru_RU': { + 'agentSmartcar': 'Smartcar', + 'agentSmartcarDesc': 'Ваш автомобильный помощник', + 'smartcarWelcome': 'С возвращением', + 'smartcarA2dpTitle': 'Bluetooth-аудио не подключено', + 'smartcarA2dpHint': 'Подключите @name в «Настройки → Bluetooth», чтобы ответы и музыка звучали из устройства.', + }, + }, +); diff --git a/apps/client/lib/modules/text_translation/module.dart b/apps/client/lib/modules/text_translation/module.dart new file mode 100644 index 00000000..e9af02bf --- /dev/null +++ b/apps/client/lib/modules/text_translation/module.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../routes/app_routes.dart'; +import '../module_descriptor.dart'; +import 'bindings/text_translation_binding.dart'; +import 'views/text_translation_view.dart'; + +/// 文本翻译 +final AgentModuleDescriptor textTranslationModule = AgentModuleDescriptor( + id: 'textTranslation', + title: 'agentTextTranslation', + subtitle: 'agentTextTranslationDesc', + icon: Icons.translate, + gradient: const [Color(0xFF26A69A), Color(0xFF00796B)], + entryRoute: Routes.textTranslation, + pages: [ + GetPage( + name: Routes.textTranslation, + page: () => const TextTranslationView(), + binding: TextTranslationBinding(), + transition: Transition.rightToLeft, + transitionDuration: const Duration(milliseconds: 250), + ), + ], +); diff --git a/apps/client/lib/modules/translation/controllers/translation_controller.dart b/apps/client/lib/modules/translation/controllers/translation_controller.dart index 75ab3ec6..c0daccf3 100644 --- a/apps/client/lib/modules/translation/controllers/translation_controller.dart +++ b/apps/client/lib/modules/translation/controllers/translation_controller.dart @@ -14,7 +14,6 @@ import 'package:device_info_plus/device_info_plus.dart'; import 'package:eaimar/data/services/qq_music.dart'; import '../../../data/services/ast_service.dart'; import '../../../data/services/server_translation_service.dart'; -import '../../../data/services/bluetooth_manager.dart'; import '../../../data/services/music_manager.dart'; import '../../../data/services/translation_usage_service.dart'; import '../../../data/services/tts_service.dart'; @@ -25,8 +24,8 @@ import '../../../core/services/floating_window_manager.dart'; import '../../../data/services/asr_service.dart'; import '../../../data/services/usage_stats_service.dart'; -import '../../../data/services/ble_manager.dart'; -import '../../../data/services/bes_bluetooth_service.dart'; +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import '../../../devices/device_hub.dart'; import '../../../data/services/recording_archive.dart'; import '../../../core/utils/device_connection.dart'; import '../../../core/utils/background_session_notifier.dart'; @@ -90,8 +89,6 @@ class TranslationController extends GetxController with WidgetsBindingObserver { /// 否则下次点开始会以为不需要再调,实际原生那边已经停了。 bool _astAutoStartPending = false; final GetStorage _storage = GetStorage(); - final BluetoothManager bluetoothManager = Get.find(); - final BleManager bleManager = Get.find(); final _musiceManager = Get.find(); final _qqMusicManager = Get.find(); late final UsageStatsService _usageService; @@ -185,22 +182,21 @@ class TranslationController extends GetxController with WidgetsBindingObserver { StreamSubscription? _astEventSubscription; StreamSubscription? _voiceInteractionSubscription; StreamSubscription? _deviceCallTranslationSubscription; - // 通话翻译 ↔ 杰理桥接: - // inUplink/inDownlink → AstService.pushExternalAudio - // AstService.astTtsFrames → BleManager.feedAstTtsPcm - StreamSubscription? _jieliCallInUplinkSub; - StreamSubscription? _jieliCallInDownlinkSub; - StreamSubscription? _jieliCallAstTtsSub; - // 通话翻译 ↔ 恒玄桥接(与上面杰理那套二选一,见 _configureCallMode): - // micPcmStream(本端) / spkPcmStream(对端) → AstService.pushExternalAudio - // AstService.astTtsFrames → BesBluetoothService.pushTranslationTtsPcm + // 通话翻译 ↔ 设备桥接(厂商无关,走 DeviceSession 的音频通路): + // openMic(callLocal)(本端) / openMic(callPeer)(对端) → AstService.pushExternalAudio + // AstService.astTtsFrames → openSpeaker(callLegA / callLegB) + DeviceSession? _callSession; + DeviceAudioSource? _callLocalSrc; + DeviceAudioSource? _callPeerSrc; + DeviceAudioSink? _callSinkA; + DeviceAudioSink? _callSinkB; StreamSubscription? _besCallMicSub; StreamSubscription? _besCallSpkSub; StreamSubscription? _besCallAstTtsSub; - // 本次通话翻译会话用的是恒玄链路还是杰理链路——停止/出错收尾时按这个分流, - // 不要临停时再去查 DeviceConnection.besConnected(这时耳机可能已经断开了) + // 本次通话翻译会话是否走了设备双路通路——停止/出错收尾时按这个分流, + // 不要临停时再去查连接状态(这时耳机可能已经断开了) bool _callModeUsingBes = false; - // 一次通话模式会话的设备侧收尾(AA52/AA58 或 bleManager.closeCodec)只应该 + // 一次通话模式会话的设备侧收尾(call.stop/asr.stopped)只应该 // 真正执行一次——stopAll() 和 AST 流异步报错触发的 _terminateCallOnError() // 都可能收尾同一个会话,不加锁耳机会收到两遍关闭指令。见 _teardownCallModeAudio。 bool _callAudioTornDown = true; @@ -674,33 +670,11 @@ class TranslationController extends GetxController with WidgetsBindingObserver { WidgetsBinding.instance.addObserver(this); } - /// 监听 BleManager 下发的设备通话翻译开关信号 (0x16 / 0x17) - /// - 收到 true: 若当前非 call 模式则切换到 call 模式,并自动启动识别; - /// - 收到 false: 停止当前识别(stopAll)。 - /// 首次进入时若 autoStart=true,也立即触发一次开启。 + /// 首次进入时若 autoStart=true,立即触发一次开启。 + /// (设备端「通话翻译开关」按键的信号目前没有厂商上报,所以这里只剩 autoStart。) void _setupDeviceCallTranslationListener(String initMode) { _deviceCallTranslationSubscription?.cancel(); - _deviceCallTranslationSubscription = - bleManager.onCallTranslationRequest.listen((enable) async { - Logger.info( - '[CALL_TRANS_CMD] TranslationController 收到信号: ${enable ? "开启" : "关闭"}'); - try { - if (enable) { - if (currentMode.value != 'call') { - await changeTranslationMode('call'); - } - if (!isRecognizing.value) { - await startRecognition(); - } - } else { - await stopAll(); - } - } catch (e, s) { - Logger.e('TRANSL', '[CALL_TRANS_CMD] 处理设备通话翻译信号失败: $e', e, s); - } - }); - - // 支持从 BleManager 导航进入时携带 autoStart 参数自动开启 + // 支持导航进入时携带 autoStart 参数自动开启 final autoStart = Get.arguments?['autoStart'] == true; if (autoStart && initMode == 'call') { Logger.info('[CALL_TRANS_CMD] 检测到 autoStart=true, 进入通话翻译并自启动'); @@ -718,14 +692,14 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - /// 监听恒玄耳机的通话状态(0xD1/0xD2/0x02/0x03 → BesBluetoothService.isCallOngoing)。 + /// 监听设备上报的通话状态(DeviceHub.inCall)。 /// 挂断(isCallOngoing 变 false)时,如果正在通话翻译,自动停止识别—— /// 不然识别会一直空跑,AST 也拿不到新音频,只能等用户自己发现再手动停。 void _setupBesCallHangupListener() { _besCallOngoingWorker?.dispose(); - if (!Get.isRegistered()) return; + if (!Get.isRegistered()) return; _besCallOngoingWorker = ever( - BesBluetoothService.to.isCallOngoing, + DeviceHub.to.inCall, (calling) async { if (calling) return; if (currentMode.value != 'call') return; @@ -1080,7 +1054,6 @@ class TranslationController extends GetxController with WidgetsBindingObserver { _besCallOngoingWorker = null; _floatingWindowClosedSubscription?.cancel(); _floatingWindowClosedSubscription = null; - _detachJieliCallTranslationBridge(); _detachBesCallTranslationBridge(); _translationDebounceTimer?.cancel(); restoreOtherServices(); @@ -1343,8 +1316,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { currentMode.value == 'call') && !isAndroidAudioVideo && !isIosAudioVideo && - !(currentMode.value == 'call' && _callModeUsingBes) && - !bleManager.isCodecActive) { + !(currentMode.value == 'call' && _callModeUsingBes)) { return; } if (currentMode.value == 'simultaneous') { @@ -1521,45 +1493,44 @@ class TranslationController extends GetxController with WidgetsBindingObserver { /// 配置通话模式(只做设备音频链路配置,AST 已在 /// _initializeCallModeTranslationService 中初始化)。 - /// 恒玄和杰理耳机的通话音频通路完全不同,分两套桥接,互不影响; - /// 用哪套由当前连着的是哪条链路决定,记进 [_callModeUsingBes] 供停止时分流。 + /// 需要一台具备 [DeviceCapability.callAudioTap] 的设备;没有就直接报错。 Future _configureCallMode() async { - _callModeUsingBes = DeviceConnection.besConnected; + _callSession = DeviceHub.to.sessionWith(DeviceCapability.callAudioTap); + _callModeUsingBes = _callSession != null; _callAudioTornDown = false; if (_callModeUsingBes) { await _configureCallModeBes(); } else { - await _configureCallModeJieli(); + Get.snackbar('tip'.tr, 'bluetoothCallStateError'.tr); + throw Exception('没有具备通话双路抓音能力的设备'); } } - /// 配置通话模式(恒玄):进通话模式拿双路上行(AA 51)+ 开译文下行通道(AA 56)+ - /// 通知耳机 ASR 已开启(AA 57),再把 mic/spk PCM 接上 AST。 + /// 配置通话模式(设备双路通路):进通话模式拿双路上行 + 开译文下行通道 + + /// 通知设备 ASR 已开启,再把本端/对端 PCM 接上 AST。 /// - /// 恒玄这套私有协议是纯事件推送,没有类似杰理 isCodecActive 那种「解码器 - /// 已就绪」的同步信号,所以这里不像杰理那样轮询等待/失败即抛异常—— - /// 直接乐观下发指令,真正有没有收到音频帧由 [_attachBesCallTranslationBridge] - /// 里的流订阅决定。 + /// 恒玄这套私有协议是纯事件推送,没有「解码器已就绪」的同步信号, + /// 所以这里直接乐观下发指令,真正有没有收到音频帧由桥接里的流订阅决定。 Future _configureCallModeBes() async { isPreparing.value = true; - final bes = BesBluetoothService.to; + final session = _callSession!; try { - Logger.info('[CALL-CFG-BES] 进通话模式(AA 51) + 开译文下行通道(AA 56) + 通知ASR已开启(AA 57)'); - await bes.startCallMode(); - await bes.startTranslationDownlink(); - await bes.notifyAsrStarted(); + Logger.info('[CALL-CFG] call.start + 开译文下行通道 + asr.started'); + await session.invokeFeature(DeviceFeatures.callStart); + _callSinkA = await session.openSpeaker(route: AudioRoute.callLegA); + _callSinkB = await session.openSpeaker(route: AudioRoute.callLegB); + await session.invokeFeature(DeviceFeatures.asrStarted); } catch (e) { - Logger.error('[CALL-CFG-BES] 恒玄通话模式配置失败: $e'); + Logger.error('[CALL-CFG] 设备通话模式配置失败: $e'); } isPreparing.value = false; _audioSourceType = true; isTtsEnabled.value = false; - // 根据设备产品配置决定是否由原生层本地播报对方(B)翻译音频, - // 逻辑与杰理那份一致,只是设备名的来源换成恒玄 + // 根据设备产品配置决定是否由原生层本地播报对方(B)翻译音频 bool broadcastPeer = false; try { - final deviceName = bes.connectedDeviceName.value; + final deviceName = session.info.name; if (deviceName.isNotEmpty) { final DBProduct? product = AppConfig.getproduct(deviceName); broadcastPeer = product?.broadcastpeertranslate == true; @@ -1568,31 +1539,30 @@ class TranslationController extends GetxController with WidgetsBindingObserver { Logger.error('读取 broadcastpeertranslate 失败,回退默认 false: $e'); } await _astService.setBroadcastPeerTranslate(broadcastPeer); - Logger.info('[CALL-BES] broadcastPeerTranslate=$broadcastPeer'); - - _attachBesCallTranslationBridge(); - Logger.info('发送恒玄通话双路(mic本端/spk对端)声音'); - } + Logger.info('[CALL] broadcastPeerTranslate=$broadcastPeer'); - /// 通话翻译 ↔ 恒玄桥接: - /// micPcmStream(本端) → AST.A(己方→对端语种) - /// spkPcmStream(对端) → AST.B(对端→己方语种) - /// AST.A TTS → pushTranslationTtsPcm('A', pcm)(对端听) - /// AST.B TTS → pushTranslationTtsPcm('B', pcm)(己方听) - void _attachBesCallTranslationBridge() { - _detachBesCallTranslationBridge(); - final bes = BesBluetoothService.to; - _besCallMicSub = bes.micPcmStream.listen( - (pcm) { - _astService.pushExternalAudio(leg: 'A', pcm: pcm); - }, - onError: (e) => Logger.error('[CALL-BRIDGE-BES] mic stream error: $e'), + await _attachBesCallTranslationBridge(); + Logger.info('发送设备通话双路(本端/对端)声音'); + } + + /// 通话翻译 ↔ 设备桥接: + /// callLocal(本端) → AST.A(己方→对端语种) + /// callPeer(对端) → AST.B(对端→己方语种) + /// AST.A TTS → callLegA(对端听) + /// AST.B TTS → callLegB(己方听) + Future _attachBesCallTranslationBridge() async { + await _detachBesCallTranslationBridge(closeSinks: false); + final session = _callSession; + if (session == null) return; + _callLocalSrc = await session.openMic(route: AudioRoute.callLocal); + _callPeerSrc = await session.openMic(route: AudioRoute.callPeer); + _besCallMicSub = _callLocalSrc!.pcm.listen( + (pcm) => _astService.pushExternalAudio(leg: 'A', pcm: pcm), + onError: (e) => Logger.error('[CALL-BRIDGE] local stream error: $e'), ); - _besCallSpkSub = bes.spkPcmStream.listen( - (pcm) { - _astService.pushExternalAudio(leg: 'B', pcm: pcm); - }, - onError: (e) => Logger.error('[CALL-BRIDGE-BES] spk stream error: $e'), + _besCallSpkSub = _callPeerSrc!.pcm.listen( + (pcm) => _astService.pushExternalAudio(leg: 'B', pcm: pcm), + onError: (e) => Logger.error('[CALL-BRIDGE] peer stream error: $e'), ); // 诊断:计数 + isFinal 必打,用于定位 "TTS 到底有没有被转发到 native"。 int forwardCnt = 0; @@ -1601,121 +1571,34 @@ class TranslationController extends GetxController with WidgetsBindingObserver { forwardCnt++; if (frame.isFinal || forwardCnt == 1 || forwardCnt % 50 == 0) { Logger.info( - '[CALL-BRIDGE-BES] forward TTS leg=${frame.leg} pcm=${frame.pcm.length}B isFinal=${frame.isFinal} (#$forwardCnt)', + '[CALL-BRIDGE] forward TTS leg=${frame.leg} pcm=${frame.pcm.length}B isFinal=${frame.isFinal} (#$forwardCnt)', ); } - bes.pushTranslationTtsPcm(frame.leg, frame.pcm); + final sink = frame.leg == 'A' ? _callSinkA : _callSinkB; + sink?.write(frame.pcm); }, - onError: (e) => Logger.error('[CALL-BRIDGE-BES] ast tts stream error: $e'), + onError: (e) => Logger.error('[CALL-BRIDGE] ast tts stream error: $e'), ); - Logger.info('[CALL-BRIDGE-BES] 已连通 恒玄双路 ↔ AST'); + Logger.info('[CALL-BRIDGE] 已连通 设备双路 ↔ AST'); } - void _detachBesCallTranslationBridge() { + Future _detachBesCallTranslationBridge({bool closeSinks = true}) async { _besCallMicSub?.cancel(); _besCallMicSub = null; _besCallSpkSub?.cancel(); _besCallSpkSub = null; _besCallAstTtsSub?.cancel(); _besCallAstTtsSub = null; - } - - /// 配置通话模式(杰理,原有实现,只是改了名字) - Future _configureCallModeJieli() async { - isPreparing.value = true; - // 最多重试 3 轮 A2DP 解码器打开,每轮等待 2 秒(约 13 次 150ms 轮询) - // 部分耳机首次收到 CMD_CONTROL_CODEC 时需要重放命令才能真正切到 A2DP 流式模式 - const int maxRounds = 3; - const int attemptsPerRound = 13; - for (int round = 0; round < maxRounds; round++) { - Logger.info('[CALL-CFG] 打开 A2DP 解码器 (round=${round + 1}/$maxRounds)'); - await bleManager.openA2DPDecoder(); - int attempts = 0; - while (!bleManager.isCodecActive && attempts < attemptsPerRound) { - await Future.delayed(const Duration(milliseconds: 150)); - attempts++; - } - if (bleManager.isCodecActive) { - Logger.info('[CALL-CFG] A2DP 解码器就绪 (round=${round + 1}, attempts=$attempts)'); - break; - } - Logger.warning('[CALL-CFG] A2DP 解码器未激活,重试 (round=${round + 1})'); + await _callLocalSrc?.close(); + _callLocalSrc = null; + await _callPeerSrc?.close(); + _callPeerSrc = null; + if (closeSinks) { + await _callSinkA?.close(); + _callSinkA = null; + await _callSinkB?.close(); + _callSinkB = null; } - isPreparing.value = false; - if (!bleManager.isCodecActive) { - Get.snackbar('tip'.tr, 'bluetoothCallStateError'.tr); - throw Exception('lxm--BLE编解码打开失败'); - } - _audioSourceType = true; - isTtsEnabled.value = false; - - // 根据设备产品配置决定是否由原生层本地播报对方(B)翻译音频 - // 只有 product.broadcastpeertranslate == true 才播报;null / false / 读取异常 → 不播报 - bool broadcastPeer = false; - try { - final deviceName = bleManager.getDeviceName(); - if (deviceName.isNotEmpty) { - final DBProduct? product = AppConfig.getproduct(deviceName); - broadcastPeer = product?.broadcastpeertranslate == true; - } - } catch (e) { - Logger.error('读取 broadcastpeertranslate 失败,回退默认 false: $e'); - } - await _astService.setBroadcastPeerTranslate(broadcastPeer); - Logger.info('[CALL] broadcastPeerTranslate=$broadcastPeer'); - - // 把杰理 SCO 双向 PCM ↔ AST 流水线接上: - // in.uplink → AST.A(己方→对端语种) - // in.downlink → AST.B(对端→己方语种) - // AST.A TTS → out.uplink(对端听) - // AST.B TTS → out.downlink(己方听) - _attachJieliCallTranslationBridge(); - - Logger.info('发送ble系统mic和dac(音乐或者通话远端)声音'); - } - - void _attachJieliCallTranslationBridge() { - _detachJieliCallTranslationBridge(); - _jieliCallInUplinkSub = bleManager.inUplinkPcmStream.listen( - (pcm) { - _astService.pushExternalAudio(leg: 'A', pcm: pcm); - }, - onError: (e) => Logger.error('[CALL-BRIDGE] in.uplink stream error: $e'), - ); - _jieliCallInDownlinkSub = bleManager.inDownlinkPcmStream.listen( - (pcm) { - _astService.pushExternalAudio(leg: 'B', pcm: pcm); - }, - onError: (e) => Logger.error('[CALL-BRIDGE] in.downlink stream error: $e'), - ); - // 诊断:计数 + isFinal 必打,用于定位 “TTS 到底有没有被转发到 native”。 - int forwardCnt = 0; - _jieliCallAstTtsSub = _astService.astTtsFrames.listen( - (frame) { - forwardCnt++; - if (frame.isFinal || forwardCnt == 1 || forwardCnt % 50 == 0) { - Logger.info( - '[CALL-BRIDGE] forward TTS leg=${frame.leg} pcm=${frame.pcm.length}B isFinal=${frame.isFinal} (#$forwardCnt)', - ); - } - bleManager.feedAstTtsPcm( - leg: frame.leg, - pcm: frame.pcm, - isFinal: frame.isFinal, - ); - }, - onError: (e) => Logger.error('[CALL-BRIDGE] ast tts stream error: $e'), - ); - Logger.info('[CALL-BRIDGE] 已连通 杰理 SCO ↔ AST'); - } - - void _detachJieliCallTranslationBridge() { - _jieliCallInUplinkSub?.cancel(); - _jieliCallInUplinkSub = null; - _jieliCallInDownlinkSub?.cancel(); - _jieliCallInDownlinkSub = null; - _jieliCallAstTtsSub?.cancel(); - _jieliCallAstTtsSub = null; } /// 配置默认模式 @@ -2577,18 +2460,12 @@ class TranslationController extends GetxController with WidgetsBindingObserver { _callAudioTornDown = true; if (currentMode.value == "call" && _callModeUsingBes) { await _teardownBesCallMode(); - } else { - _detachJieliCallTranslationBridge(); - if (currentMode.value == "audioVideo" && - (Platform.isAndroid || Platform.isIOS)) { - // Android:关掉 MediaProjection 的前台服务。 - // iOS:只关我们这一端的 socket 接收;广播本身得用户从系统面板/灵动岛 - // 自己停,App 无权强停(扩展会收到 broadcastFinished 自行退出)。 - await _asrService.stopScreenCapture(); - } else { - bleManager.closeCodec(); - } - Logger.info('关闭ble编解码器'); + } else if (currentMode.value == "audioVideo" && + (Platform.isAndroid || Platform.isIOS)) { + // Android:关掉 MediaProjection 的前台服务。 + // iOS:只关我们这一端的 socket 接收;广播本身得用户从系统面板/灵动岛 + // 自己停,App 无权强停(扩展会收到 broadcastFinished 自行退出)。 + await _asrService.stopScreenCapture(); } if (currentMode.value == "call") { // 通话翻译真的结束了(不管是用户点结束、还是挂断自动停止), @@ -2597,20 +2474,22 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - /// 恒玄通话翻译收尾:断开桥接 + 关译文下行(AA 58/56的反向) + 退通话模式(AA 52)。 + /// 设备通话翻译收尾:断开桥接 + 通知 ASR 关闭 + 关译文下行 + 退通话模式。 /// 耳机可能已经断开了,下发指令前先判断连接状态,别让收尾本身再抛异常。 Future _teardownBesCallMode() async { - _detachBesCallTranslationBridge(); - if (!Get.isRegistered()) return; - final bes = BesBluetoothService.to; - if (!bes.isConnected) return; + final session = _callSession; + _callSession = null; + final alive = session != null && session.state == DeviceConnectionState.ready; + try { + if (alive) await session.invokeFeature(DeviceFeatures.asrStopped); + } catch (_) {} + await _detachBesCallTranslationBridge(); // 关掉两路 sink = 停译文下行 + if (!alive) return; try { - await bes.notifyAsrStopped(); // AA 58 - await bes.stopTranslationDownlink(); - await bes.stopCallMode(); // AA 52 - Logger.info('[CALL-BRIDGE-BES] 已退出恒玄通话模式'); + await session.invokeFeature(DeviceFeatures.callStop); + Logger.info('[CALL-BRIDGE] 已退出设备通话模式'); } catch (e) { - Logger.error('[CALL-BRIDGE-BES] 退出恒玄通话模式失败: $e'); + Logger.error('[CALL-BRIDGE] 退出设备通话模式失败: $e'); } } diff --git a/apps/client/lib/modules/translation/middleware/controllers/translation_middleware_controller.dart b/apps/client/lib/modules/translation/middleware/controllers/translation_middleware_controller.dart index e9989d03..b1e0695e 100644 --- a/apps/client/lib/modules/translation/middleware/controllers/translation_middleware_controller.dart +++ b/apps/client/lib/modules/translation/middleware/controllers/translation_middleware_controller.dart @@ -3,12 +3,11 @@ import 'package:get/get.dart'; import 'package:flutter/material.dart'; import '../../../../core/utils/toast_throttle.dart'; import '../../../../routes/app_routes.dart'; -import '../../../../data/services/ble_manager.dart'; +import '../../../../core/utils/device_connection.dart'; /// 翻译中间层控制器 /// 负责管理翻译功能入口的导航和状态 class TranslationMiddlewareController extends GetxController { - final BleManager bleManager = Get.find(); //获取BLE管理器实例 /// 翻译功能选项列表 final List translationOptions = [ @@ -121,7 +120,7 @@ class TranslationMiddlewareController extends GetxController { bool isOptionEnabled(TranslationOption option) { // 多媒体翻译改为走手机摄像头/麦克风,不再要求 BLE 已连接 if (option.translationId == 'call') { - return bleManager.isConnected; + return DeviceConnection.any; } return true; } diff --git a/apps/client/lib/modules/translation/module.dart b/apps/client/lib/modules/translation/module.dart new file mode 100644 index 00000000..0a38c7b7 --- /dev/null +++ b/apps/client/lib/modules/translation/module.dart @@ -0,0 +1,87 @@ +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../routes/app_routes.dart'; +import '../home/controllers/home_controller.dart'; +import '../module_descriptor.dart'; +import 'bindings/translation_binding.dart'; +import 'bindings/translation_history_binding.dart'; +import 'bindings/translation_list_binding.dart'; +import 'middleware/bindings/translation_middleware_binding.dart'; +import 'middleware/views/translation_middleware_view.dart'; +import 'views/translation_history_view.dart'; +import 'views/translation_list_view.dart'; +import 'views/translation_view.dart'; + +GetPage _p(String name, GetPageBuilder page, Bindings binding) => GetPage( + name: name, + page: page, + binding: binding, + transition: Transition.rightToLeft, + transitionDuration: const Duration(milliseconds: 250), + ); + +/// 翻译模块的页面,四个入口共用 +final List _translationPages = [ + _p(Routes.translationMiddleware, () => const TranslationMiddlewareView(), + TranslationMiddlewareBinding()), + _p(Routes.translation, () => const TranslationView(), TranslationBinding()), + _p(Routes.translationHistory, () => const TranslationHistoryView(), + TranslationHistoryBinding()), + _p(Routes.translationList, () => const TranslationListView(), + TranslationListBinding()), +]; + +AgentModuleDescriptor _mode({ + required String id, + required String title, + required String subtitle, + required IconData icon, + required List gradient, + Set caps = const {}, +}) => + AgentModuleDescriptor( + id: id, + title: title, + subtitle: subtitle, + icon: icon, + gradient: gradient, + requiredCapabilities: caps, + onLaunch: () => HomeController.to.openTranslationFeature(id), + pages: _translationPages, + ); + +/// 同声翻译 / 面对面翻译 / 通话翻译 / 多媒体翻译——同一个翻译页的四种模式 +final List translationModules = [ + _mode( + id: 'simultaneous', + title: 'agentSimultaneous', + subtitle: 'agentSimultaneousDesc', + icon: Icons.record_voice_over, + gradient: const [Color(0xFF4CAF50), Color(0xFF009688)], + ), + _mode( + id: 'faceToFace', + title: 'agentFaceToFace', + subtitle: 'agentFaceToFaceDesc', + icon: Icons.forum, + gradient: const [Color(0xFF42A5F5), Color(0xFF1E88E5)], + ), + _mode( + id: 'call', + title: 'agentCall', + subtitle: 'agentCallDesc', + icon: Icons.phone_in_talk, + gradient: const [Color(0xFFFFA726), Color(0xFFFB8C00)], + // 通话翻译要抓通话双路音频 + caps: const {DeviceCapability.callAudioTap}, + ), + _mode( + id: 'audioVideo', + title: 'agentAudioVideo', + subtitle: 'agentAudioVideoDesc', + icon: Icons.slideshow, + gradient: const [Color(0xFF5C6BC0), Color(0xFF3949AB)], + ), +]; diff --git a/apps/client/lib/modules/translation/views/dialogs/translation_mode_selector.dart b/apps/client/lib/modules/translation/views/dialogs/translation_mode_selector.dart index 76109102..b3d80887 100644 --- a/apps/client/lib/modules/translation/views/dialogs/translation_mode_selector.dart +++ b/apps/client/lib/modules/translation/views/dialogs/translation_mode_selector.dart @@ -2,6 +2,8 @@ import 'dart:ui'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; + +import '../../../../core/utils/device_connection.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../controllers/translation_controller.dart'; @@ -122,7 +124,7 @@ class TranslationModeSelector { Icons.videocam, Colors.orange, controller, - onTap: controller.bleManager.isConnected + onTap: DeviceConnection.any ? () async { Get.back(); await controller.stopAll(); @@ -137,7 +139,7 @@ class TranslationModeSelector { Icons.phone, Colors.purple, controller, - onTap: controller.bleManager.isConnected + onTap: DeviceConnection.any ? () async { Get.back(); await controller.stopAll(); diff --git a/apps/client/lib/routes/app_pages.dart b/apps/client/lib/routes/app_pages.dart index a8a92789..7fd1a67b 100644 --- a/apps/client/lib/routes/app_pages.dart +++ b/apps/client/lib/routes/app_pages.dart @@ -1,114 +1,69 @@ import 'package:get/get.dart'; -import '../modules/call_recording/bindings/call_recording_binding.dart'; -import '../modules/call_recording/views/call_recording_view.dart'; -import '../modules/qqmusic/bindings/qqmusic_playlist_binding.dart'; -import '../modules/qqmusic/views/qqmusic_playlist_view.dart'; -import '../modules/voice_replication/bindings/voice_replication_binding.dart'; -import '../modules/voice_replication/views/voice_replication_view.dart'; -import '/modules/ble/bindings/ble_binding.dart'; -import '../modules/ble/views/ble_view.dart'; - -import '../../modules/devices/bindings/devices_binding.dart'; -import '../../modules/devices/views/devices_view.dart'; -import '../../modules/devices/views/device_category_view.dart'; -import '../../modules/devices/views/holder_scan_view.dart'; -import '../../modules/devices/views/bes_scan_view.dart'; -import '../modules/main_tab/views/tabs/plaza_tab.dart'; -import '../modules/my_devices/bindings/my_devices_binding.dart'; -import '../modules/my_devices/views/my_devices_view.dart'; +import '../modules/devices/views/bes_scan_view.dart'; +import '../modules/devices/views/device_category_view.dart'; +import '../modules/devices/views/holder_scan_view.dart'; +import '../modules/devices/views/smartcar_scan_view.dart'; import '../modules/feedback/bindings/feedback_bindings.dart'; import '../modules/feedback/views/feedback_view.dart'; -import '../modules/home/views/home_view.dart'; -import '../modules/home/bindings/home_binding.dart'; -import '../modules/main_tab/views/main_tab_view.dart'; -import '../modules/main_tab/bindings/main_tab_binding.dart'; -import '../modules/meeting/bindings/meeting_binding.dart'; -import '../modules/meeting/bindings/meeting_connect_binding.dart'; -import '../modules/meeting/bindings/meeting_details_binding.dart'; -import '../modules/meeting/views/meeting_connect_view.dart'; -import '../modules/meeting/views/meeting_details_view.dart'; -import '../modules/meeting/bindings/meeting_record_binding.dart'; -import '../modules/meeting/views/meeting_record_view.dart'; -import '../modules/meeting/views/meeting_view.dart'; -import '../modules/opus_test/bindings/opus_test_binding.dart'; -import '../modules/opus_test/views/opus_test_view.dart'; -import '../modules/bes_test/bindings/bes_test_binding.dart'; -import '../modules/bes_test/views/bes_test_view.dart'; +import '../modules/goods/bindings/goodsmeet_binding.dart'; +import '../modules/goods/bindings/goodstrans_binding.dart'; +import '../modules/goods/bindings/goodsvip_binding.dart'; +import '../modules/goods/views/goodsmeet_view.dart'; +import '../modules/goods/views/goodstrans_view.dart'; +import '../modules/goods/views/goodsvip_view.dart'; import '../modules/log_export/bindings/log_export_binding.dart'; import '../modules/log_export/views/log_export_view.dart'; -import '../modules/profile/views/profile_view.dart'; -import '../modules/profile/views/profile_meeting_view.dart'; -import '../modules/profile/bindings/profile_binding.dart'; -// import '../modules/chat/bindings/chat_binding.dart'; -//import '../modules/chat/views/chat_view.dart'; - -import '../modules/timbre/bindings/timbre_binding.dart'; -import '../modules/timbre/views/timbre_view.dart'; -import '../modules/translation/views/translation_view.dart'; -import '../modules/translation/bindings/translation_binding.dart'; -import '../modules/translation/views/translation_history_view.dart'; -import '../modules/usage/views/usage_view.dart'; -import '../modules/usage/bindings/usage_binding.dart'; -import '../modules/translation/bindings/translation_list_binding.dart'; -import '../modules/translation/views/translation_list_view.dart'; -import '../modules/translation/bindings/translation_history_binding.dart'; -import '../modules/login/views/login_view.dart'; import '../modules/login/bindings/login_binding.dart'; -import '../modules/splash/views/splash_view.dart'; -import '../modules/splash/bindings/splash_binding.dart'; -import './app_routes.dart'; -import '../modules/settings/views/settings_view.dart'; -import '../modules/settings/bindings/settings_binding.dart'; -import '../modules/permissions/views/permissions_view.dart'; -import '../modules/permissions/bindings/permissions_binding.dart'; -import '../modules/speech_test/views/speech_test_view.dart'; -import '../modules/speech_test/bindings/speech_test_binding.dart'; -import '../modules/agent/views/agent_view.dart'; -import '../modules/emai/views/emai_view.dart'; -import '../modules/emai/bindings/emai_binding.dart'; -import '../modules/agent/bindings/agent_binding.dart'; -import '../modules/ota_upgrade/views/bes_ota_upgrade_view.dart'; +import '../modules/login/views/login_view.dart'; +import '../modules/main_tab/bindings/main_tab_binding.dart'; +import '../modules/main_tab/views/main_tab_view.dart'; +import '../modules/main_tab/views/tabs/plaza_tab.dart'; +import '../modules/mobile_elf/bindings/mobile_elf_binding.dart'; +import '../modules/mobile_elf/views/mobile_elf_view.dart'; +import '../modules/my_devices/bindings/my_devices_binding.dart'; +import '../modules/my_devices/views/my_devices_view.dart'; import '../modules/ota_upgrade/bindings/ota_upgrade_binding.dart'; -import '../modules/realtime/bindings/realtime_binding.dart'; -import '../modules/realtime/views/realtime_view.dart'; -import '../modules/music/views/music_playlist_view.dart'; -import '../modules/music/bindings/music_playlist_binding.dart'; +import '../modules/ota_upgrade/views/device_ota_view.dart'; import '../modules/payment/bindings/payment_binding.dart'; import '../modules/payment/views/payment_view.dart'; -import '../modules/translation/middleware/views/translation_middleware_view.dart'; -import '../modules/translation/middleware/bindings/translation_middleware_binding.dart'; -import '../modules/text_translation/bindings/text_translation_binding.dart'; -import '../modules/text_translation/views/text_translation_view.dart'; -import '../modules/picture_translation/views/picture_translation_view.dart'; -import '../modules/picture_translation/bindings/picture_translation_binding.dart'; -import '../modules/goods/bindings/goodsvip_binding.dart'; -import '../modules/goods/views/goodsvip_view.dart'; -import '../modules/goods/bindings/goodstrans_binding.dart'; -import '../modules/goods/views/goodstrans_view.dart'; -import '../modules/goods/bindings/goodsmeet_binding.dart'; -import '../modules/goods/views/goodsmeet_view.dart'; -import '../modules/goods/bindings/goodsai_binding.dart'; -import '../modules/goods/views/goodsai_view.dart'; -import '../modules/mobile_elf/bindings/mobile_elf_binding.dart'; -import '../modules/mobile_elf/views/mobile_elf_view.dart'; +import '../modules/permissions/bindings/permissions_binding.dart'; +import '../modules/permissions/views/permissions_view.dart'; +import '../modules/profile/bindings/profile_binding.dart'; +import '../modules/profile/views/profile_meeting_view.dart'; +import '../modules/profile/views/profile_view.dart'; +import '../modules/splash/bindings/splash_binding.dart'; +import '../modules/splash/views/splash_view.dart'; +import '../modules/voice_replication/bindings/voice_replication_binding.dart'; +import '../modules/voice_replication/views/voice_replication_view.dart'; +import '../modules/bes_test/bindings/bes_test_binding.dart'; +import '../modules/module_registry.dart'; +import '../modules/bes_test/views/bes_test_view.dart'; +import 'app_routes.dart'; +/// 路由表。 +/// +/// 只放**核心页面**(启动/登录/主框架/设备/商品/设置…)。 +/// Agent 能力模块的页面由各模块的描述符自带(见 `modules/module_registry.dart`), +/// 在末尾 `...ModuleRegistry.pages` 拼进来,新增模块不用回这里改。 abstract class AppPages { - static final pages = [ - GetPage( - name: Routes.splash, - page: () => const SplashView(), - binding: SplashBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.login, - page: () => const LoginView(), - binding: LoginBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), + static const _fade = Transition.rightToLeft; + static const _dur = Duration(milliseconds: 250); + + static GetPage _page(String name, GetPageBuilder page, + {Bindings? binding, bool popGesture = true}) => + GetPage( + name: name, + page: page, + binding: binding, + popGesture: popGesture, + transition: _fade, + transitionDuration: _dur, + ); + + static final pages = [ + _page(Routes.splash, () => const SplashView(), binding: SplashBinding()), + _page(Routes.login, () => const LoginView(), binding: LoginBinding()), GetPage( name: Routes.initial, page: () => const MainTabView(), @@ -121,322 +76,42 @@ abstract class AppPages { binding: MainTabBinding(), transition: Transition.noTransition, ), - // 改版前的单页首页,保留作为回退入口,方便对照与回滚 - GetPage( - name: Routes.legacyHome, - page: () => const HomeView(), - binding: HomeBinding(), - transition: Transition.noTransition, - ), - // GetPage( - // name: Routes.chat, - // page: () => const ChatView(), - // binding: ChatBinding(), - // transition: Transition.rightToLeft, - // transitionDuration: Duration(milliseconds: 250), - // ), - GetPage( - name: Routes.recording, - page: () => const CallRecordingView(), - binding: CallRecordingBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.fieldRecording, - page: () => const CallRecordingView(), - binding: CallRecordingBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.OTA_UPGRADE, - // 本项目只有恒玄耳机:固件页走 BES 链路(bes_ota_manager 插件自管 SPP)。 - // 杰理那版 OtaUpgradeView/OtaUpgradeController 留着但不再挂路由。 - page: () => const BesOtaUpgradeView(), - binding: OtaUpgradeBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - // GetPage( - // name: Routes.profile, - // page: () => const ProfileView(), - // binding: ProfileBinding(), - // transition: Transition.rightToLeft, - // transitionDuration: Duration(milliseconds: 250), - // ), - GetPage( - name: Routes.editProfile, - page: () => const EditProfileView(), - binding: ProfileBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.profileMeeting, - page: () => ProfileMeetingView(), - binding: ProfileBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.translationMiddleware, - page: () => const TranslationMiddlewareView(), - binding: TranslationMiddlewareBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.translation, - page: () => const TranslationView(), - binding: TranslationBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.pictureTranslation, - page: () => const PictureTranslationView(), - binding: PictureTranslationBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.textTranslation, - page: () => const TextTranslationView(), - binding: TextTranslationBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.translationHistory, - page: () => const TranslationHistoryView(), - binding: TranslationHistoryBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.usageStats, - page: () => const UsageView(), - binding: UsageBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.translationList, - page: () => const TranslationListView(), - binding: TranslationListBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.meeting, - page: () => const MeetingView(), - binding: MeetingBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.meetingDetails, - page: () => const MeetingDetailsView(), - binding: MeetingDetailsBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.meetingConnect, - page: () => const MeetingConnectView(), - binding: MeetingConnectBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.meetingRecord, - page: () => const MeetingRecordView(), - binding: MeetingRecordBinding(), - popGesture: false, - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.timbre, - page: () => const TimbreView(), - binding: TimbreBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.voiceReplication, - page: () => const VoiceReplicationView(), - binding: VoiceReplicationBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.settings, - page: () => const SettingsView(), - binding: SettingsBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.feedback, - page: () => const FeedbackView(), - binding: FeedbackBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - - GetPage( - name: Routes.speechTest, - page: () => const SpeechTestView(), - binding: SpeechTestBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.opusTest, - page: () => const OpusTestView(), - binding: OpusTestBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.besTest, - page: () => const BesTestView(), - binding: BesTestBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.logExport, - page: () => const LogExportView(), - binding: LogExportBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.agent, - page: () => const AgentView(), - binding: AgentBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.emai, - page: () => const EmaiView(), - binding: EmaiBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.permissions, - page: () => const PermissionsView(), - binding: PermissionsBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.realtime, - page: () => const RealtimeView(), - binding: RealtimeBinding(), - ), - GetPage( - name: Routes.musicPlaylist, - page: () => const MusicPlaylistView(), - binding: MusicPlaylistBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), + _page(Routes.otaUpgrade, () => const DeviceOtaView(), + binding: OtaUpgradeBinding()), + _page(Routes.editProfile, () => const EditProfileView(), + binding: ProfileBinding()), + _page(Routes.profileMeeting, () => ProfileMeetingView(), + binding: ProfileBinding()), + _page(Routes.voiceReplication, () => const VoiceReplicationView(), + binding: VoiceReplicationBinding()), + _page(Routes.feedback, () => const FeedbackView(), + binding: FeedbackBinding()), + _page(Routes.logExport, () => const LogExportView(), + binding: LogExportBinding()), + _page(Routes.permissions, () => const PermissionsView(), + binding: PermissionsBinding()), // 添加设备第一步:选品类(纯展示,无需 binding) - GetPage( - name: Routes.deviceCategory, - page: () => const DeviceCategoryView(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.holderScan, - page: () => const HolderScanView(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.plaza, - page: () => const PlazaTab(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.besScan, - page: () => const BesScanView(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.devices, - page: () => const DevicesView(), - binding: DevicesBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.myDevices, - page: () => const MyDevicesView(), - binding: MyDevicesBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.ble, - page: () => const BleView(), - binding: BleBinding(), - ), - GetPage( - name: Routes.qqmusic, - page: () => const QqmusicPlaylistView(), - binding: QQMusicPlaylistBinding(), - ), - GetPage( - name: Routes.payment, - page: () => const PaymentView(), - binding: PaymentBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.goodsvip, - page: () => const GoodsvipView(), - binding: GoodsvipBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.goodstrans, - page: () => const GoodstransView(), - binding: GoodstransBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.goodsmeet, - page: () => const GoodsmeetView(), - binding: GoodsmeetBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.goodsai, - page: () => const GoodsaiView(), - binding: GoodsaiBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), - GetPage( - name: Routes.mobileElf, - page: () => const MobileElfView(), - binding: MobileElfBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), + _page(Routes.deviceCategory, () => const DeviceCategoryView()), + _page(Routes.holderScan, () => const HolderScanView()), + _page(Routes.smartcarScan, () => const SmartcarScanView()), + _page(Routes.besScan, () => const BesScanView()), + _page(Routes.plaza, () => const PlazaTab()), + _page(Routes.myDevices, () => const MyDevicesView(), + binding: MyDevicesBinding()), + _page(Routes.payment, () => const PaymentView(), + binding: PaymentBinding()), + _page(Routes.goodsvip, () => const GoodsvipView(), + binding: GoodsvipBinding()), + _page(Routes.goodstrans, () => const GoodstransView(), + binding: GoodstransBinding()), + _page(Routes.goodsmeet, () => const GoodsmeetView(), + binding: GoodsmeetBinding()), + _page(Routes.mobileElf, () => const MobileElfView(), + binding: MobileElfBinding()), + // 设备协议探测页(设置 → 开发者),只在需要重扫固件命令时用 + _page(Routes.besTest, () => const BesTestView(), + binding: BesTestBinding()), + // ---------- Agent 能力模块自带的页面 ---------- + ...ModuleRegistry.pages, ]; } diff --git a/apps/client/lib/routes/app_routes.dart b/apps/client/lib/routes/app_routes.dart index 6cb07e0a..a85d4ed8 100644 --- a/apps/client/lib/routes/app_routes.dart +++ b/apps/client/lib/routes/app_routes.dart @@ -1,90 +1,62 @@ +/// 路由常量。 +/// +/// 只放核心页面;Agent 能力模块的路由由各模块描述符自带。 +/// 这里每一条都必须在 `app_pages.dart` 注册且有跳转方,`test/routes_test.dart` 守着。 abstract class Routes { // 认证相关 static const splash = '/splash'; static const login = '/login'; - // 主功能模块 + // 主框架(底部五 tab:设备/代办/AI/广场/我的) static const initial = '/home'; - static const home = '/home'; // 底部五 tab 主框架(设备/代办/AI/广场/我的) - static const legacyHome = '/legacy_home'; // 改版前的单页首页,保留备查 - static const chat = '/chat'; - static const profile = '/profile'; + static const home = '/home'; static const editProfile = '/edit_profile'; static const profileMeeting = '/profile_meeting'; // 个人信息页面(从会议模块跳转) - // 设备管理 - static const OTA_UPGRADE = '/ota_upgrade'; // OTA升级 - static const timbre = '/timbre'; // 音色设置 + // 设备 + static const otaUpgrade = '/ota_upgrade'; // 固件升级 + static const deviceCategory = '/device_category'; // 添加设备第一步:选择产品品类 + static const holderScan = '/holder_scan'; // EaiRec 录音支架扫描/连接 + static const smartcarScan = '/smartcar_scan'; // Smartcar 车载香薰扫描/连接 + static const besScan = '/bes_scan'; // 恒玄耳机(经典蓝牙)连接 + static const myDevices = '/my_devices'; // 用户已绑定设备列表 + static const besTest = '/bes_test'; // 恒玄协议探测页(开发者) + + // 录音 + static const recording = '/recording'; // 通话录音 + static const fieldRecording = '/field_recording'; // 现场录音 + + // 设置 static const voiceReplication = '/voice_replication'; // 声音复刻 - static const settings = '/settings'; // 系统设置 static const permissions = '/permissions'; // 权限管理 - static const recording = '/recording'; // 录音功能 - static const eqSettings = '/eq_settings'; // 设备设置 + static const logExport = '/log_export'; // 日志导出 + static const feedback = '/feedback'; // 用户反馈 // 会议相关 static const meeting = '/meeting'; static const meetingDetails = '/meeting/details'; static const meetingConnect = '/meeting/connect'; static const meetingRecord = '/meeting/record'; - // 语言功能 + + // 翻译 static const translationMiddleware = '/translationMiddleware'; // 翻译中间层(统一入口) - static const translation = '/translation'; // 翻译 - static const pictureTranslation = '/picture_translation'; // 图片翻译 - static const textTranslation = '/text_translation'; // 文本翻译 - static const translationHistory = '/translation/history'; // 翻译历史 - static const usageStats = '/usage/stats'; // 用量统计 - static const speechDemo = '/speech_demo'; // 语音演示 - static const translationList = '/translation/List'; // 翻译历史 - // 测试路由(生产环境建议移除) - static const ttsTest = '/tts_test'; // 文字转语音测试 - static const asrTest = '/asr_test'; // 语音识别测试 - static const azureAsrTest = '/azure_asr_test'; // Azure语音识别 - static const azureTtsTest = '/azure_tts_test'; // Azure文字转语音 - static const volcanoAsrTest = '/volcano_asr_test'; // 火山引擎语音识别 - static const flutterTtsTest = '/flutter_tts_test'; // Flutter TTS测试 - static const flutterAsrTest = '/flutter_asr_test'; // Flutter ASR测试 - static const jieliTest = '/jieli_test'; // 杰理芯片测试 - static const opusTest = '/opus_test'; // Opus编码测试 - static const logExport = '/log_export'; // 日志导出 - static const bleTest = '/ble_test'; // 蓝牙测试 - static const besTest = '/bes_test'; // 恒玄(BES)蓝牙连接测试 - static const speechTest = '/speech_test'; // 综合语音测试 + static const translation = '/translation'; + static const pictureTranslation = '/picture_translation'; + static const textTranslation = '/text_translation'; + static const translationHistory = '/translation/history'; + static const translationList = '/translation/List'; - // 支持服务 - static const feedback = '/feedback'; // 用户反馈 - static const agent = '/agent'; // 在线客服 + // AI 助手 static const emai = '/emai'; // EMAI 助手(阿里百炼多模态对话) - static const navigation = '/navigation'; // 实时导航 - - // 音乐相关 - static const musicPlaylist = '/music/playlist'; // 音乐播放列表 - - // 实时语音对话 - static const realtime = '/realtime'; - - // 移动精灵 - static const mobileElf = '/mobile_elf'; - - // 设备管理 - static const deviceCategory = '/device_category'; // 添加设备第一步:选择产品品类 - static const holderScan = '/holder_scan'; // 蓝讯支架扫描/连接 - static const besScan = '/bes_scan'; // 恒玄耳机(经典蓝牙)连接 - static const plaza = '/plaza'; // 广场(原底部 tab,改成「我的」里的入口) - static const devices = '/devices'; // 扫描页:发现/绑定/连接新设备 - static const fieldRecording = '/field_recording'; // 现场录音 - static const myDevices = '/my_devices'; // 用户已绑定设备列表 - - // ble设备管理 - static const ble = '/ble'; - // ble设备管理 - static const qqmusic = '/qqmusic'; + static const smartcarChat = '/smartcar_chat'; // Smartcar 车载助手(同一套对话 UI,另一个百炼应用) + static const mobileElf = '/mobile_elf'; // 移动精灵 - // 支付相关 - static const payment = '/payment'; // 支付测试页面 + // 广场 + static const plaza = '/plaza'; - //商品购买页面 - static const goodsvip = '/goodsvip'; //vip商品页面 - static const goodstrans = '/goodstrans'; //翻译商品页面 - static const goodsmeet = '/goodsmeet'; //会议商品页面 - static const goodsai = '/goodsai'; //ai商品页面 + // 支付 / 商品 + static const payment = '/payment'; + static const goodsvip = '/goodsvip'; + static const goodstrans = '/goodstrans'; + static const goodsmeet = '/goodsmeet'; } diff --git a/apps/client/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift b/apps/client/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift index b3a66b38..1a87a654 100644 --- a/apps/client/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift +++ b/apps/client/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift @@ -140,8 +140,13 @@ public class BleService: NSObject { } os_log("🔧 开始初始化CBCentralManager", log: logger, type: .info) + // ⚠️ **不要在这里申请状态恢复(restore identifier)。** + // 这个插件 Dart 侧已零引用,只因 agent_service 的原生依赖还链在工程里, + // 但它在 GeneratedPluginRegistrant 里排在 recorder_holder 前面、注册时就建 central。 + // iOS 上同一进程里第二个带 restore identifier 的 central 拿不到真实电源状态 + // (恒为 4=poweredOff),于是真正在用的支架插件 startScan 永远「蓝牙未就绪」。 + // 2026-09-11 iPhone 12 / iOS 26 真机复现;把这里的 restore id 去掉后支架恢复正常。 let options: [String: Any] = [ - CBCentralManagerOptionRestoreIdentifierKey: "BLEAssistantCentral", CBCentralManagerOptionShowPowerAlertKey: true ] diff --git a/apps/client/local_plugins/bluetooth_manager/android/build.gradle b/apps/client/local_plugins/bluetooth_manager/android/build.gradle index ca0a10e7..930dbf12 100644 --- a/apps/client/local_plugins/bluetooth_manager/android/build.gradle +++ b/apps/client/local_plugins/bluetooth_manager/android/build.gradle @@ -29,6 +29,10 @@ android { compileSdk = 36 + // 与主工程一致。NDK r28 起链接器默认 16KB 页对齐;不声明就会退回工具链默认的 + // 老 NDK,产出 p_align=0x1000 的 .so,Google Play 的 16KB 检查直接拒收。 + ndkVersion = "28.2.13676358" + compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 @@ -50,6 +54,8 @@ android { externalNativeBuild { cmake { cppFlags "" + // NDK r27+ 支持,显式要求可变页大小(16KB) + arguments "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON" } } } diff --git a/apps/client/local_plugins/bluetooth_manager/android/src/main/cpp/CMakeLists.txt b/apps/client/local_plugins/bluetooth_manager/android/src/main/cpp/CMakeLists.txt index 72a8282f..be8d39f3 100644 --- a/apps/client/local_plugins/bluetooth_manager/android/src/main/cpp/CMakeLists.txt +++ b/apps/client/local_plugins/bluetooth_manager/android/src/main/cpp/CMakeLists.txt @@ -58,3 +58,9 @@ target_link_libraries(msbc_jni sbc ${log-lib} ) + +# 16KB 页对齐兜底:任何 NDK 版本都生效,不依赖上面 gradle 里的 ndkVersion 声明。 +# Google Play 自 2025-11-01 起要求 64 位 .so 的 LOAD 段 p_align >= 0x4000, +# 不合规直接拒收(无延期)。 +target_link_options(g722_jni PRIVATE "-Wl,-z,max-page-size=16384") +target_link_options(msbc_jni PRIVATE "-Wl,-z,max-page-size=16384") diff --git a/apps/client/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothHelper.kt b/apps/client/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothHelper.kt index 3f5ca6e5..198c50db 100644 --- a/apps/client/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothHelper.kt +++ b/apps/client/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothHelper.kt @@ -66,6 +66,86 @@ class ClassicBluetoothHelper(private val context: Context) { } } + /** + * 发起经典蓝牙配对(A2DP 音频通路的前置动作)。 + * + * ⚠️ **这是 2026-09-11 为车载香薰新增的方法,纯增量**:原有的 + * `getConnectedDevices` / `isBluetoothEnabled` / 状态监听一个字节都没动, + * 依赖本插件的 `azure_speech`(iOS 的 MicrophoneCapture)不受影响。 + * + * Android 上「连 A2DP」的正确做法就是 `createBond()`:配对成功后系统会自己 + * 把 A2DP/HFP 接起来,**没有公开 API 直接连某个 profile**。所以这里只负责配对, + * 连接与否交给系统。返回值语义(对齐 lumi): + * - `already_bonded` 已配对,系统会自动连 + * - `bonding_in_progress` 正在配对 + * - `bonding_started` 已发起配对,系统会弹配对框 + */ + fun connectDevice(macAddress: String, callback: ConnectCallback) { + try { + if (!BluetoothAdapter.checkBluetoothAddress(macAddress)) { + callback.onError("INVALID_MAC", "非法的 MAC 地址: $macAddress") + return + } + if (!hasBluetoothConnectPermission()) { + callback.onError("PERMISSION_DENIED", "缺少 BLUETOOTH_CONNECT 权限") + return + } + val adapter = BluetoothAdapter.getDefaultAdapter() + if (adapter == null) { + callback.onError("NO_ADAPTER", "没有找到蓝牙适配器") + return + } + if (!adapter.isEnabled) { + callback.onError("BT_DISABLED", "蓝牙未开启") + return + } + val device = adapter.getRemoteDevice(macAddress) + val bondState = try { + device.bondState + } catch (e: SecurityException) { + callback.onError("PERMISSION_DENIED", "读取 bondState 失败: ${e.message}") + return + } + when (bondState) { + BluetoothDevice.BOND_BONDED -> callback.onSuccess("already_bonded") + BluetoothDevice.BOND_BONDING -> callback.onSuccess("bonding_in_progress") + else -> { + val started = try { + device.createBond() + } catch (e: SecurityException) { + callback.onError("PERMISSION_DENIED", "createBond 失败: ${e.message}") + return + } + if (started) { + callback.onSuccess("bonding_started") + } else { + callback.onError("BOND_FAILED", "createBond 返回 false") + } + } + } + } catch (e: Exception) { + callback.onError("BLUETOOTH_ERROR", e.message ?: "未知错误") + } + } + + /** + * 这台 MAC 当前是不是已经接上了 A2DP(真正决定"能不能出声"的判据)。 + * 拿不到就回 false,绝不阻塞调用方。 + */ + fun isA2dpConnected(macAddress: String, callback: (Boolean) -> Unit) { + if (!hasBluetoothConnectPermission()) { + callback(false) + return + } + getConnectedBluetoothDevices(BluetoothProfile.A2DP, object : BluetoothDevicesCallback { + override fun onSuccess(devices: List>) { + callback(devices.any { it["address"].equals(macAddress, ignoreCase = true) }) + } + + override fun onError(code: String, message: String) = callback(false) + }) + } + /** * 检查蓝牙是否启用 * @return 蓝牙是否启用 @@ -394,6 +474,12 @@ class ClassicBluetoothHelper(private val context: Context) { fun onSuccess(devices: List>) fun onError(code: String, message: String) } + + /** [connectDevice] 的回调(2026-09-11 新增) */ + interface ConnectCallback { + fun onSuccess(status: String) + fun onError(code: String, message: String) + } /** * 蓝牙状态回调接口 diff --git a/apps/client/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothPlugin.kt b/apps/client/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothPlugin.kt index d2174a77..109e9cc6 100644 --- a/apps/client/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothPlugin.kt +++ b/apps/client/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothPlugin.kt @@ -59,6 +59,26 @@ class ClassicBluetoothPlugin: FlutterPlugin, MethodCallHandler { "isBluetoothEnabled" -> { result.success(bluetoothHelper.isBluetoothEnabled()) } + // ↓ 2026-09-11 为车载香薰新增,原有分支未改动 + "connectDevice" -> { + val mac = call.argument("macAddress") + if (mac.isNullOrEmpty()) { + result.error("INVALID_MAC", "缺少 macAddress", null) + } else { + bluetoothHelper.connectDevice(mac, object : ClassicBluetoothHelper.ConnectCallback { + override fun onSuccess(status: String) = result.success(status) + override fun onError(code: String, message: String) = result.error(code, message, null) + }) + } + } + "isA2dpConnected" -> { + val mac = call.argument("macAddress") + if (mac.isNullOrEmpty()) { + result.success(false) + } else { + bluetoothHelper.isA2dpConnected(mac) { result.success(it) } + } + } else -> { result.notImplemented() } diff --git a/apps/client/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/ClassicBluetoothHelper.swift b/apps/client/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/ClassicBluetoothHelper.swift index 6db8ac02..dde0287f 100644 --- a/apps/client/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/ClassicBluetoothHelper.swift +++ b/apps/client/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/ClassicBluetoothHelper.swift @@ -246,6 +246,23 @@ public class ClassicBluetoothHelper: NSObject, CBCentralManagerDelegate { return portType == .bluetoothA2DP || portType == .bluetoothHFP || portType == .bluetoothLE } + /// 这台 MAC(或设备名)当前是不是正接在音频输出上(= A2DP 通了)。 + /// + /// 2026-09-11 为车载香薰新增。iOS 上 `AVAudioSession` 的 `output.uid` 形如 + /// `A8:1A:B3:21:E4:DD-tacl`,去掉后缀就是**经典蓝牙 MAC**——这也是 iOS 上唯一 + /// 能拿到设备经典 MAC 的地方(BLE 那侧只有 peripheral UUID)。 + /// 传空串时只要有任意蓝牙音频输出就算连上。 + public func isAudioDeviceConnected(address: String) -> Bool { + let devices = getConnectedAudioDevices() + if address.isEmpty { return !devices.isEmpty } + let target = address.uppercased() + return devices.contains { d in + let addr = (d["address"] ?? "").uppercased() + let name = (d["name"] ?? "").uppercased() + return addr == target || name == target + } + } + // 清理设备地址 private func cleanDeviceAddress(_ address: String) -> String { // 移除类似 "-tacl" 的后缀 diff --git a/apps/client/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/SwiftClassicBluetoothPlugin.swift b/apps/client/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/SwiftClassicBluetoothPlugin.swift index 6f445ea1..c5c296b5 100644 --- a/apps/client/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/SwiftClassicBluetoothPlugin.swift +++ b/apps/client/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/SwiftClassicBluetoothPlugin.swift @@ -34,6 +34,15 @@ public class SwiftClassicBluetoothPlugin: NSObject, FlutterPlugin { getConnectedDevices(result: result) case "isBluetoothEnabled": result(bluetoothHelper.isBluetoothEnabled()) + // ↓ 2026-09-11 为车载香薰新增,原有分支未改动 + case "connectDevice": + // iOS **没有**发起经典蓝牙配对的公开 API(Apple 限制), + // 只能引导用户去「设置 → 蓝牙」自己配一次。返回固定串让上层区分平台。 + result("unsupported_ios") + case "isA2dpConnected": + let args = call.arguments as? [String: Any] + let mac = (args?["macAddress"] as? String) ?? "" + result(bluetoothHelper.isAudioDeviceConnected(address: mac)) default: result(FlutterMethodNotImplemented) } diff --git a/apps/client/local_plugins/classic_bluetooth/lib/classic_bluetooth.dart b/apps/client/local_plugins/classic_bluetooth/lib/classic_bluetooth.dart index 2deef982..1a5495e6 100644 --- a/apps/client/local_plugins/classic_bluetooth/lib/classic_bluetooth.dart +++ b/apps/client/local_plugins/classic_bluetooth/lib/classic_bluetooth.dart @@ -23,6 +23,40 @@ class ClassicBluetooth { return await _methodChannel.invokeMethod('isBluetoothEnabled'); } + /// 发起经典蓝牙配对(A2DP 出声的前置动作)。**2026-09-11 为车载香薰新增。** + /// + /// 返回原生层的状态串: + /// - Android:`already_bonded` / `bonding_in_progress` / `bonding_started` + /// (Android 没有"直接连某个 profile"的公开 API,配对成功后系统自己接 A2DP) + /// - iOS:恒为 `unsupported_ios` —— Apple 不提供发起经典蓝牙配对的接口, + /// 只能引导用户去「设置 → 蓝牙」手动配一次 + /// + /// 失败抛 [PlatformException](`INVALID_MAC` / `PERMISSION_DENIED` / + /// `BT_DISABLED` / `NO_ADAPTER` / `BOND_FAILED`)。 + static Future connectDevice(String macAddress) async { + return await _methodChannel.invokeMethod( + 'connectDevice', + {'macAddress': macAddress}, + ); + } + + /// 这台 MAC 当前是不是已经接上音频通路(A2DP)。**2026-09-11 新增。** + /// + /// Android 查 `BluetoothProfile.A2DP` 的已连接列表; + /// iOS 查 `AVAudioSession` 的当前输出(`uid` 去掉后缀就是经典蓝牙 MAC)。 + /// 拿不到一律 false,不抛。 + static Future isA2dpConnected(String macAddress) async { + try { + return await _methodChannel.invokeMethod( + 'isA2dpConnected', + {'macAddress': macAddress}, + ) ?? + false; + } catch (_) { + return false; + } + } + /// 监听蓝牙事件(状态变化、设备连接/断开) static Stream get events { _eventStream ??= _eventChannel diff --git a/apps/client/local_plugins/device_jieli/ios/device_jieli/Package.swift b/apps/client/local_plugins/device_jieli/ios/device_jieli/Package.swift index ef3ec31c..e476e898 100644 --- a/apps/client/local_plugins/device_jieli/ios/device_jieli/Package.swift +++ b/apps/client/local_plugins/device_jieli/ios/device_jieli/Package.swift @@ -20,6 +20,14 @@ let package = Package( // recorder_holder(蓝讯支架)也要用同一份,跨包同名 target 会冲突, // 所以这里以产品形式暴露,供其复用。 .library(name: "jl-audio-unit-kit", targets: ["JLAudioUnitKit"]), + // JL_BLEKit.xcframework(杰理 BLE + RCSP 认证,**动态库**)同理暴露给 + // device_smartcar(车载香薰)复用:Smartcar 固件要求先过 JL_Assist 的 RCSP + // 认证才把手机当成已连接。再 vendor 一份动态库会在运行时报 + // 「Class JL_xxx is implemented in both …」且行为不可预期,所以只能共享这一份。 + .library(name: "jl-blekit", targets: ["JL_BLEKit"]), + // JL_OTALib.xcframework(杰理 OTA)同理暴露给 device_smartcar:Smartcar 固件升级走 + // cmdOTAData + stage2 扫描回连(lumi 的做法)。 + .library(name: "jl-otalib", targets: ["JL_OTALib"]), ], dependencies: [], targets: [ diff --git a/apps/client/local_plugins/device_jieli/pubspec.yaml b/apps/client/local_plugins/device_jieli/pubspec.yaml index b82ad95f..d1466156 100644 --- a/apps/client/local_plugins/device_jieli/pubspec.yaml +++ b/apps/client/local_plugins/device_jieli/pubspec.yaml @@ -37,9 +37,9 @@ flutter: # adding or updating assets for this project. plugin: platforms: - android: - package: com.jielihome.jielihome - pluginClass: JielihomePlugin + # ⚠️ Android 已不再装配:Dart 侧不再使用杰理,且它的 Android 模块依赖 + # device_plugin_interface 的原生工程(已改成纯 Dart 契约)。 + # 只保留 iOS:recorder_holder 的 Package.swift 引用本插件 vendor 的 JLAudioUnitKit。 ios: pluginClass: JielihomePlugin sharedDarwinSource: false diff --git a/apps/client/local_plugins/device_plugin_interface/android/build.gradle b/apps/client/local_plugins/device_plugin_interface/android/build.gradle deleted file mode 100644 index 821b1198..00000000 --- a/apps/client/local_plugins/device_plugin_interface/android/build.gradle +++ /dev/null @@ -1,37 +0,0 @@ -buildscript { - repositories { - google() - mavenCentral() - } - dependencies { - classpath "com.android.tools.build:gradle:8.7.3" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0" - } -} - -apply plugin: "com.android.library" -apply plugin: "kotlin-android" - -android { - namespace "com.aiagent.device_plugin_interface" - compileSdk 35 - - defaultConfig { - minSdk 24 - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = "17" - } -} - -dependencies { - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0" - // 注意:本包不依赖任何 native 厂商实现;它只定义接口与数据类, - // 厂商插件(device_jieli 等)依赖它来 implement,不能反向依赖。 -} diff --git a/apps/client/local_plugins/device_plugin_interface/android/src/main/AndroidManifest.xml b/apps/client/local_plugins/device_plugin_interface/android/src/main/AndroidManifest.xml deleted file mode 100644 index 31aa4282..00000000 --- a/apps/client/local_plugins/device_plugin_interface/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,3 +0,0 @@ - - diff --git a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/Assistant.kt b/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/Assistant.kt deleted file mode 100644 index 81c54fb5..00000000 --- a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/Assistant.kt +++ /dev/null @@ -1,149 +0,0 @@ -package com.aiagent.device_plugin_interface - -import kotlinx.coroutines.flow.Flow - -/** - * AI 助理场景的音频载荷编码。 - * - * 与 [CallAudioCodec] 并列但语义独立 —— AI 助理是单向对话(用户麦 → AI → 耳机扬声器), - * 没有通话翻译的 UPLINK/DOWNLINK 概念。 - */ -enum class AssistantAudioCodec { OPUS, PCM_S16LE } - -/** AI 助理场景的音频格式描述。 */ -data class AssistantAudioFormat( - val codec: AssistantAudioCodec, - val sampleRate: Int, - val channels: Int, - val frameMs: Int, -) { - companion object { - /** 16 kHz / mono / 20 ms 一帧 OPUS(耳机原生格式) */ - val OPUS_16K_MONO_20MS = AssistantAudioFormat(AssistantAudioCodec.OPUS, 16000, 1, 20) - - /** 16 kHz / mono / 20 ms 一帧 PCM_S16LE = 640 字节 */ - val PCM_S16LE_16K_MONO_20MS = AssistantAudioFormat(AssistantAudioCodec.PCM_S16LE, 16000, 1, 20) - } -} - -/** - * device → 编排器:一帧用户麦克风音频(单路上行)。 - * - * 与 [CallAudioFrame] 的区别:**无 leg 字段**。AI 助理场景只有"用户说话"一路输入, - * 不存在"远端通话音"的概念。 - */ -data class AssistantAudioFrame( - val codec: AssistantAudioCodec, - val sampleRate: Int, - val channels: Int, - val bytes: ByteArray, - /** 单调递增帧序号;丢帧后**不得**回填。 */ - val sequence: Long, - /** 单调递增的捕获时间戳(微秒)。 */ - val timestampUs: Long, -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is AssistantAudioFrame) return false - return sequence == other.sequence && bytes.contentEquals(other.bytes) - } - override fun hashCode(): Int { - var r = sequence.hashCode() - r = 31 * r + bytes.contentHashCode() - return r - } -} - -/** - * 编排器 → device:把 AI 的 TTS 音频回灌给耳机扬声器播放。 - * - * 与 [TranslatedAudioFrame] 的区别:**无 leg 字段**。AI 助理只有一个回放方向 - * (AI 回复 → 戴耳机的用户),不存在"回灌给对端"的概念。 - * - * @param isFinal 本帧是否为当前 utterance 的最后一帧。device 端可能据此决定是否 - * 触发整段编码 / 一次性下发(例如 jieli RCSP 场景下按"一段 = 一个 AudioData"下发)。 - */ -data class AssistantPlaybackFrame( - val codec: AssistantAudioCodec, - val sampleRate: Int, - val channels: Int, - val bytes: ByteArray, - val isFinal: Boolean = false, -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is AssistantPlaybackFrame) return false - return codec == other.codec && bytes.contentEquals(other.bytes) - } - override fun hashCode(): Int { - var r = codec.hashCode() - r = 31 * r + bytes.contentHashCode() - return r - } -} - -/** AI 助理场景下由 device 抛出的错误(不致命:编排器决定是否 stop)。 */ -data class AssistantError( - val code: String, - val message: String, -) - -/** - * AI 助理设备能力端口(device 侧)。 - * - * 由设备厂商插件按需实现(例如杰理基于 RCSP `MODE_CALL_TRANSLATION` 的 `UP_LINK` 上行 + - * `OUT_UPLINK` 回灌落地一份 `JieliAssistantPort`)。`assistant_server` 编排器统一通过 - * 本接口拿用户麦克风 PCM、回灌 AI TTS,不依赖具体 vendor。 - * - * 与 [DeviceCallTranslationPort] 并列但**语义完全独立**: - * - 不存在 leg 概念(通话翻译特有的上下行) - * - 上行流只有一路(用户麦) - * - 下行回灌只有一路(耳机扬声器) - * - * 生命周期: - * ``` - * idle → enter(format) → active → exit() → idle - * ``` - * - * 铁律: - * - 同一设备同一时刻**至多一个** active 端口;重复 `enter` 抛 - * `IllegalStateException("device.assistant.busy")`; - * - 协商格式([enter] 入参)必须出自 [supportedSourceFormats] 列出的范围; - * - [reportPlayback] 的 codec/sampleRate/channels 必须落在 [supportedSinkFormats] 内; - * - [exit] 后 [audioFrames]/[errors] 仍可订阅,但不再产新事件。 - */ -interface DeviceAssistantPort { - /** 该端口能向上派发的用户麦克风音频格式集合。 */ - fun supportedSourceFormats(): Set - - /** 该端口能接受的 TTS 回灌格式集合。 */ - fun supportedSinkFormats(): Set - - /** - * 进入 AI 助理模式。 - * - * @param sourceFormat 协商好的源音频格式(必须 ∈ [supportedSourceFormats])。 - * device 侧据此决定是否做 OPUS↔PCM 转换。 - */ - fun enter(sourceFormat: AssistantAudioFormat) - - /** - * 用户麦克风上行音频帧流。`enter` 之后开始派发,`exit` 后停止。 - * 必须是 broadcast / replayable 不变的实现,编排器多次订阅安全。 - */ - val audioFrames: Flow - - /** - * 把 AI 的 TTS 音频回灌给耳机扬声器。 - * - * @throws IllegalArgumentException codec 不在 [supportedSinkFormats] 内 - * @throws IllegalStateException 当前未在 active 状态 - */ - fun reportPlayback(frame: AssistantPlaybackFrame) - - /** 退出 AI 助理模式,归还设备 RCSP / 音频通道。 */ - fun exit() - - /** 错误流。**不致命**——编排器自行决定是否 [exit]。 */ - val errors: Flow -} diff --git a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/CallRecording.kt b/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/CallRecording.kt deleted file mode 100644 index 50c11d91..00000000 --- a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/CallRecording.kt +++ /dev/null @@ -1,126 +0,0 @@ -package com.aiagent.device_plugin_interface - -import kotlinx.coroutines.flow.Flow - -/** - * 通话录音两条腿(leg)的方向: - * - [UPLINK]: 本端说出去(戴耳机的人 / 会议本地参会者) → 录音 - * - [DOWNLINK]: 对端说过来(远端通话音 / 会议参会对方) → 录音 - * - * 与 [CallTranslationLeg] 同义;区分独立枚举仅为防止跨场景误用。 - */ -enum class CallRecordingLeg { UPLINK, DOWNLINK } - -/** 通话录音音频载荷的编码。 */ -enum class CallRecordingAudioCodec { OPUS, PCM_S16LE } - -/** 通话录音协商时使用的音频格式描述。 */ -data class CallRecordingAudioFormat( - val codec: CallRecordingAudioCodec, - val sampleRate: Int, - val channels: Int, - val frameMs: Int, -) { - companion object { - /** 16 kHz / mono / 20 ms 一帧 OPUS(耳机原生格式) */ - val OPUS_16K_MONO_20MS = CallRecordingAudioFormat(CallRecordingAudioCodec.OPUS, 16000, 1, 20) - - /** 16 kHz / mono / 20 ms 一帧 PCM_S16LE = 640 字节 */ - val PCM_S16LE_16K_MONO_20MS = CallRecordingAudioFormat(CallRecordingAudioCodec.PCM_S16LE, 16000, 1, 20) - } -} - -/** - * device → 编排器:一帧通话录音音频。 - * - * 与 [CallAudioFrame] 同形但语义独立 —— 通话录音不需要 TTS 回灌,因此对应的端口里 - * 没有 [DeviceCallTranslationPort.reportTranslated] 这种回写接口。 - */ -data class CallRecordingFrame( - val leg: CallRecordingLeg, - val codec: CallRecordingAudioCodec, - val sampleRate: Int, - val channels: Int, - val bytes: ByteArray, - /** 单调递增帧序号;丢帧后**不得**回填。 */ - val sequence: Long, - /** 单调递增的捕获时间戳(微秒)。 */ - val timestampUs: Long, -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is CallRecordingFrame) return false - return leg == other.leg && sequence == other.sequence && bytes.contentEquals(other.bytes) - } - override fun hashCode(): Int { - var r = leg.hashCode() - r = 31 * r + sequence.hashCode() - r = 31 * r + bytes.contentHashCode() - return r - } -} - -/** 通话录音过程中由 device 抛出的错误(不致命:编排器决定是否 stop)。 */ -data class CallRecordingError( - val code: String, - val message: String, -) - -/** - * 通话录音能力端口(device 侧)。 - * - * 应用场景:会议记录 / 通话存证 / 通话转写。耳机持续把**本端 + 对端**两路音频 - * 同步上推给 APP,APP 落盘或交给 ASR/纪要服务做后续处理。 - * - * 由设备厂商插件按需实现,例如杰理基于 RCSP `MODE_CALL_TRANSLATION_WITH_STEREO`(=6) - * + `STRATEGY_DEVICE_ALWAYS_RECORDING` + 双声道 OPUS(SOURCE_E_SCO_MIX)落地一份 - * `JieliCallRecordingPort`(左=UPLINK、右=DOWNLINK 反交织成 mono 双流)。 - * - * # 与 [DeviceCallTranslationPort] 的区别 - * 两者都按 leg 派发音频,但通话录音是**单向上报**: - * - 没有 TTS 回灌(无 `reportTranslated` / `reportPlayback`),编排器只读不写 - * - 一般也不依赖真实通话(`MODE_RECORDING_TRANSLATION` 不需要 eSCO 通话存在), - * 适合「会议中的环境录音 + 远端通话录音混合」场景 - * - * # 与 [DeviceAssistantPort] 的区别 - * AI 助理是单路上行(用户麦),通话录音是**双路上行**(按 leg)。 - * - * 生命周期: - * ``` - * idle → enter(format) → active → exit() → idle - * ``` - * - * 铁律: - * - 同一设备同一时刻**至多一个** active 端口(与 callTranslation / assistant 共用底层 - * RCSP 状态机互斥);重复 `enter` 抛 `IllegalStateException("device.call_recording.busy")` - * - 协商格式([enter] 入参)必须出自 [supportedSourceFormats] 列出的范围; - * - [exit] 后 [audioFrames]/[errors] 仍可订阅,但不再产新事件。 - */ -interface DeviceCallRecordingPort { - /** 该端口能向上派发的音频源格式集合(per-leg mono)。 */ - fun supportedSourceFormats(): Set - - /** - * 进入通话录音模式。 - * - * @param sourceFormat 协商好的源音频格式(必须 ∈ [supportedSourceFormats])。 - * device 侧据此决定是否做 OPUS↔PCM 转换:例如耳机原生发 stereo OPUS, - * APP 只吃 mono PCM 时 device 内部解码 + 反交织后再按 leg 派发到 [audioFrames]。 - */ - fun enter(sourceFormat: CallRecordingAudioFormat) - - /** - * 上行/下行通话录音帧。`enter` 之后开始派发,`exit` 后停止。 - * 必须是 broadcast / replayable 不变的实现,编排器多次订阅安全。 - * - * 帧到达顺序(UPLINK vs DOWNLINK)由 device 实现保证「时序基本对齐」即可, - * 不要求严格交替。消费方应以各 leg 自己的 `timestampUs` 做时间轴。 - */ - val audioFrames: Flow - - /** 退出通话录音模式,归还设备 RCSP / 音频通道。幂等。 */ - fun exit() - - /** 错误流。**不致命**——编排器自行决定是否 [exit]。 */ - val errors: Flow -} diff --git a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/CallTranslation.kt b/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/CallTranslation.kt deleted file mode 100644 index 1b64ef32..00000000 --- a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/CallTranslation.kt +++ /dev/null @@ -1,139 +0,0 @@ -package com.aiagent.device_plugin_interface - -import kotlinx.coroutines.flow.Flow - -/** - * 通话翻译两条腿(leg)的方向: - * - [UPLINK]: 用户说出去(手机麦/耳机麦) → 翻译给对方 - * - [DOWNLINK]: 对方说过来(远端通话音) → 翻译给用户 - */ -enum class CallTranslationLeg { UPLINK, DOWNLINK } - -/** 通话翻译音频载荷的编码。 */ -enum class CallAudioCodec { OPUS, PCM_S16LE } - -/** 通话翻译协商时使用的音频格式描述。 */ -data class CallAudioFormat( - val codec: CallAudioCodec, - val sampleRate: Int, - val channels: Int, - val frameMs: Int, -) { - companion object { - val OPUS_16K_MONO_20MS = CallAudioFormat(CallAudioCodec.OPUS, 16000, 1, 20) - val PCM_S16LE_16K_MONO_20MS = CallAudioFormat(CallAudioCodec.PCM_S16LE, 16000, 1, 20) - } -} - -/** device → 编排器:一帧通话翻译音频。 */ -data class CallAudioFrame( - val leg: CallTranslationLeg, - val codec: CallAudioCodec, - val sampleRate: Int, - val channels: Int, - val bytes: ByteArray, - /** 单调递增帧序号;丢帧后**不得**回填。 */ - val sequence: Long, - /** 单调递增的捕获时间戳(微秒)。 */ - val timestampUs: Long, -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is CallAudioFrame) return false - return leg == other.leg && sequence == other.sequence && bytes.contentEquals(other.bytes) - } - override fun hashCode(): Int { - var r = leg.hashCode() - r = 31 * r + sequence.hashCode() - r = 31 * r + bytes.contentHashCode() - return r - } -} - -/** 编排器 → device:把已翻译的 TTS 音频回灌到指定 leg。 - * - * @param isFinal 本帧是否为当前 utterance 的最后一帧。device 端可能据此决定是否触发整段编码 / 一次性下发 - * (例如 jieli 通话翻译走 RCSP 时,需要按"一段 = 一个 AudioData"下发)。 - */ -data class TranslatedAudioFrame( - val leg: CallTranslationLeg, - val codec: CallAudioCodec, - val sampleRate: Int, - val channels: Int, - val bytes: ByteArray, - val isFinal: Boolean = false, -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is TranslatedAudioFrame) return false - return leg == other.leg && codec == other.codec && bytes.contentEquals(other.bytes) - } - override fun hashCode(): Int { - var r = leg.hashCode() - r = 31 * r + codec.hashCode() - r = 31 * r + bytes.contentHashCode() - return r - } -} - -/** 通话翻译过程中由 device 抛出的错误(不致命:编排器决定是否 stop)。 */ -data class CallTranslationError( - val code: String, - val message: String, -) - -/** - * 通话翻译能力端口(device 侧)。 - * - * 由设备厂商插件按需实现,例如杰理基于 RCSP `MODE_CALL_TRANSLATION` 落地一份 - * `JieliCallTranslationPort`。`translate_server` 编排器统一通过本接口拿音频帧、 - * 回灌 TTS,不依赖具体 vendor。 - * - * 生命周期: - * ``` - * idle → enter(format) → active → exit() → idle - * ``` - * - * 铁律: - * - 同一设备同一时刻**至多一个** active 端口;重复 `enter` 抛 - * `IllegalStateException("device.call_translation.busy")`; - * - 协商格式([enter] 入参)必须出自 [supportedSourceFormats] 列出的范围; - * - [reportTranslated] 的 codec/sampleRate/channels 必须落在 [supportedSinkFormats] 内; - * - [exit] 后 [audioFrames]/[errors] 仍可订阅,但不再产新事件。 - */ -interface DeviceCallTranslationPort { - /** 该端口能向上派发的音频源格式集合。 */ - fun supportedSourceFormats(): Set - - /** 该端口能接受的 TTS 回灌格式集合。 */ - fun supportedSinkFormats(): Set - - /** - * 进入通话翻译模式。 - * - * @param sourceFormat 协商好的源音频格式(必须 ∈ [supportedSourceFormats])。 - * device 侧据此决定是否做 OPUS↔PCM 转换:例如耳机原生发 OPUS,agent 只吃 - * PCM 时编排器协商出 PCM,device 内部解码后再派发到 [audioFrames]。 - */ - fun enter(sourceFormat: CallAudioFormat) - - /** - * 上行/下行音频帧。`enter` 之后开始派发,`exit` 后停止。 - * 必须是 broadcast / replayable 不变的实现,编排器多次订阅安全。 - */ - val audioFrames: Flow - - /** - * 把已翻译的 TTS 音频回灌到指定 leg。 - * - * @throws IllegalArgumentException codec 不在 [supportedSinkFormats] 内 - * @throws IllegalStateException 当前未在 active 状态 - */ - fun reportTranslated(frame: TranslatedAudioFrame) - - /** 退出通话翻译模式,归还设备 RCSP / 音频通道。 */ - fun exit() - - /** 错误流。**不致命**——编排器自行决定是否 [exit]。 */ - val errors: Flow -} diff --git a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/DevicePluginInterfacePlugin.kt b/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/DevicePluginInterfacePlugin.kt deleted file mode 100644 index 66775506..00000000 --- a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/DevicePluginInterfacePlugin.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.aiagent.device_plugin_interface - -import io.flutter.embedding.engine.plugins.FlutterPlugin - -/** No-op plugin class — device_plugin_interface only provides native interfaces and data classes. */ -class DevicePluginInterfacePlugin : FlutterPlugin { - override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {} - override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {} -} diff --git a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceManager.kt b/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceManager.kt deleted file mode 100644 index a37ceb4f..00000000 --- a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceManager.kt +++ /dev/null @@ -1,93 +0,0 @@ -package com.aiagent.device_plugin_interface - -import kotlinx.coroutines.flow.Flow - -/** 容器 → app 的聚合事件类型(与 Dart [DeviceManagerEventType] 对齐)。 */ -enum class DeviceManagerEventType { - MANAGER_READY, - VENDOR_CHANGED, - BLUETOOTH_STATE_CHANGED, - SCAN_STARTED, - SCAN_STOPPED, - DEVICE_DISCOVERED, - ACTIVE_SESSION_CHANGED, - SESSION_EVENT, - /** - * 设备完整快照变化。**任何**改动(连接态、电量、固件、活跃 session 切换) - * 都会产生一份新的快照供 Dart 直接 mirror,Dart 端不再做字段 diff。 - */ - SNAPSHOT_UPDATED, - ERROR, -} - -data class DeviceManagerEvent( - val type: DeviceManagerEventType, - val vendorKey: String? = null, - val bluetoothEnabled: Boolean? = null, - val discovered: DiscoveredDevice? = null, - val activeDeviceId: String? = null, - val sessionEvent: DeviceSessionEvent? = null, - /** - * SNAPSHOT_UPDATED / ACTIVE_SESSION_CHANGED / SESSION_EVENT 一律附带;null - * 表示当前没有 active session(vendor 未选 / 已断开)。 - * 由 [com.aiagent.device_manager.DefaultNativeDeviceManager] 在每次状态变化 - * 时统一序列化,供 Dart MethodChannel facade 整体替换缓存。 - */ - val sessionSnapshot: Map? = null, - val errorCode: String? = null, - val errorMessage: String? = null, -) - -/** 设备触发 agent 的事件(PTT / 翻译键 / 挂断键)。 */ -data class DeviceAgentTrigger( - val deviceId: String, - val kind: Kind, - val payload: Map = emptyMap(), -) { - enum class Kind { CHAT, TRANSLATE, STOP } -} - -/** - * 设备路由器 native 抽象(与 Dart [DeviceManager] 等价)。 - * - * 进程内单例(典型实现:[com.aiagent.device_manager.DefaultNativeDeviceManager])。 - * - * 单设备 / 单 vendor 模型: - * - [activeSession] 至多一个;新 [connect] 自动断开旧 session - * - [useVendor] 是原子操作:stopScan → disconnect → 旧 plugin.dispose → - * 新 plugin.initialize → emit [DeviceManagerEventType.VENDOR_CHANGED] - * - 切换中所有 scan/connect 抛 [DeviceException]([DeviceErrorCode.VENDOR_SWITCHING]) - */ -interface NativeDeviceManager { - /** 当前 active vendor key;未选为 null。 */ - val activeVendor: String? - - val activeCapabilities: Set - - val activeSession: NativeDeviceSession? - - /** 列出全部已注册的 vendor(来自 [NativeDevicePluginRegistry])。 */ - fun listVendors(): List - - /** 切换到指定 vendor;vendor=null 等价于 [clearVendor]。 */ - fun useVendor(vendorKey: String, config: DevicePluginConfig) - - /** 清掉当前 vendor:disconnect → dispose 当前 plugin。 */ - fun clearVendor() - - fun startScan(filter: DeviceScanFilter? = null, timeoutMs: Long? = null) - fun stopScan() - fun bondedDevices(): List - - fun connect(deviceId: String, options: DeviceConnectOptions? = null): NativeDeviceSession - fun disconnect() - - /** 容器级聚合事件流(多订阅安全)。 */ - val eventStream: Flow - - /** 设备主动触发 agent 的事件流。 */ - val agentTriggers: Flow - - fun initialize() - fun dispose() -} diff --git a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDevicePlugin.kt b/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDevicePlugin.kt deleted file mode 100644 index 548cde6f..00000000 --- a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDevicePlugin.kt +++ /dev/null @@ -1,149 +0,0 @@ -package com.aiagent.device_plugin_interface - -import kotlinx.coroutines.flow.Flow - -/** - * 厂商插件 → 容器的事件类型。 - */ -enum class DevicePluginEventType { - PLUGIN_READY, - PLUGIN_DISPOSED, - BLUETOOTH_STATE_CHANGED, - SCAN_STARTED, - SCAN_STOPPED, - DEVICE_DISCOVERED, - BOND_STATE_CHANGED, - CONNECTION_STATE_CHANGED, - DEVICE_INFO_UPDATED, - WAKE_TRIGGERED, - CUSTOM_EVENT, - ERROR, -} - -data class DevicePluginEvent( - val type: DevicePluginEventType, - val deviceId: String? = null, - val discovered: DiscoveredDevice? = null, - val connectionState: DeviceConnectionState? = null, - val deviceInfo: DeviceInfo? = null, - val bluetoothEnabled: Boolean? = null, - val bondState: String? = null, // 'none' | 'bonding' | 'bonded' - val wake: DeviceWakeEvent? = null, - val customKey: String? = null, - val customPayload: Map? = null, - val errorCode: String? = null, - val errorMessage: String? = null, -) - -/** - * 厂商插件 native 抽象(与 Dart [DevicePlugin] 等价)。 - * - * 每家芯片/SDK 一份实现: - * - `JieliNativeDevicePlugin` (设备厂商:杰理) - * - 后续:恒玄 / 高通 / 中科蓝讯 等 - * - * 实现方在自己 FlutterPlugin.onAttachedToEngine 时把工厂注册到 - * [NativeDevicePluginRegistry],例如: - * ```kotlin - * NativeDevicePluginRegistry.register("jieli") { JieliNativeDevicePlugin(context) } - * ``` - * - * 容器 [NativeDeviceManager] 通过 vendorKey 查工厂,按需创建实例并管理生命周期。 - * - * 铁律(与 Dart 接口完全对齐): - * 1. `initialize` 幂等;重复调用先释放旧资源。 - * 2. `dispose` 必须释放**所有** native 资源 + close 事件流。 - * 3. `dispose` 后任何方法抛 [IllegalStateException]。 - * 4. 通过 [eventStream]([Flow])派发事件,多订阅安全(用 `MutableSharedFlow.replay=0`)。 - */ -interface NativeDevicePlugin { - val vendorKey: String - val displayName: String - val capabilities: Set - - /** 初始化 SDK;失败抛 [DeviceException]。 */ - fun initialize(config: DevicePluginConfig) - - fun startScan(filter: DeviceScanFilter? = null, timeoutMs: Long? = null) - fun stopScan() - fun isScanning(): Boolean - - /** 已配对设备快照(含历史/系统配对)。 */ - fun bondedDevices(): List - - /** - * 建立会话;必须在握手完成(state=READY)之后才 return; - * 失败抛 [DeviceException]。 - */ - fun connect(deviceId: String, options: DeviceConnectOptions? = null): NativeDeviceSession - - /** 当前 active session(最多一个)。 */ - val activeSession: NativeDeviceSession? - - /** 全局事件流:扫描/连接/蓝牙开关/错误等。 */ - val eventStream: Flow - - /** 释放 SDK + 断开所有 session + close stream。 */ - fun dispose() -} - -/** 厂商插件工厂。 */ -typealias NativeDevicePluginFactory = () -> NativeDevicePlugin - -/** - * 厂商插件全局注册表(参照 NativeAgentRegistry 模式)。 - * - * 每个 device_ 包在自己的 FlutterPlugin.onAttachedToEngine 时注册一次工厂, - * 容器 [NativeDeviceManager] 通过 vendorKey 创建实例。 - */ -object NativeDevicePluginRegistry { - - private val factories = mutableMapOf() - private val descriptors = mutableMapOf() - - /** 注册厂商(重复 register 用新工厂覆盖旧的)。 */ - fun register( - vendorKey: String, - displayName: String, - capabilities: Set, - factory: NativeDevicePluginFactory, - ) { - factories[vendorKey] = factory - descriptors[vendorKey] = VendorDescriptor( - vendorKey = vendorKey, - displayName = displayName, - capabilities = capabilities, - ) - } - - fun unregister(vendorKey: String) { - factories.remove(vendorKey) - descriptors.remove(vendorKey) - } - - fun create(vendorKey: String): NativeDevicePlugin { - val f = factories[vendorKey] - ?: throw DeviceException( - DeviceErrorCode.NOT_SUPPORTED, - "vendor \"$vendorKey\" not registered. Available: ${factories.keys}", - ) - return f() - } - - fun listVendors(): List = descriptors.values.toList() - - fun isRegistered(vendorKey: String): Boolean = factories.containsKey(vendorKey) -} - -/** 用于 listVendors() 给上层 UI 渲染下拉选项。 */ -data class VendorDescriptor( - val vendorKey: String, - val displayName: String, - val capabilities: Set, -) { - fun toMap(): Map = mapOf( - "vendorKey" to vendorKey, - "displayName" to displayName, - "capabilities" to capabilities.map { it.name }, - ) -} diff --git a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceSession.kt b/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceSession.kt deleted file mode 100644 index 04297b62..00000000 --- a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceSession.kt +++ /dev/null @@ -1,88 +0,0 @@ -package com.aiagent.device_plugin_interface - -import kotlinx.coroutines.flow.Flow - -/** 单设备会话事件类型(与 Dart [DeviceSessionEventType] 对齐)。 */ -enum class DeviceSessionEventType { - CONNECTION_STATE_CHANGED, - DEVICE_INFO_UPDATED, - FEATURE, - RSSI_UPDATED, - RAW, - ERROR, -} - -data class DeviceSessionEvent( - val type: DeviceSessionEventType, - val deviceId: String, - val connectionState: DeviceConnectionState? = null, - val deviceInfo: DeviceInfo? = null, - val feature: DeviceFeatureEvent? = null, - val rssi: Int? = null, - val raw: Map? = null, - val errorCode: String? = null, - val errorMessage: String? = null, -) - -/** - * 已连接设备的 native 会话句柄(与 Dart [DeviceSession] 等价)。 - * - * 生命周期:connecting → linkConnected → ready → (业务调用) → disconnecting → disconnected - * - * 铁律: - * 1. `disconnected` 之后任何方法抛 [IllegalStateException] - * 2. [eventStream] 是 broadcast / multi-subscriber-safe - * 3. [invokeFeature] / [readBattery] / [refreshInfo] 在状态非 READY 时抛 - * [DeviceException]([DeviceErrorCode.NO_ACTIVE_SESSION]),禁止静默排队 - */ -interface NativeDeviceSession { - val deviceId: String - val vendor: String - val state: DeviceConnectionState - val info: DeviceInfo - val capabilities: Set - - val eventStream: Flow - - fun readRssi(): Int - - /** 读电量;不支持时返回 null(不抛)。 */ - fun readBattery(): Int? - - /** 强制刷新 [DeviceInfo](电量/固件版本/序列号)。 */ - fun refreshInfo(): DeviceInfo - - /** - * 调用厂商私有 feature。`featureKey` 形如: - * - `common.battery.subscribe` - * - `jieli.translation.start` - * - `bes.eq.set` - */ - fun invokeFeature(featureKey: String, args: Map = emptyMap()): Map - - /** - * 该 session 暴露的通话翻译端口;vendor 无该能力时返回 null。 - * - * 给 native 编排器(translate_server)vendor-agnostic 拿端口的入口—— - * 编排器只调本接口,不需要 import 任何具体厂商类型。 - */ - fun callTranslationPort(): DeviceCallTranslationPort? = null - - /** - * 该 session 暴露的 AI 助理端口;vendor 无该能力时返回 null。 - * - * 给 native 编排器(assistant_server)vendor-agnostic 拿端口的入口—— - * 与 [callTranslationPort] 语义独立(AI 助理为单向对话,无 UPLINK/DOWNLINK 两条腿)。 - */ - fun assistantPort(): DeviceAssistantPort? = null - - /** - * 该 session 暴露的 OTA 端口;vendor 无 [DeviceCapability.OTA] 时返回 null。 - * - * 编排器 / UI 通过本接口拿到 vendor-agnostic 的 OTA 控制;不依赖具体厂商。 - * 端口生命周期与 session 绑定 —— session disconnect 时端口必须自动收尾。 - */ - fun otaPort(): DeviceOtaPort? = null - - fun disconnect() -} diff --git a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceTypes.kt b/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceTypes.kt deleted file mode 100644 index d4e4f667..00000000 --- a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/NativeDeviceTypes.kt +++ /dev/null @@ -1,208 +0,0 @@ -package com.aiagent.device_plugin_interface - -/** 设备能力(与 Dart [DeviceCapability] 一一对应)。 */ -enum class DeviceCapability { - SCAN, - CONNECT, - BOND, - BATTERY, - RSSI, - OTA, - EQ, - ANC, - KEY_MAPPING, - WEAR_DETECTION, - MIC_UPLINK, - SPEAKER_DOWNLINK, - WAKE_WORD, - ON_DEVICE_CALL_TRANSLATION, - ON_DEVICE_FACE_TO_FACE_TRANSLATION, - ON_DEVICE_RECORDING_TRANSLATION, - CUSTOM_COMMAND, -} - -/** 连接状态机(与 Dart [DeviceConnectionState] 一一对应)。 */ -enum class DeviceConnectionState { - DISCONNECTED, - CONNECTING, - LINK_CONNECTED, - READY, - DISCONNECTING, -} - -/** 厂商插件初始化配置。 */ -data class DevicePluginConfig( - val appKey: String? = null, - val appSecret: String? = null, - val extra: Map = emptyMap(), -) { - companion object { - fun fromMap(map: Map<*, *>?): DevicePluginConfig { - if (map == null) return DevicePluginConfig() - return DevicePluginConfig( - appKey = map["appKey"] as? String, - appSecret = map["appSecret"] as? String, - extra = (map["extra"] as? Map<*, *>) - ?.entries - ?.associate { it.key.toString() to it.value } - ?: emptyMap(), - ) - } - } -} - -/** 扫描过滤条件。 */ -data class DeviceScanFilter( - val namePrefix: String? = null, - val nameList: List? = null, - val serviceUuids: List? = null, - val vendor: String? = null, - val minRssi: Int? = null, - val skipUnnamed: Boolean? = null, -) { - companion object { - fun fromMap(map: Map<*, *>?): DeviceScanFilter? { - if (map == null) return null - @Suppress("UNCHECKED_CAST") - return DeviceScanFilter( - namePrefix = map["namePrefix"] as? String, - nameList = (map["nameList"] as? List<*>)?.map { it.toString() }, - serviceUuids = (map["serviceUuids"] as? List<*>)?.map { it.toString() }, - vendor = map["vendor"] as? String, - minRssi = (map["minRssi"] as? Number)?.toInt(), - skipUnnamed = map["skipUnnamed"] as? Boolean, - ) - } - } -} - -/** 连接选项。 */ -data class DeviceConnectOptions( - val timeoutMs: Long = 15_000, - val extra: Map = emptyMap(), -) { - companion object { - fun fromMap(map: Map<*, *>?): DeviceConnectOptions { - if (map == null) return DeviceConnectOptions() - return DeviceConnectOptions( - timeoutMs = (map["timeoutMs"] as? Number)?.toLong() ?: 15_000, - extra = (map["extra"] as? Map<*, *>) - ?.entries - ?.associate { it.key.toString() to it.value } - ?: emptyMap(), - ) - } - } -} - -/** 扫描发现的设备。 */ -data class DiscoveredDevice( - val id: String, - val name: String, - val rssi: Int? = null, - val vendor: String? = null, - val metadata: Map = emptyMap(), -) { - fun toMap(): Map = mapOf( - "id" to id, - "name" to name, - "rssi" to rssi, - "vendor" to vendor, - "metadata" to metadata, - ) -} - -/** 已连接设备的信息快照。 */ -data class DeviceInfo( - val id: String, - val name: String, - val vendor: String, - val firmwareVersion: String? = null, - val hardwareVersion: String? = null, - val serialNumber: String? = null, - val manufacturer: String? = null, - val model: String? = null, - val batteryPercent: Int? = null, - val metadata: Map = emptyMap(), -) { - fun toMap(): Map = mapOf( - "id" to id, - "name" to name, - "vendor" to vendor, - "firmwareVersion" to firmwareVersion, - "hardwareVersion" to hardwareVersion, - "serialNumber" to serialNumber, - "manufacturer" to manufacturer, - "model" to model, - "batteryPercent" to batteryPercent, - "metadata" to metadata, - ) - - fun copyWith( - name: String? = null, - firmwareVersion: String? = null, - hardwareVersion: String? = null, - serialNumber: String? = null, - manufacturer: String? = null, - model: String? = null, - batteryPercent: Int? = null, - metadata: Map? = null, - ): DeviceInfo = DeviceInfo( - id = id, - vendor = vendor, - name = name ?: this.name, - firmwareVersion = firmwareVersion ?: this.firmwareVersion, - hardwareVersion = hardwareVersion ?: this.hardwareVersion, - serialNumber = serialNumber ?: this.serialNumber, - manufacturer = manufacturer ?: this.manufacturer, - model = model ?: this.model, - batteryPercent = batteryPercent ?: this.batteryPercent, - metadata = metadata ?: this.metadata, - ) -} - -/** 唤醒原因(设备 → app)。 */ -enum class WakeReason { PTT, VOICE_WAKE, TRANSLATE_KEY, HANGUP } - -data class DeviceWakeEvent( - val deviceId: String, - val reason: WakeReason, - val payload: Map = emptyMap(), -) - -/** 通用语义事件。`key` 命名空间:`common.` / `.`。 */ -data class DeviceFeatureEvent( - val key: String, - val data: Map = emptyMap(), -) - -/** 设备异常(plugin 抛出,路由器据此 emit error / 中断)。 */ -class DeviceException( - val code: String, - message: String? = null, - cause: Throwable? = null, -) : RuntimeException(message ?: code, cause) - -/** 错误码命名空间。 */ -object DeviceErrorCode { - const val PERMISSION_DENIED = "device.permission_denied" - const val BLUETOOTH_OFF = "device.bluetooth_off" - const val CONNECT_TIMEOUT = "device.connect_timeout" - const val CONNECT_FAILED = "device.connect_failed" - const val HANDSHAKE_FAILED = "device.handshake_failed" - const val DISCONNECTED_REMOTE = "device.disconnected_remote" - const val AUDIO_BUSY = "device.audio_busy" - const val NOT_SUPPORTED = "device.not_supported" - const val FORMAT_UNSUPPORTED = "device.format_unsupported" - const val VENDOR_SWITCHING = "device.vendor_switching" - const val NO_ACTIVE_SESSION = "device.no_active_session" - const val PLUGIN_NOT_INITIALIZED = "device.plugin_not_initialized" - const val INVALID_ARGUMENT = "device.invalid_argument" - - // OTA - const val OTA_BUSY = "device.ota_busy" - const val OTA_INQUIRE_REFUSED = "device.ota_inquire_refused" - const val OTA_VERIFY_FAILED = "device.ota_verify_failed" - const val OTA_FILE_INVALID = "device.ota_file_invalid" - const val OTA_TRANSFER_FAILED = "device.ota_transfer_failed" -} diff --git a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/Ota.kt b/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/Ota.kt deleted file mode 100644 index dd9eb910..00000000 --- a/apps/client/local_plugins/device_plugin_interface/android/src/main/kotlin/com/aiagent/device_plugin_interface/Ota.kt +++ /dev/null @@ -1,170 +0,0 @@ -package com.aiagent.device_plugin_interface - -import kotlinx.coroutines.flow.Flow - -/** - * OTA 升级请求 —— 多态请求层级(与 Dart [DeviceOtaRequest] 对齐)。 - * - * 业务层只构造其中一种子类;插件实现按 `when` 分派。 - * 厂商不支持的子类一律抛 [DeviceException]([DeviceErrorCode.NOT_SUPPORTED]), - * **禁止**静默退化(业务侧才有"是否回退到本地下载"的语义)。 - */ -sealed class DeviceOtaRequest { - /** 单块大小。null = 走厂商默认。 */ - abstract val blockSize: Int? - - /** 整段 OTA 的超时;null = 不限。 */ - abstract val timeoutMs: Long? - - /** 本地文件:app 自己下载好后放在沙盒里。 */ - data class File( - val filePath: String, - override val blockSize: Int? = null, - override val timeoutMs: Long? = null, - ) : DeviceOtaRequest() - - /** 内存字节流:固件已经在内存里。 */ - data class Bytes( - val bytes: ByteArray, - override val blockSize: Int? = null, - override val timeoutMs: Long? = null, - ) : DeviceOtaRequest() { - override fun equals(other: Any?): Boolean = - this === other || (other is Bytes && bytes.contentEquals(other.bytes)) - override fun hashCode(): Int = bytes.contentHashCode() - } - - /** 远程 URL:让 native 自己下载;不支持时抛 NOT_SUPPORTED 由调用方退回。 */ - data class Url( - val url: String, - val headers: Map = emptyMap(), - override val blockSize: Int? = null, - override val timeoutMs: Long? = null, - ) : DeviceOtaRequest() - - /** 厂商扩展:差分包 / 双备份 / fileFlag 等私有参数。 */ - data class Vendor( - val vendorKey: String, - val payload: Map, - override val blockSize: Int? = null, - override val timeoutMs: Long? = null, - ) : DeviceOtaRequest() - - companion object { - /** - * 从 method channel map 反序列化(kind 字段做 tag)。 - * 不识别的 kind 抛 [DeviceException]([DeviceErrorCode.INVALID_ARGUMENT])。 - */ - @Suppress("UNCHECKED_CAST") - fun fromMap(map: Map<*, *>): DeviceOtaRequest { - val kind = map["kind"] as? String - ?: throw DeviceException(DeviceErrorCode.INVALID_ARGUMENT, "ota: kind required") - val blockSize = (map["blockSize"] as? Number)?.toInt() - val timeoutMs = (map["timeoutMs"] as? Number)?.toLong() - return when (kind) { - "file" -> File( - filePath = map["filePath"] as? String - ?: throw DeviceException(DeviceErrorCode.INVALID_ARGUMENT, "ota.file: filePath required"), - blockSize = blockSize, - timeoutMs = timeoutMs, - ) - "bytes" -> Bytes( - bytes = (map["bytes"] as? ByteArray) - ?: throw DeviceException(DeviceErrorCode.INVALID_ARGUMENT, "ota.bytes: bytes required"), - blockSize = blockSize, - timeoutMs = timeoutMs, - ) - "url" -> Url( - url = map["url"] as? String - ?: throw DeviceException(DeviceErrorCode.INVALID_ARGUMENT, "ota.url: url required"), - headers = (map["headers"] as? Map) ?: emptyMap(), - blockSize = blockSize, - timeoutMs = timeoutMs, - ) - "vendor" -> Vendor( - vendorKey = map["vendorKey"] as? String - ?: throw DeviceException(DeviceErrorCode.INVALID_ARGUMENT, "ota.vendor: vendorKey required"), - payload = (map["payload"] as? Map) ?: emptyMap(), - blockSize = blockSize, - timeoutMs = timeoutMs, - ) - else -> throw DeviceException( - DeviceErrorCode.INVALID_ARGUMENT, - "ota: unknown kind \"$kind\"", - ) - } - } - } -} - -/** OTA 全局状态机(与 Dart [DeviceOtaState] 一一对应)。 */ -enum class DeviceOtaState { - IDLE, - /** 容器层下载远程固件中(Url 请求专属,厂商插件看不到)。 */ - DOWNLOADING, - INQUIRING, - NOTIFYING_SIZE, - ENTERING, - TRANSFERRING, - VERIFYING, - REBOOTING, - DONE, - FAILED, - CANCELLED, -} - -/** OTA 进度事件。 */ -data class DeviceOtaProgress( - val state: DeviceOtaState, - val sentBytes: Long, - val totalBytes: Long, - /** 0..100;未知或非 transferring 阶段可为 -1。 */ - val percent: Int, - val tsMs: Long, - /** 终态时携带错误码(state ∈ {FAILED});其它阶段为 null。 */ - val errorCode: String? = null, - val errorMessage: String? = null, -) { - fun toMap(): Map = mapOf( - "state" to state.name, - "sentBytes" to sentBytes, - "totalBytes" to totalBytes, - "percent" to percent, - "tsMs" to tsMs, - "errorCode" to errorCode, - "errorMessage" to errorMessage, - ) - - val isTerminal: Boolean - get() = state == DeviceOtaState.DONE || - state == DeviceOtaState.FAILED || - state == DeviceOtaState.CANCELLED -} - -/** - * OTA 端口(同 [DeviceCallTranslationPort] 的设计风格)。 - * - * 单设备 OTA 互斥:同时只能跑一个 [start],重复 start 抛 - * [DeviceException]([DeviceErrorCode.OTA_BUSY])。 - * - * 生命周期与铁律: - * 1. `start` 之后 [progressStream] 必有终态(DONE/FAILED/CANCELLED),不得悬挂; - * 2. 设备掉线时端口须主动派 FAILED 收尾; - * 3. `cancel` 后短时间内(≤ 5s)须收到 CANCELLED;超时强制收尾; - * 4. **不**要求支持断点续传,但若实现了须在 SDK 内部完成,对外只露统一进度。 - */ -interface DeviceOtaPort { - fun start(request: DeviceOtaRequest) - fun cancel() - val isRunning: Boolean - val progressStream: Flow -} - -/** OTA 错误码补充(与 Dart 镜像)。 */ -object OtaErrorCode { - const val BUSY = DeviceErrorCode.OTA_BUSY - const val INQUIRE_REFUSED = DeviceErrorCode.OTA_INQUIRE_REFUSED - const val VERIFY_FAILED = DeviceErrorCode.OTA_VERIFY_FAILED - const val FILE_INVALID = DeviceErrorCode.OTA_FILE_INVALID - const val TRANSFER_FAILED = DeviceErrorCode.OTA_TRANSFER_FAILED -} diff --git a/apps/client/local_plugins/device_plugin_interface/ios/Classes/DevicePluginInterfacePlugin.swift b/apps/client/local_plugins/device_plugin_interface/ios/Classes/DevicePluginInterfacePlugin.swift deleted file mode 100644 index 485c56d4..00000000 --- a/apps/client/local_plugins/device_plugin_interface/ios/Classes/DevicePluginInterfacePlugin.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Flutter -import UIKit - -/// No-op plugin class — `device_plugin_interface` only provides Dart-side contracts -/// and shared data classes. Vendor plugins (`device_jieli`, ...) implement them -/// in their own native code and depend on this package solely at the Flutter level. -/// -/// Mirrors the Android stub at -/// `android/src/main/kotlin/com/aiagent/device_plugin_interface/DevicePluginInterfacePlugin.kt`. -public class DevicePluginInterfacePlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - // Intentionally empty: no MethodChannel / EventChannel surface. - } -} diff --git a/apps/client/local_plugins/device_plugin_interface/ios/device_plugin_interface.podspec b/apps/client/local_plugins/device_plugin_interface/ios/device_plugin_interface.podspec deleted file mode 100644 index 562b742c..00000000 --- a/apps/client/local_plugins/device_plugin_interface/ios/device_plugin_interface.podspec +++ /dev/null @@ -1,19 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'device_plugin_interface' - s.version = '0.1.0' - s.summary = 'Abstract contracts for hardware device plugins (BLE / RCSP / vendor SDK).' - s.description = <<-DESC -This pod is a no-op companion for the device_plugin_interface Flutter plugin. -The Dart layer holds the actual abstract contracts; vendor plugins (e.g. device_jieli) -implement them in their own native code and depend on this package only at the Flutter level. - DESC - s.homepage = 'https://example.com' - s.license = { :type => 'MIT' } - s.author = { 'AI Agent' => 'liwei1dao@gmail.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*.{h,m,swift}' - s.dependency 'Flutter' - s.platform = :ios, '12.0' - s.swift_version = '5.0' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } -end diff --git a/apps/client/local_plugins/device_plugin_interface/lib/device_plugin_interface.dart b/apps/client/local_plugins/device_plugin_interface/lib/device_plugin_interface.dart index adf0f298..6813ad35 100644 --- a/apps/client/local_plugins/device_plugin_interface/lib/device_plugin_interface.dart +++ b/apps/client/local_plugins/device_plugin_interface/lib/device_plugin_interface.dart @@ -2,8 +2,8 @@ export 'src/audio_format.dart'; export 'src/device_capability.dart'; export 'src/device_event.dart'; export 'src/device_exception.dart'; +export 'src/device_files.dart'; export 'src/device_info.dart'; -export 'src/device_manager.dart'; export 'src/device_ota.dart'; export 'src/device_plugin.dart'; export 'src/device_session.dart'; diff --git a/apps/client/local_plugins/device_plugin_interface/lib/src/audio_format.dart b/apps/client/local_plugins/device_plugin_interface/lib/src/audio_format.dart index 6707a8cb..8b50476f 100644 --- a/apps/client/local_plugins/device_plugin_interface/lib/src/audio_format.dart +++ b/apps/client/local_plugins/device_plugin_interface/lib/src/audio_format.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/foundation.dart'; /// 音频编码。 @@ -9,15 +11,12 @@ enum AudioCodec { pcm16le, } -/// 设备插件与 agent 容器之间统一的音频格式约束。 -/// -/// 接口层规定: -/// - 所有 [DeviceAudioSource] 派发的 [AudioFrame] 必须满足 [AudioFormat.standard]; -/// - 所有 [DeviceAudioSink] 接受的 [AudioFrame] 必须满足 [AudioFormat.standard]。 +/// 设备插件与业务层之间统一的音频格式约束。 /// -/// 厂商插件内部如果拿到的格式不一致(如 8 kHz Opus、PCM、非 20ms 帧长), -/// **必须**在 vendor SDK 出口做重采样 / 转码 / 重新切帧后再送入 Stream。 -/// 转换不可行时,在 [DevicePlugin.initialize] 阶段抛出 +/// 铁律:**业务层拿到的永远是 [AudioFormat.pcm16kMono]**。 +/// 厂商插件内部无论拿到的是 G.722 / mSBC / Opus / 别的采样率, +/// 都必须在插件出口(通常是原生解码器)转成这个格式再交出来。 +/// 转换不可行时,在 `DevicePlugin.initialize` 阶段抛出 /// `DeviceException('device.format_unsupported')`,让上层禁用该厂商。 @immutable class AudioFormat { @@ -28,22 +27,22 @@ class AudioFormat { required this.frameMs, }); - /// 接口层规定的统一格式:Opus / 16 kHz / mono / 20 ms 一帧。 + /// 业务层统一格式:PCM 16-bit LE / 16 kHz / mono / 20 ms 一帧 = 640 字节。 /// - /// 适用于"app 直接转发设备端 OPUS 帧"的零转码路径(旧版设计)。 - static const AudioFormat standard = AudioFormat( - codec: AudioCodec.opus, + /// 恒玄(G.722/mSBC 原生解码)、EaiRec 支架(Opus 原生解码)出口都是它。 + static const AudioFormat pcm16kMono = AudioFormat( + codec: AudioCodec.pcm16le, sampleRate: 16000, channels: 1, frameMs: 20, ); - /// PCM 16-bit LE / 16 kHz / mono / 20 ms 一帧 = 640 字节。 - /// - /// 当前 jieli 通话翻译路径已经在 native 端把 OPUS 解码成 PCM 再上推, - /// translate_server / agent 直接吃这个格式即可(无需自己解码)。 - static const AudioFormat pcm16kMono20ms = AudioFormat( - codec: AudioCodec.pcm16le, + /// 旧名保留:等同 [pcm16kMono]。 + static const AudioFormat pcm16kMono20ms = pcm16kMono; + + /// 「app 直接转发设备端 OPUS 帧」的零转码路径(旧版设计,目前无实现)。 + static const AudioFormat standard = AudioFormat( + codec: AudioCodec.opus, sampleRate: 16000, channels: 1, frameMs: 20, @@ -56,6 +55,10 @@ class AudioFormat { /// 单帧时长(毫秒)。 final int frameMs; + /// PCM 时每毫秒的字节数(16k/16bit/mono = 32)。Opus 无意义,返回 0。 + int get bytesPerMs => + codec == AudioCodec.pcm16le ? sampleRate * channels * 2 ~/ 1000 : 0; + bool isCompatibleWith(AudioFormat other) => codec == other.codec && sampleRate == other.sampleRate && @@ -80,8 +83,7 @@ class AudioFrame { /// 帧负载。Opus 时为压缩字节;PCM 时为 16-bit 小端样本。 final Uint8List bytes; - /// 实际帧格式。理论上等于 [AudioFormat.standard], - /// 实现方仍需逐帧附带,便于 agent 容器层防御性校验。 + /// 实际帧格式。 final AudioFormat format; /// 严格单调递增的帧序号;丢帧后**不得**回填。 @@ -90,3 +92,47 @@ class AudioFrame { /// 单调递增的捕获时间戳(微秒)。 final int timestampUs; } + +/// 音频通路。业务层按「要什么音频」选,插件负责映射到具体链路。 +/// +/// 上行(设备 → app,[DeviceSession.openMic]): +/// - [mic]:设备主麦(现场录音)。 +/// - [callLocal]:通话中本端麦克风。 +/// - [callPeer]:通话中对端声音。 +/// - [ai]:设备 AI 会话(按键唤醒)时的麦克风。 +/// +/// 下行(app → 设备,[DeviceSession.openSpeaker]): +/// - [ai]:AI 会话的回复语音。 +/// - [callLegA]:己方译文,给对端听。 +/// - [callLegB]:对端译文,给己方听。 +enum AudioRoute { mic, callLocal, callPeer, ai, callLegA, callLegB } + +/// 设备 → app 的音频源。`pcm` 里的每一块都满足 [format]。 +/// +/// 由 [DeviceSession.openMic] 创建;用完必须 [close],否则插件不知道 +/// 什么时候可以让设备停止上行。 +abstract class DeviceAudioSource { + AudioRoute get route; + AudioFormat get format; + + /// PCM 数据块流。块大小由插件决定(恒玄 640B/20ms,支架按 Opus 帧)。 + Stream get pcm; + + Future close(); +} + +/// app → 设备的音频汇。写入的 PCM 必须满足 [format]。 +/// +/// 编码、节流、组包(比如恒玄 G.722 + 20ms 定时)一律在插件/原生里做, +/// 业务层只管往里丢 PCM,**不要**自己掐时钟。 +abstract class DeviceAudioSink { + AudioRoute get route; + AudioFormat get format; + + Future write(Uint8List pcm); + + /// 丢掉还没发出去的排队音频(用户插话打断时用)。 + Future discardPending(); + + Future close(); +} diff --git a/apps/client/local_plugins/device_plugin_interface/lib/src/device_capability.dart b/apps/client/local_plugins/device_plugin_interface/lib/src/device_capability.dart index 192b6c35..55abb3c8 100644 --- a/apps/client/local_plugins/device_plugin_interface/lib/src/device_capability.dart +++ b/apps/client/local_plugins/device_plugin_interface/lib/src/device_capability.dart @@ -2,6 +2,8 @@ /// /// 业务层据此显示/隐藏 UI(OTA 按钮、翻译模式选择等), /// **禁止**写厂商分支判断。 +/// +/// 只增不删:已发布的插件声明过的值不会被移除。 enum DeviceCapability { /// 扫描发现设备(必备) scan, @@ -33,10 +35,10 @@ enum DeviceCapability { /// 佩戴检测事件 wearDetection, - /// 设备 → app 麦克风上行(音频通道在 native 内部维护,不直接暴露给 Flutter) + /// 设备 → app 麦克风上行([DeviceSession.openMic],`AudioRoute.mic`) micUplink, - /// app → 设备扬声器下行(音频通道在 native 内部维护) + /// app → 设备扬声器下行 speakerDownlink, /// 设备本地唤醒(PTT 键 / 语音唤醒),派发 [DeviceWakeEvent] @@ -53,4 +55,36 @@ enum DeviceCapability { /// 自定义 RCSP / 私有协议命令([DeviceSession.invokeFeature] 可用) customCommand, + + // ---------- 2026-09 新增 ---------- + + /// 能拿到设备真实蓝牙 MAC([DeviceInfo.macAddress]),用于服务端确权 + macAddress, + + /// 设备端主麦录音:`record.start` / `record.stop`,且设备按键起停会派 + /// `record.started` / `record.stopped` feature 事件 + micRecording, + + /// 通话中能抓到本端与对端两路音频(`AudioRoute.callLocal` / `callPeer`) + callAudioTap, + + /// 设备会上报通话起止(`call.started` / `call.ended` feature 事件) + callState, + + /// 按键唤醒 AI 会话:派 [DeviceWakeEvent],并支持 `ai.accept` / `ai.exit` + /// 与 `AudioRoute.ai` 的上下行 + aiWake, + + /// 通话翻译下行:`AudioRoute.callLegA` / `callLegB` + translationDownlink, + + /// 设备端面对面翻译开关:`f2f.start` / `f2f.stop` + faceToFace, + + /// 设备自己把录音存在本机存储里(TF 卡 / 内置 flash),事后由 app 同步走。 + /// 通过 [DeviceSession.fileStore] 拿 [DeviceFileStore]。 + /// + /// ⚠️ 与 [micUplink](边录边传)**互不蕴含**:EaiRec 支架只有前者, + /// 恒玄耳机只有后者,以后的录音笔可能两个都有。 + fileStore, } diff --git a/apps/client/local_plugins/device_plugin_interface/lib/src/device_exception.dart b/apps/client/local_plugins/device_plugin_interface/lib/src/device_exception.dart index 9d13a5ea..7d754249 100644 --- a/apps/client/local_plugins/device_plugin_interface/lib/src/device_exception.dart +++ b/apps/client/local_plugins/device_plugin_interface/lib/src/device_exception.dart @@ -33,6 +33,14 @@ class DeviceErrorCode { static const String otaVerifyFailed = 'device.ota_verify_failed'; static const String otaFileInvalid = 'device.ota_file_invalid'; static const String otaTransferFailed = 'device.ota_transfer_failed'; + + // 设备端文件仓库(DeviceFileStore) + static const String fileNotFound = 'device.file_not_found'; + static const String fileTransferFailed = 'device.file_transfer_failed'; + static const String fileBusy = 'device.file_busy'; + + /// 调用方主动取消。**不是故障**,调用方不该按错误弹提示。 + static const String cancelled = 'device.cancelled'; } /// 设备域统一异常。 diff --git a/apps/client/local_plugins/device_plugin_interface/lib/src/device_files.dart b/apps/client/local_plugins/device_plugin_interface/lib/src/device_files.dart new file mode 100644 index 00000000..a46c54f7 --- /dev/null +++ b/apps/client/local_plugins/device_plugin_interface/lib/src/device_files.dart @@ -0,0 +1,87 @@ +import 'dart:async'; + +import 'device_exception.dart'; + +/// 设备端存储里的一个文件。 +/// +/// 「设备自己录、事后同步到手机」这类硬件的通用抽象:支架/录音笔的 TF 卡、 +/// 眼镜的内置 flash 都是这一类。与 [DeviceAudioSource] 那条「边录边传」的 +/// 实时链路是**两回事**,很多硬件只有其中一条。 +class DeviceFileEntry { + const DeviceFileEntry({ + required this.name, + required this.size, + this.modifiedAt, + this.metadata = const {}, + }); + + /// 设备上的文件名。**这是这个文件在设备上的唯一标识**,下载/删除都用它。 + final String name; + + /// 字节数。设备正在往这个文件里录时它会变,别拿它做「下完了没」的判据。 + final int size; + + /// 设备侧记录的修改时间。解不出合法时间的给 null—— + /// 宁可没有时间,也不要把 1980 年这种垃圾值当真。 + final DateTime? modifiedAt; + + /// 厂商私有的附加信息(原始时间戳、目录、格式…),业务层不解释它。 + final Map metadata; + + @override + String toString() => 'DeviceFileEntry($name, $size B, $modifiedAt)'; +} + +/// 文件传输的取消令牌。 +/// +/// 设备端文件走 BLE 拉,速度按 KB/s 计,一个十几分钟的录音要拉好几分钟—— +/// **必须可取消**,否则用户退出页面/断开设备时会留一条拉不完也停不下的传输。 +class DeviceFileCancelToken { + bool _cancelled = false; + final _completer = Completer(); + + bool get isCancelled => _cancelled; + + /// 已取消时完成的 Future,实现方可以用它去 race 自己的等待。 + Future get whenCancelled => _completer.future; + + void cancel() { + if (_cancelled) return; + _cancelled = true; + if (!_completer.isCompleted) _completer.complete(); + } +} + +/// 设备端文件仓库端口。 +/// +/// 声明 [DeviceCapability.fileStore] 的会话通过 [DeviceSession.fileStore] +/// 暴露它。业务层只认这个接口,不认哪家的芯片、哪条私有通道。 +abstract class DeviceFileStore { + /// 列出设备上的文件。设备没有文件时返回空列表(**不是**抛异常)。 + Future> list(); + + /// 把 [name] 拉到本地 [destPath]。 + /// + /// 实现方负责建父目录。返回实际写入的路径(通常就是 [destPath])。 + /// [onProgress] 的 `total` 在设备没给总长度时为 0。 + /// 被 [cancelToken] 取消时抛 [DeviceException],错误码 + /// [DeviceErrorCode.cancelled],**已写的半成品要保留**(供断点续传)。 + Future download( + String name, { + required String destPath, + void Function(int received, int total)? onProgress, + DeviceFileCancelToken? cancelToken, + }); + + /// 删除设备上的文件。**调用前必须已经过用户二次确认**——这是不可逆的, + /// 而且删的是用户录在硬件里、可能还没同步走的东西。 + Future delete(String name); + + /// 设备主动推来的文件列表(多数硬件会在「录音停止」后推一次)。 + /// 没有这个行为的实现给空流即可,业务层照样能靠 [list] 轮询。 + Stream> get listPushes => const Stream.empty(); + + /// 设备此刻是否正在录音。正在录的那个文件**不能拉**(还在写,拉下来是残的)。 + /// 判断不出来的实现返回 false。 + bool get isDeviceRecording => false; +} diff --git a/apps/client/local_plugins/device_plugin_interface/lib/src/device_info.dart b/apps/client/local_plugins/device_plugin_interface/lib/src/device_info.dart index 04daa7b6..4ac392a6 100644 --- a/apps/client/local_plugins/device_plugin_interface/lib/src/device_info.dart +++ b/apps/client/local_plugins/device_plugin_interface/lib/src/device_info.dart @@ -12,7 +12,7 @@ class DiscoveredDevice { }); /// 厂商插件不透明 ID。 - /// - 杰里:BLE MAC(与 [metadata]['edrAddr'] 一同标识真实设备) + /// - 经典蓝牙:Android 是 MAC,iOS 是 CoreBluetooth peripheral UUID /// - BLE 通用:MAC(Android)/ CBPeripheral.identifier(iOS) /// /// **业务层只把它当字符串用**,不要解析或假设格式。 @@ -27,14 +27,63 @@ class DiscoveredDevice { /// 来源厂商插件 [DevicePlugin.vendorKey]。 final String? vendor; - /// 厂商相关的扩展字段(edrAddr / deviceType / advertisementData / serviceUuids 等)。 - /// key 由具体厂商插件文档约定。 + /// 厂商相关的扩展字段。key 由具体厂商插件文档约定。 final Map metadata; @override String toString() => 'DiscoveredDevice($name, $id, rssi=$rssi)'; } +/// 电量快照。每一项 `-1` 或 null 表示未知/未上报。 +/// +/// TWS 耳机三个值都可能有;支架、香薰这类单体设备只填 [single]。 +@immutable +class DeviceBattery { + const DeviceBattery({ + this.left, + this.right, + this.caseBox, + this.single, + this.chargingLeft = false, + this.chargingRight = false, + this.chargingCase = false, + this.chargingSingle = false, + }); + + static const DeviceBattery unknown = DeviceBattery(); + + final int? left; + final int? right; + final int? caseBox; + + /// 单体设备的电量;TWS 耳机这里给「左右较低的一侧」。 + final int? single; + + final bool chargingLeft; + final bool chargingRight; + final bool chargingCase; + final bool chargingSingle; + + bool get hasAny => + (left ?? -1) >= 0 || + (right ?? -1) >= 0 || + (caseBox ?? -1) >= 0 || + (single ?? -1) >= 0; + + /// 给「只显示一个数」的 UI 用:优先 single,其次左右较低值,再次盒。 + int? get summary { + if ((single ?? -1) >= 0) return single; + final lr = [left, right].where((v) => (v ?? -1) >= 0).cast(); + if (lr.isNotEmpty) return lr.reduce((a, b) => a < b ? a : b); + if ((caseBox ?? -1) >= 0) return caseBox; + return null; + } + + @override + String toString() => + 'Battery(L=$left R=$right C=$caseBox S=$single)'; +} + /// 已连接设备的信息快照。 @immutable class DeviceInfo { @@ -48,6 +97,8 @@ class DeviceInfo { this.manufacturer, this.model, this.batteryPercent, + this.battery = DeviceBattery.unknown, + this.macAddress, this.metadata = const {}, }); @@ -61,9 +112,18 @@ class DeviceInfo { final String? manufacturer; final String? model; - /// 0..100;未知为 null。 + /// 0..100;未知为 null。等价于 [battery].summary,保留兼容旧调用。 final int? batteryPercent; + final DeviceBattery battery; + + /// 设备**真实**蓝牙 MAC(大写、冒号分隔)。 + /// + /// 与 [id] 的区别:iOS 上 [id] 是 peripheral UUID,每台手机都不一样, + /// 不能拿去服务端确权;这个值要么来自系统(Android),要么来自设备自报。 + /// 拿不到为 null。 + final String? macAddress; + final Map metadata; DeviceInfo copyWith({ @@ -74,6 +134,8 @@ class DeviceInfo { String? manufacturer, String? model, int? batteryPercent, + DeviceBattery? battery, + String? macAddress, Map? metadata, }) { return DeviceInfo( @@ -86,19 +148,21 @@ class DeviceInfo { manufacturer: manufacturer ?? this.manufacturer, model: model ?? this.model, batteryPercent: batteryPercent ?? this.batteryPercent, + battery: battery ?? this.battery, + macAddress: macAddress ?? this.macAddress, metadata: metadata ?? this.metadata, ); } } -/// 连接状态机(细化以容纳"链路通了但 RCSP 协议尚未握手"的中间态)。 +/// 连接状态机(细化以容纳"链路通了但私有协议尚未握手"的中间态)。 enum DeviceConnectionState { disconnected, /// 已发起连接,链路(ACL/GATT/SPP)尚未建立 connecting, - /// 蓝牙链路已建立,等待厂商私有协议握手(如杰里 RCSP init、GATT 服务发现等) + /// 蓝牙链路已建立,等待厂商私有协议握手 linkConnected, /// 协议握手完成,业务可调用 read/write/feature @@ -109,12 +173,6 @@ enum DeviceConnectionState { } /// 扫描过滤条件。所有字段均可选;`null` 表示不过滤。 -/// -/// - [namePrefix]:设备名前缀(单串,跨厂商);与 [nameList] 同时存在时各厂商 -/// 实现可自行选择优先级,杰里实现优先 [nameList]。 -/// - [nameList]:设备名命中列表(精确匹配);空 = 不按名过滤。 -/// - [serviceUuids]:UUID 命中列表;杰理实现按 `BleScanMessage.flagContent` -/// 做忽略大小写的 contains 匹配。 @immutable class DeviceScanFilter { const DeviceScanFilter({ @@ -132,8 +190,7 @@ class DeviceScanFilter { final String? vendor; final int? minRssi; - /// 是否跳过没有 `name` 的广播(环境 BLE 噪声过滤);`null` = 由实现选默认。 - /// 杰理实现默认 `true`。 + /// 是否跳过没有 `name` 的广播;`null` = 由实现选默认。 final bool? skipUnnamed; } @@ -147,6 +204,6 @@ class DeviceConnectOptions { final Duration timeout; - /// 厂商私有连接参数(如杰里的 connectWay/deviceType)。 + /// 厂商私有连接参数。 final Map extra; } diff --git a/apps/client/local_plugins/device_plugin_interface/lib/src/device_manager.dart b/apps/client/local_plugins/device_plugin_interface/lib/src/device_manager.dart deleted file mode 100644 index c7f14e0e..00000000 --- a/apps/client/local_plugins/device_plugin_interface/lib/src/device_manager.dart +++ /dev/null @@ -1,107 +0,0 @@ -import 'dart:async'; - -import 'device_capability.dart'; -import 'device_event.dart'; -import 'device_info.dart'; -import 'device_plugin.dart'; -import 'device_session.dart'; - -/// 容器层入口(业务层只见此一个)。 -/// -/// 单设备模型: -/// - `activeSession` 至多一个;切换厂商或连接新设备会先断开旧 session; -/// - 唤醒/翻译键事件统一从 [agentTriggers] 派发; -/// - 音频通道(耳机麦/扬声器)一律由 native 内部管理,Flutter 不直接持有。 -/// -/// 所有方法在 `dispose` 后必须抛 `StateError`。 -abstract class DeviceManager { - // ---------- 厂商管理 ---------- - - /// 已注册的厂商(在 app 启动时由各 plugin 主动 register)。 - Map get registeredVendors; - - /// 注册厂商工厂。`replace=false` 时同 key 重复注册抛 [DeviceException]。 - void registerVendor( - DevicePluginDescriptor descriptor, { - bool replace = false, - }); - - /// 当前激活的厂商 key;未选择为 null。 - String? get activeVendor; - - /// 当前激活厂商的能力集合(便于 UI 一行判断);无 active 时空集合。 - Set get activeCapabilities; - - /// 切换厂商。流程(原子操作): - /// - /// 1. `stopScan()` - /// 2. 断开 [activeSession](若有) - /// 3. dispose 旧 plugin - /// 4. 创建并 initialize 新 plugin - /// 5. 派发 `vendorChanged` - /// - /// 切换中所有 scan/connect 调用抛 `DeviceException('device.vendor_switching')`。 - Future useVendor(String vendorKey, DevicePluginConfig config); - - /// 清空当前 vendor —— 断开 active session、dispose 旧 plugin, - /// 派发 `vendorChanged(vendorKey=null)`。无 active vendor 时 no-op。 - Future clearVendor(); - - // ---------- 扫描 / 连接 ---------- - - Future startScan({DeviceScanFilter? filter, Duration? timeout}); - Future stopScan(); - - /// 当前蓝牙开关状态。仅由 native 实现真实查询,pure-Dart 默认返回 true。 - Future isBluetoothEnabled(); - - /// 已配对设备(来自 active plugin)。 - Future> bondedDevices(); - - /// 连接设备。如果当前已有 active session,先断开旧的再连新的, - /// 并派发 `activeSessionChanged`。 - Future connect( - String deviceId, { - DeviceConnectOptions? options, - }); - - /// 断开当前 session(无 session 时 no-op)。 - Future disconnect(); - - /// 当前 active session;未连接为 null。 - DeviceSession? get activeSession; - - // ---------- agent 协调 ---------- - - /// 设备主动触发 agent 的事件(PTT/语音唤醒/翻译键)。 - /// 由 `agents_server` 中的 `DeviceAgentRouter` 监听。 - Stream get agentTriggers; - - /// 容器全局事件流:扫描结果、连接状态、active session 变更等。 - Stream get eventStream; - - // ---------- 生命周期 ---------- - - Future initialize(); - Future dispose(); -} - -/// 厂商描述符(用于注册表 / 设置 UI 列表)。 -class DevicePluginDescriptor { - DevicePluginDescriptor({ - required this.vendorKey, - required this.displayName, - required this.factory, - this.configSchema = DevicePluginConfigSchema.empty, - this.declaredCapabilities = const {}, - }); - - final String vendorKey; - final String displayName; - final DevicePluginFactory factory; - final DevicePluginConfigSchema configSchema; - - /// 能力声明的"广告版"——容器在 plugin 未 initialize 前用它做 UI 引导。 - /// 真实可用能力以 [DevicePlugin.capabilities] 为准。 - final Set declaredCapabilities; -} diff --git a/apps/client/local_plugins/device_plugin_interface/lib/src/device_ota.dart b/apps/client/local_plugins/device_plugin_interface/lib/src/device_ota.dart index feb73a13..9e4e08c2 100644 --- a/apps/client/local_plugins/device_plugin_interface/lib/src/device_ota.dart +++ b/apps/client/local_plugins/device_plugin_interface/lib/src/device_ota.dart @@ -169,4 +169,11 @@ abstract class DeviceOtaPort { /// 进度事件流(broadcast / multi-subscribe)。 Stream get progressStream; + + /// 释放端口占用的链路资源,并把设备**交还给正常会话**。 + /// + /// 有些方案(恒玄 SPP OTA)升级期间要独占蓝牙链路、必须先断开 app 层连接, + /// 升级完/取消后由端口负责把 app 层连接恢复回来。UI 退出升级页时调用。 + /// 没在跑时 no-op。 + Future close() async {} } diff --git a/apps/client/local_plugins/device_plugin_interface/lib/src/device_plugin.dart b/apps/client/local_plugins/device_plugin_interface/lib/src/device_plugin.dart index bfd486e1..a04accdb 100644 --- a/apps/client/local_plugins/device_plugin_interface/lib/src/device_plugin.dart +++ b/apps/client/local_plugins/device_plugin_interface/lib/src/device_plugin.dart @@ -79,6 +79,28 @@ abstract class DevicePlugin { /// 已配对设备快照(含历史/系统配对,但**不一定**当前可连)。 Future> bondedDevices(); + /// 本插件「记住」的设备(App 自己配过、会自动回连的那些),最近的在前。 + /// 同步读本地存储,不打原生。没有则空列表。 + List get rememberedDevices => const []; + + /// 最近一次连过的设备。断连后设备页仍按它显示主图。 + DiscoveredDevice? get lastKnownDevice => + rememberedDevices.isEmpty ? null : rememberedDevices.first; + + /// 冷启动/断连后尝试回连记住的设备。没记住任何设备时 no-op。 + Future tryAutoConnect() async {} + + /// 把一台设备记为「我的设备」(连接成功后调用),之后会参与自动回连。 + Future rememberDevice(DiscoveredDevice device) async {} + + /// 用户**主动**进入连接页时调:申请权限、起蓝牙栈。返回 false 表示 + /// 当前不能扫/连(权限被拒且在冷却期等),UI 应置灰入口。 + /// 与 [initialize] 的区别:后者在冷启动就跑、不允许弹任何权限框。 + Future ensureReady() async => true; + + /// 把一台设备从「记住」列表移除(解绑),正连着就顺带断开。 + Future forgetDevice(String deviceId) async {} + /// 建立会话。 /// /// 实现要求: @@ -92,6 +114,8 @@ abstract class DevicePlugin { }); /// 当前 active session(最多一个);未连接为 null。 + /// + /// 只有 `state == ready` 的会话才算业务可用,容器层据此维护已连接列表。 DeviceSession? get activeSession; /// 全局事件流:扫描/连接/蓝牙开关/错误等。 diff --git a/apps/client/local_plugins/device_plugin_interface/lib/src/device_session.dart b/apps/client/local_plugins/device_plugin_interface/lib/src/device_session.dart index 9a37e128..ea21f486 100644 --- a/apps/client/local_plugins/device_plugin_interface/lib/src/device_session.dart +++ b/apps/client/local_plugins/device_plugin_interface/lib/src/device_session.dart @@ -1,8 +1,11 @@ import 'dart:async'; +import 'audio_format.dart'; import 'device_capability.dart'; import 'device_event.dart'; +import 'device_exception.dart'; import 'device_info.dart'; +import 'device_files.dart'; import 'device_ota.dart'; /// 已连接设备的会话句柄。生命周期: @@ -14,10 +17,10 @@ import 'device_ota.dart'; /// 铁律: /// 1. `disconnected` 之后任何方法必须抛 `StateError`; /// 2. `eventStream` 必须用 `StreamController.broadcast()`,`disconnect` 时关闭; -/// 3. 同一时刻最多一个 active [DeviceAudioSource] + 一个 active [DeviceAudioSink], -/// 重复 open 抛 `DeviceException('device.audio_busy')`; -/// 4. `invokeFeature` / `read*` / `write*` 在状态非 `ready` 时抛 -/// `DeviceException('device.no_active_session')`,禁止静默排队。 +/// 3. `invokeFeature` / `read*` 在状态非 `ready` 时抛 +/// `DeviceException('device.no_active_session')`,禁止静默排队; +/// 4. **协议是冻结的**:同一个 featureKey 在同一厂商上永远发同样的字节, +/// 这条由各插件的字节级金测试守着。 abstract class DeviceSession { String get deviceId; String get vendor; @@ -26,9 +29,16 @@ abstract class DeviceSession { DeviceInfo get info; Set get capabilities; + bool supports(DeviceCapability c) => capabilities.contains(c); + /// 会话事件流(连接态、电量、按键、佩戴...)。 Stream get eventStream; + /// 设备主动唤醒(PTT / 语音 / 翻译键 / 挂断)。 + /// + /// 无 [DeviceCapability.aiWake] 的设备给空流即可。 + Stream get wakeEvents => const Stream.empty(); + // -------- 通用查询 -------- Future readRssi(); @@ -38,14 +48,36 @@ abstract class DeviceSession { /// 强制刷新 [DeviceInfo](电量/固件版本/序列号)。 Future refreshInfo(); + // -------- 音频 -------- + + /// 打开一路上行音频。多次打开同一 route 各自独立、互不影响。 + /// + /// 插件负责:让设备开始上行(若需要)、解码到 [AudioFormat.pcm16kMono]、 + /// 挑出这条 route 的帧。不支持的 route 抛 `device.not_supported`。 + Future openMic({AudioRoute route = AudioRoute.mic}) => + throw DeviceException(DeviceErrorCode.notSupported, 'openMic($route)'); + + /// 打开一路下行音频。编码/节流/组包在插件里做。 + Future openSpeaker({AudioRoute route = AudioRoute.ai}) => + throw DeviceException( + DeviceErrorCode.notSupported, 'openSpeaker($route)'); + // -------- 厂商私有特性 -------- - /// 调用厂商私有 feature。`featureKey` 形如: - /// - `common.battery.subscribe` - /// - `jieli.translation.start` - /// - `bes.eq.set` + /// 调用 feature。跨厂商通用的 key(插件按能力声明实现): + /// + /// | key | 能力 | 含义 | + /// |---|---|---| + /// | `record.start` / `record.stop` | micRecording | 设备主麦录音起停(stop 可带 `fileName`) | + /// | `call.start` / `call.stop` | callAudioTap | 进入/退出通话模式(双路上行) | + /// | `call.query` | callState | 主动查一次通话状态 | + /// | `asr.started` / `asr.stopped` | callAudioTap | 通知设备 ASR 起停 | + /// | `ai.accept` / `ai.exit` | aiWake | 应答唤醒 / 请求退出 AI 模式 | + /// | `f2f.start` / `f2f.stop` | faceToFace | 面对面翻译起停 | + /// | `battery.query` | battery | 主动查一次电量 | + /// | `state.refresh` | — | 把所有已知查询各发一遍 | /// - /// 返回 `Map` 或 throw [DeviceException]。 + /// 厂商私有的用 `.`。返回 `Map` 或 throw [DeviceException]。 Future> invokeFeature( String featureKey, [ Map args = const {}, @@ -54,13 +86,70 @@ abstract class DeviceSession { // -------- OTA 端口 -------- /// 该 session 暴露的 OTA 端口;vendor 无 [DeviceCapability.ota] 时返回 null。 - /// - /// 编排器 / UI 通过本接口拿到 vendor-agnostic 的 OTA 控制;不依赖具体厂商。 - /// 端口生命周期与 session 绑定 —— session disconnect 时端口必须自动收尾 - /// (`failed` 事件 + `isRunning=false`)。 DeviceOtaPort? otaPort() => null; + /// 该 session 暴露的设备端文件仓库;无 [DeviceCapability.fileStore] 时返回 null。 + /// + /// 「设备自己录到 TF 卡 / flash,事后 app 同步」这条链路的入口。 + /// 同一个 session 多次调用应返回同一个实例。 + DeviceFileStore? fileStore() => null; + // -------- 关闭 -------- Future disconnect(); } + +/// 通用 feature 事件 key(设备 → app)。插件把私有帧翻译成这些名字派发。 +class DeviceFeatureKeys { + DeviceFeatureKeys._(); + + static const String recordStarted = 'record.started'; + static const String recordStopped = 'record.stopped'; + static const String callStarted = 'call.started'; + static const String callEnded = 'call.ended'; + static const String batteryUpdated = 'battery.updated'; + static const String firmwareUpdated = 'firmware.updated'; + static const String macUpdated = 'mac.updated'; +} + +/// 通用 feature 调用 key(app → 设备)。 +class DeviceFeatures { + DeviceFeatures._(); + + static const String recordStart = 'record.start'; + static const String recordStop = 'record.stop'; + static const String callStart = 'call.start'; + static const String callStop = 'call.stop'; + static const String callQuery = 'call.query'; + static const String asrStarted = 'asr.started'; + static const String asrStopped = 'asr.stopped'; + static const String aiAccept = 'ai.accept'; + static const String aiExit = 'ai.exit'; + static const String f2fStart = 'f2f.start'; + static const String f2fStop = 'f2f.stop'; + static const String batteryQuery = 'battery.query'; + static const String stateRefresh = 'state.refresh'; + + /// AI 会话状态(app → 设备),驱动设备端的指示灯 / 表情动画。 + /// 参数:`{'state': DeviceAiState}`。设备不支持时抛 `device.not_supported`, + /// **调用方要吞掉**——这只是锦上添花,不该影响对话本身。 + static const String aiState = 'ai.state'; +} + +/// [DeviceFeatures.aiState] 的取值。 +/// +/// 刻意用语义名而不是厂商字节:车载香薰映射到 C2 的 `0x07` +/// (0说话结束/1思考中/2说话开始/4聆听中),别的芯片各映射各的。 +enum DeviceAiState { + /// 在听用户说话 + listening, + + /// 已收到用户的话,正在想 + thinking, + + /// AI 正在说 + speaking, + + /// 一轮说完,回到待命 + idle, +} diff --git a/apps/client/local_plugins/device_plugin_interface/pubspec.yaml b/apps/client/local_plugins/device_plugin_interface/pubspec.yaml index 7712630e..7afff3b5 100644 --- a/apps/client/local_plugins/device_plugin_interface/pubspec.yaml +++ b/apps/client/local_plugins/device_plugin_interface/pubspec.yaml @@ -1,10 +1,10 @@ name: device_plugin_interface -description: Abstract contracts for hardware device plugins (BLE / RCSP / vendor SDK). +description: 硬件设备插件的纯 Dart 契约(厂商插件 / 会话 / 能力 / 音频 / OTA)。不含任何原生代码。 publish_to: none -version: 0.1.0 +version: 0.2.0 environment: - sdk: ^3.8.1 + sdk: ">=3.3.0 <4.0.0" flutter: ">=3.3.0" dependencies: @@ -14,12 +14,3 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - -flutter: - plugin: - platforms: - android: - package: com.aiagent.device_plugin_interface - pluginClass: DevicePluginInterfacePlugin - ios: - pluginClass: DevicePluginInterfacePlugin diff --git a/apps/client/local_plugins/device_smartcar/android/build.gradle b/apps/client/local_plugins/device_smartcar/android/build.gradle new file mode 100644 index 00000000..63bd1502 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/android/build.gradle @@ -0,0 +1,83 @@ +group = "com.yimai.device_smartcar" +version = "1.0-SNAPSHOT" + +buildscript { + ext.kotlin_version = "2.1.0" + repositories { + google() + mavenCentral() + } + + dependencies { + classpath("com.android.tools.build:gradle:8.7.3") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" + +// 杰理 SDK 以「解包后的 jar + jniLibs」形态随插件分发(原始 aar 留在 third_party/aar/): +// Android Gradle Plugin 不允许 library 模块直接依赖本地 .aar +// ("Direct local .aar file dependencies are not supported when building an Android library"), +// 走 flatDir 又要求每个宿主 App 自己配仓库。解包成 jar 就完全自包含。 +// 升级 SDK:换 third_party/aar/ 下的文件,重跑 tool/unpack_aars.sh,提交产物。 +// +// 只带一个:jl_rcsp —— RcspAuth(设备认证,libjl_auth.so / libjl_crc.so),**BLE 能不能连上全靠它**。 +// 它在 maven 上没有坐标,只能 vendor;包名 com.jieli.jl_rcsp.* / jl_filebrowse.*, +// 与工程里已有的 com.jieli.jl_bt_ota.* / com.jieli.audio.* 不重叠(已用 javap 核过)。 +// +// ⚠️ **jl_bt_ota 必须走 maven,不能 vendor**:`ble_service` 与 `recorder_holder` 已经 +// 依赖 com.jieli.jl_bt_ota:jl_bt_ota(解析到 1.11.0),再 vendor 一份 1.10.0 会直接 +// Duplicate class 编不过(2026-09-10 踩过)。这里显式声明同一个坐标即可, +// 它自带 libjl_ota_auth.so,所以 jniLibs 里也不要放那个 so。 +// +// ⚠️ 刻意**没有**带 jl_audio_decode / JL_Watch / jl_bluetooth_connect: +// - 音频解码(opus)阶段 6 才用,且 ble_service 已经带了 com.jieli.audio:jl_audio_decode; +// - JL_Watch 的 WatchOpImpl 是手表专用,我们直接继承 jl_rcsp 的 RcspOpImpl; +// - jl_bluetooth_connect 只被 lumi 的状态码转换用到,RcspAuth 本身不依赖它。 +android { + namespace = "com.yimai.device_smartcar" + compileSdk = 36 + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17 + } + + sourceSets { + main.java.srcDirs += "src/main/kotlin" + main.jniLibs.srcDirs = ["src/main/jniLibs"] + } + + defaultConfig { + minSdk = 21 + } + + // 杰理的 so 没有 16KB 对齐等新要求,按原样打包 + packagingOptions { + jniLibs { + useLegacyPackaging = false + } + } + + dependencies { + implementation "androidx.core:core-ktx:1.13.1" + implementation fileTree(dir: "libs", include: ["*.jar"]) + // 与 ble_service / recorder_holder 同一个坐标,版本由 Gradle 统一解析 + implementation "com.jieli.jl_bt_ota:jl_bt_ota:1.11.0" + // 麦克风上行的 opus 解码(同上,坐标与 ble_service/recorder_holder 一致) + implementation "com.jieli.audio:jl_audio_decode:2.1.0" + } +} diff --git a/apps/client/local_plugins/device_smartcar/android/libs/jl_rcsp_V0.8.0_705-release.jar b/apps/client/local_plugins/device_smartcar/android/libs/jl_rcsp_V0.8.0_705-release.jar new file mode 100644 index 0000000000000000000000000000000000000000..bf4110a44b6a0acfee27e0abb2c9c8e2334559c3 GIT binary patch literal 720497 zcmb50QFnR7ur79J9 zDNrz=e+>$V7>XD~^{+Ny5Euxk0R#w$;oq#0oejOEg^9HVy`{CDsfD$Pp`)FflL@`( zzoFp&84B6iIyoEII@1|h8#p=1B+SZg2q1--L9+xTvo*;}{wTbuBg3hXft1qSLC}!7 z8grLrtKv2ShsEHpLF37DKGu7lf<6{h%xDU)Z}{$9ewvPcf84wf0=+`yL4SIB!)YQe z%MZ0ObvMXXxf@?;IIv}qOHL)y*vK|eNARUdMhY69_kQBhQo5|E> zp)%T#n~XSYa-lG8PisYe&udenxiQf*po>`j-0J^a6g)LT1ovsCPd});qL4v*_rE=J zBv93lM#jy-KV0_2x6tLKj=H8|Fel7Z)Jf+vVz>>c{_1Y|+EX7f&qFQ?4RXy2AqL)8 zwbvu6n+WuOu@Lb3jlO`V@>rTIuic5Wn{?tr-aH)IvkDwWx@ zh5*URi~HeoI)C_M7Ndg}<|M*wT-(JR!#${{>hu2kMUJQyl+&O(JgoJ3xuD*xA|@9eVEFG z(-FV?e+i;m6BfS!6bNV<0tkrl|4R@u2DS!fCXS?x|4~G>@|F{h3fj+>fO>v0aI}q$ zVvIU`a6E0Z=KZ{-prBxgJg5vQ7gO31NETh^)b)bwX#K%!+7gA{`$C2!GuJ^S^S6YL zJ&#+Gtj&QK(*da4>|0Ll4(Fzq@6W-B90Uy8+pujuO|^*P6tcF`W! zYY}fReJrp|)D|HP=&@Ad~k!%*E?^RUvT}H64+Q2&wo%$bqt|sE=sPqjnn0Ff6+Cg_Hz^xNAJT!=qa8v zc43DGI>8y~#OY{oAb2om%cXt`enIIs*p$45ZYCF+j0H9lMfc z3p^9r)d`I-u6T63S6Nw}o=GHq*2OZj&w%N*)xkd%m5RLzVlX9D8TOgOTx2f^5}&7W z@0DwfCr;wYeQ_@@GFE1c;mn{PWJsa;?ku9huVsjyQkbrU<1WSd;D2WWXa9SynY&S~ zg3?W?ouu@7+H8w(bK>Xhq?0%`KkZm8WCRxFSjL=>%dApk%i^jQ*}T6jS|q<_TUEWJ ziqmZ9(d}4@F$5nfRa@7@T3U;sy(Mp#fQE^kf03k#&$EQ&u(usRF~!wpWg2j@Yz)e4&J;Z+Vhifer+c3U zN5>NgW%qCwlkJi~L(MKP@*C`9&+rq+7^KYr`S?732p${sxhW{p?b33YoFd+O6Mw|r*6gD%37w2h!i-{XHQSPsNNV-G5>UbQ*FC@}xt3 zCJQXSN(j4jLA!m2F@Q4zC2j~j%_~?uA$$IU{%_vH&WSp@{~7-f@c$|AO#k7%Sy@L8 z6@bPo1pCK?T0~f2C=R@NM+(>o+z1XF^%vm?P9izEaYs%n?Z%d=YZRiWq4(oXyniGj z-}^5A0^~ssIAJmi0F}`7ddusE^W{1tY>>A2x<)Vqlr(niL&iKidWM%&<8{K}BJ?f=R zqPgJ}R_|t&4g5LyF+2ri*xP`dUu#b9C5Ulo!d5JEzup8k6z+*VGqsMk$ii-gQZ?mT zN)C&v8?EhPa}S=l)Qkj*nKaWo4wuahXT-FbQkp-IFI12nXYwwj%1Oz6#8gZCI<3uy z8v56%nRrg87Z@W%_4NeCOWJU*$-?Evc(d(m#cr&EE}esh)-ShuD}$9c45dmOmLY7c zQo!t1#Cav0)6ZOdJh_dy+99?K)ci}IBh3%-VCS`F_VAb5S__uo_)==9fp%merV$QA zg8Vi*yii+NS0#=p1C9{b3RYo_(sjD<(fk_A*(o=fY*;R_*Y}som#tu&0gw{hTQ9N@ zAk1D0U}x19Fb^!8U>x2y6Pa9N3`L=)qJV>)GNG6+j2UBKKkYaqTB?G6&skfsfkvwZ zANGMS;cKY#%58f^nbt)nPW#^BzD5zT?D5g0t>uD8EXDT1132qPA8pc^b;O~Ne|LCH z6c&z>Hxw_2iYJ2ym3mhc3BM<4lV+2%!xju4M<}JHXA;AjB{2Bq7CesF<||+T5wy(L zVBl#wcGLeG#`u7EH)fyTBON7Bb+{cF4OHn&@(AhROh~$Gl*NP4;RGoug+dQWijZX3 z-X4iz1|q2OW-iDT)0~afBwKMXKuj{%k-tzKaqZ6ehP`wWeRvzxF zDU<@~b;v_=uqmse79`9U@6ntAbv057PLY#^z(Dz&)X#IIy*E&sPXW{YpQxHet-O*@8cF)yp2s)0+un= zhwfSs1IZW3;?(xZtbsfYWh66kn+LH?=e7+NyOov@bSf-E^;5MGSD`)jHZqV0SFKkb z8vD@%wBOzdPbN};B?q_y1o(*+I_YAa^9?dc0n+H$z6{z&u*H8|6z7hi9WbwfVj)$nNujw zQA-$*D7T>69-%CsE^~)8Qp{3vz`2p6t=^vsP*Y9fCyVIWhe zWJux&kb--tT@WfMvDYY}Be?PW&T$04VLps)v!WNs8U2g;3gi)*_s!3>J?5jE*fm#7 z!Q+-=%DbxQ0IGz-Bh$U#Zq;-126yMI5F3|3*Mow{UjIu9y-XlL*En=O@hVa)M^)z4 z&0U7Ca}d4r?7r?`(n||tFIDX)`=d)l-Up{NK~h|Qvdagn217^f6+8?wfav8k(~479 zzjHcB`8^D~IHR~hUXkL+9hB6fjYOgdUjpY+d_i68eySjc4nied;Tw!xqGrA}u3Roy@%==Q4OdUYKYjlUxKlc=4Mgs z#|NP}`Tkf zfPlq?t40`vkW@+f@)Fo3asfnKA@J)5EPHkdau`ux!2iv=5^uHp+dtm-ApfVlv;1FQ zSH(sNR|ShV4G7xeH_M-7j0#2@8z^W>bQ-%qDXpnEFep`umF|u0!6DPOrfxxl9EAt7 zw|WdpilSzpz~7|&9J!sq+=0s3cZ1hH&mO$99@pI;8-)BnF#1@EyQAIRDf4zoA{N%v zoymA|IJo1|3-(khi-|pFt80-;ic6gniVI3CwvzN#)>K9tl`36_uc1vmDH5uaYmrr^ z(?p}`jGlTpk1k?y2ke%qBEzwcyrzE)o$XJrce@J?-H@RI%=^pRLo?ZF$r$?H+i8_F zOl>DMck*jaxpv&CN~aeC+J4(;s9sm^F=T>swI0S!X)Ms4q(*8@+zy(fV{uW(SbR)u z#fRQIN~s)4`iW|$mJmgU3;eWKh9RRPi3A8z`Kih)NN~5(d`)YdO-8hKqMMo(Yh{*j z%>VF&Vy$Q73UxTmTn_nOgG^b+pD};Qu}+3BODwW|Q3iB3e(>VI{3wwiNm>N%w{3=E zXvY+Q=4f`5NOTte*~aRa!xzC~2V2MMlxOC!mD_!8p9@Yvf=Wy2?a)#Iw4Y%mwqXx@ zwUNbt(0|dJm*KnfN5Zy|%%z;q_O8`{@33Co2fLoGAXsp@^F)jasOD%i8{tp|Mho0T zCjQw9z9H2%`Ryb|=Da5y;Twbu2ebK#OSN)a(Vl6i*ie&L$VZO3S-pOg&az>)1 zx#*`Pp{-mqR->bvf*JnD`Huq;kulUKdQ`qus7K(LOjEbgMEl(ErC6y?r=_>hH}&kv zGg2^ruwc@cvTIkH3Nm~nCRxIP&G`e=+`&+Fyiv*K=+XBj~M zYJ0RkbwYMT?tCCsb49!hnbUg*)g=`KgfYu_Ea5hl(WoM%tw6CU8s zmdiZ^g@2BdAx-0Bx=B zoSk!OkysK7d=)Y=k0NKg17Avae&CUKi}W6JM{3nXgP6xbSsE2Q*QE=Lx6I`(2d2k8 zv!DZnl`h(=`#}~_?0bCQA)#Rx?oAulV(|qmv)}O4s29TP7?=wooxBzvibs-f$ixj(CMNt* zG;~Z1vV&Net~GfugRe>IqvJ}UF#~>w9{qUtNmzp>q00RS7E`A2Bj}+LMYukIMMpR# z(L9~zz1o~%7r9P?^T$&?;&h4cE<*^jM~ zCVG#>ULRjEa!7K|e%c#JPx6H+TPs={6^9ejer*|86YZ*vQswsvqovIj$bbc8@ep1qAZ{8ub>UvyuNiEwWZamp;aw4?>*ao!>z?6Fi`vD z*D~I@b+p;Yce07wb9c8G7I6yqWCK{S-s$l^MlZ_xqD=!Es4lV+ZMDX_!rwx%utE&| zywfMu{)=G&zw5(-1oLVH?7evyr_yW<)1-}ZVICDzv$l&k46;3cg@6Tc8;GI}Fo!GJAD$XllFj3BnK-S?CIxF(73M0W4H)j17nmcR((C5L zf&#B(4_mhD>pV6;Y*5e7MBFjUuDeSna_>~YnvOy`OqNw5_2RF|Qkf^$*7k5!R9cjv62 zP$-=Er+&a7*xJ*IuME>PVDRJb9vo!KOXXk&0uHgcw&s2RZR!|V!1;)Pw^H$6V&@!bu#xlk6%r_V6i_95~-h79>_Y{|ysMH$Gh}n~MiJuj)^&t~;EvSUZ zYJEYWymp{KQC8CCK|%zv{dMC?HRq;QG0=K-&?a=7ORdiWg!I4p=%3vtjG?wRP_G5- zhPdQxQ0!?3qliVE*N51Vc_l^`UPR|{V(CcpH0Gvyo{ejL=BbdM)frn_U^1MxFYcr$ z3yX9%vEYTb#8MyyuHC-#Fh;x%y@$r#9ZXU<4UhPCX~w-7i(0U;+*(e3gf+T&(9MRg z9z6XJ0FvqNesPzp7I%GLmh+vKCX(%K>1M|?gsg>CN? z;ZD;W;fvD+8{iM6i%o<8*}&a7xcAlsHHN{bFqq7=h?Az@B`@I^2oeZiL^0Kh%@IV^TPeWijTtOxrUH{RPjnq6UglGY<&)_JPL7{?56d6 zQ%i@0p!^yUi+;MhQ8o+q&VCWx^1u0-n(=b3frnJGW$XwYLn6f2_2C#!arUWlD_0s; zcuUuXQtexuO~D((a9nAd-YW+3B&>H^CJ@z3H@insOzu!_t26z_Fhe0R0q#ZoSZsRG zI7|+TLba)l@EwsYou`uT!TIB;AA4ic2s&4Vz|JxG7N}0qIYMpa92QT#Ga@37ltD8T zgtf<>L39i&@7O_~$1rw*93N*Uc+OGz2B=PyX`EMPI?mKSGx;9Q7;<+WW%fV#i9tQP zh1~AxjTU@}4CX8waY=gt-SA#cy~OcrIbN2dd8W;*M{Q(SURl z5vzM}ECsl?C;JBo{E`#**OPg^kE|eFW5<2dU^Et%O1GRR0+KFiJ?i|lQz-J&uPuNc z<{^-wU0~eb$>GEvKrO}`^&`$Q)^aT*#pq0O0$``m&Z+Z;0ae!o!e{ny!m=$$+zD^H zFOliW!Q0a%eKNmu z#@)fzjW0D9`(i&rbkF4Zl9hGea4jk!S$*v91I&pC#6PmR0B$+=$rKSM*Z}iwN~II1 z5sc>M(N^q7Zj3jnM=vM_j4mGiIYP>Q`tM*46Q*SNX1Y?G&y4Q@nIBIkYN@2l{NBck z^yz``Fl=rNh!%C(#eBca<7fIQ{AdUIpluUyuc+@BVWb$$U@k)k+c&;e?PSBjh+-rax7o ze@6&f(>`fMwxFYr+m!kZ2M!`FlB@7su0Tf%$(Z~aF&^FCAymqVo!viCiKmemKZ5M5 z{;Y-CM}WW)*WsMGa1Qqokf^tP4UwSTLy6e8--W-`mufYMG73jvP1z*SAez#r9!^d` zIrFTd*uxx7p?4EksRldYF0%`>aS4~_YjBERPU0S)uN6*_g~Aq39mv_DS2ENK5oyuc z2IPn>KGKL+Lp94PUxNL&&cYr-`3TKP z#*VMIIVB1?lp_k>ER{oRZYt?^O0w|66PO%8Te{lJe}@4FzD16t4P07DJTs9blTA=? z!!VBoJNyespdRaZJfW5ZM?`h%EZ}S_?MbZjeE>^{2HAz@pgnNpu^>o@B^}wjpIqDn zP)vfyE{wY0V2&mQJQ`RZ3WbV`Fv7+delTQEO+14-***+I%D6o-779OxPj#ZoHB5Dg zw>@zw`#y-HTGLFSN=HcjFSG^xC9q7JmMb^l0S*-Fe79@7;q^L5d-K1F2E zb7l?6_lbfGQifs!H=k=F6P}-w($5GA??CBDARSg^v?M{{WFHdTy~5=Wk(;=36rX80o(Ho| z!q>qI%qQPN0^q-6k^m(SpguKClQBvQK`tBV@9K&mI zSSE*-;sgf9O+TwW$$S}Cqd12M045nznswuZI>59r!2x(21>ZUDn`8v2a_Mw}o%108 zEN=sp2Te`5?;BLPj-kPQ$|S{5*-(zYf=|l?hDp3h|41Z~X%W0bIm9R-{{`Z0+@Lhq zNV*X#H-|JcjhxnjqXBOIuqwpb+|kMwDa{~-F3)-IClq;n2-`Y{U5T81tLVzFy$O3# z-L*g@q<;r<=mdtX!dguh9_y(yDsC?b-d_s1Q>5C=N_7JB(RAt{8{oM+nOOVU2)jL{ zs?pM$xr@)UPKaq_w$!~B&XU8i=Q;L5cC0i=O^|+CZ8qAozp?#?h{JK(&XunYqG82U zKgqE6t&w>aD%WDX%{NfN$7fu*uSd|`#(pIn-?r14KN1+VuqlSj^!w}-G~DT>9Sx^=ihT0qgL62DRiB$s5DlxQe*2nW3VIV1D69f03Ylfqt$FJJ|0b8);i2L zuUX09>wJ-PfI=KRH^C6`cfaTtdz!n}r;^&^KCh;O&Azf5*c#0?^3A>HPmK58A=)!t zO1f~*4GJNHkC0(W)}$>-S&1C!@#?)X%nwN{V+i5Xrm{FQ?+P?%Qk^Zp?NLP4M^fHt zYN0f?dxjysycvy7LJ_Aab6G&5xS9fGN~B!qnE00nC~lB;*W`9VP~wsHMMUe9K$P=@ zcbcp2*M2sw5A^Sv0Sicufp6-ePoq7Q>3{Z}WGPexjI~G4y~4s{aOgzBr#lC56E+N4QRN#GM!+f*x`3?jvm>+2i+Kom_D677pccBh?m={DNWclD?vUPH!?djdtd+^ zh+N{csevFb7(KF3HYo1`E_Py39n`J26yboiiI-0Vv4qEy=pM5{%L-F)IacwNZfG|d{HkLxy zu3dwZOtA-~+(bfS?$K+nLeH`pf7CtLH6I-@lh$MSt9_XZZa8Hw@L8NDx1A!rh~x%( zBI?i+6MZ~tZ#03dpKLfO{`+va1I|d(p+RR$xqdZ%x?z}%i}Vy{#Ht2v#F+^NPHkk0 zi5LwY`-`E{yvQgt--#AL*#gcG~ zUff^!d&}btx0BfogOBFrT!fGbNfEPChDS&DFlpw=YTt+xUh4<8C-eNkKursT;1Lpk zSMwo_?rYf)30S~dzyw3PQXeJ}JaPa@kI3k6767B^45O59^L&)of(BM3^E^1nWsGRG z(6&5RXZF5d8{GRHk=s(>?^ud<$?Oi|-PpuLIN>hA&JL>E6_w2nPQai0PWG$1X-BrK z4)0GV3B0E?TE2j}A-?77^C>3BOoy(QrI#Z0(9gn8lt$|?V(vqX<>5}S_SFpvmHLVs z$!gF=-g{kwW4_X^u*wDXQgGS@Y99gl!zDTN?ERLnnV%#f@Y2*im<8x6Z}B-2;cJuU zE2jxDMP0u38@C3XN$K{yff}-9?}MKbHb+UVvfB)3O!(BCKvU@|?qNp3PqWFo(Q^*~WC;x@VMpEP4glpwTp!ZO8j94cY8_ttTH7 zc)W21a}EF5`P$v3(%-P32k4s{)c3fTiF(sqL2+^jZ_^-ew0t`$kS`j9tN*fsxBXQG z_nn?o%d46C-ir>A2mTT}X|$#1l^ZwEZTHv-qj|UDZl? zG@3t~CG7Pnnvfr`JwcP1;ta#!4AiT=ALrn~gT$VkgJ|GV$wSIH=4Y4*Tt2HU1Oe-L zB}G*_;TDlFag^^OU#=`B1kb<^2e!?U0Aa64b`xC!2%};tQx&sRp($g~(bl~jm8mR% zxJWF-*-w;XaHrJCmhPa^A^}G2?*lYjXI?6o1|W(PPSXmqYJWoci=~_`V%|+{X$z^$ zfqvS6VKuUJVd=8zfHMWwqvO*u9AjyP;2bHZgjOuE+OlF8nWXl9DcoA~OrEN;0zlFI zXi%2F$e|Mnw0UJ&(^b+ZZ!PbMIx8@oH-1)vC`TonmXZxoEG?O)J;GL4gwsBzNeW@v z3LvNSb@@pQR2BSvWC?^>_|dokKKj)KrsX)VOsrXQahqV>4D3p&gFYDs@qjG}gXU)5 z(&O?*B*wpMq1h#~4HcSYj*dE?m=ySoPA;LEWiOm)OivBs97l|p!UG0LZKRmwkHdrK zPGutNWmeTlnwZ;2d*%z6KiMQIiZ18c#gY}egS+YEI+a>QN;!j!dr+nbHV&FCA?5B&p7eV>1$>6VRHE?>14X5Id@;Lw zw$3Z1CkMsp5`UYha4gSn6GV)FR!0r!LypM~Vm$rMS3S1%#`so?dE zyUpKr0D1HhdC>|#5ouEI5)O*p2>@>9m2H)vh zY-I7bZnJgzpxgc7qMQ@K^?}c68h7$%b5jVv*{~-(E0lWUi~MjexB#+IfHbG}rMoHo zr8fw8H#WkAzh!ObKGU>Qq42@Evh6#;wShc6rtA2tc5_y|u?czlOxGdAzZnrme`U0= zRQbxA0vC?fPO{3Bd~eQjEgQx$li#oZVb0*iQ>_rU$b~f~QjtWb07)E;-?XSX@uzq$ z$$Tlv`9%Ro*ZSq{T<`K%XKm88N947y1^ZFEo+kp~OJN3J@Q!~#uDwU{3C9;R>2jpV ze$MCf;v4ZUR{~ekb-JHtOKERS6y2R_pMSiegfPI4$0xTF&Rc?>8u5#?y~&rfeY*@3 zMls_;eJ1FGGBJM(+S8qXiwNa0okKuw*G$hdeGh9aHXu9Qm#Bn(K#6i&MZfIV_DW-D zu4RJ4A*ZD420<$Y021{v`YMyRT;-R?BX zdkIjHSn?i%#q~qe&Pup}o6FC5R{qV+>36eR?P?ZIPkaUxG1n=2)g35K(TQRCzylEn zZszt%^_!^yew9DEZC<;#o`Qh^w)_3TJH=V)!&VCP`%xwfuC}L#q}#qhA|8HG7zLHR z5ma=1zMff>KR!h51ABfVH&0xFcAM@2r=XfgoZ`0a`aZ9)-)_kIUxLjZXusyDdz;0p zIXu>_>t_$2e3H}ccLvo|3;9p&Rnhc>AP zNgJU{0y_~3AC@6bQor!-!X*ds-;m|JA|Zxy5GR-5HGom^NL!opWJNwuQ!Y5i+CqRm zQ;0pSNGj+XZ6jcnhHW#yIr!AO%Cfn=;*V|K=v4?GASV~iLucUZq3QeE|CT04c(WtJ9G5xYLR(d~u=GEKip8t9+=N4DgAU0HNHUVul&<}LV8d`7n4!co zcdY&p&sO$UUT-o!%eZm$#HrIt(De)KTc&q41BdwH+VJZWPg`$oxQ0^UE}1cyOt@}y z7U)MWO3))+ZJW#Im2I!_<|<9Cg?KO>M}}G#pxBG*HjkK%8kXG$W6Loi0&17)#k*vf z8FGcla--($ukn(P3lxJLt41_V?>;nbxv_6liAWI9qsr>5$EmI>0M z@5BmBsb{y6zbgrDqtP(4R@XzV4RKcGfog&<-!ZP!&{FU+xZWxkXN6M1a!}CsX6<79 z@nUkkTqS|!ZPA_fkMUs6Ta}9w2mQ5dcU#;T`R*u0W5u?Fp!%d6IVUk+T^I8OZBPY@ z`^h5G(P&?_8i{%?w453!g9`@Htf6}s8IXLX{it^PWa9L1DYmz|9D0Dl_0`$q?ELgi zV`lC0c7S=L8h7DG^Nxk1S4EQyKNK?rwM<%@mY#b3u`wqRn4B3E%9=nj>TAr2_`biL z#tdDiv#VUB7-D2Mw>j78Mjlem6HobuGs$r3Y2@9N#o`fqTDX~X?Mt$Ilaw|*S`aeV z@LsUH0R_BRRGOP2beBQ|hvKguUwQ8!ivEikmINV<6KPrgDPs3$#>`WJfo$Vec=bi- zCJi`JMHpoc>@s`e+aspn99I4NkXL-L8o0#{L0v7TE@c4t8e7yR0b$eUM$2;WD?$2` zr>lR9!7XrdZRa=9Ulk1>ihJ2wZYsRbmzFZa6C>`f9xb1gdUZc>(zg zHhyN!_%H{mevFg;mE zE$Ma^omkD^)$Z6U&!%tJX&OasJCcsudHX7JLHDca?pkW+7b(BN*LqjT_~sA^_xBFy zB;4&kxc=M|#Jk!FVgUW<_0&os+@_2HavE;ilT+8%AeYY9#Dt98pMh~CR$1Fzjh=D3 z@*qRXLL8wqNTZxqd6Oj&F312Z{8w$$la8$PY3S|UlGpQMca^KbT+cKDnEb}z{! ztv+I1Sw+=VQ}e2^lEi0KV8&84Ek%?GLeMRTih&`934b4*tyTf1uTr50G;!$}vi3J* zg)`^8JNKbSrxc^tb0n9g)1NHg@y?(kQ6p6a+SoM$=E5Y!VxF{1x@O4CG~mJuxA4EI zcoPAEK`GcSis?d{XC}~;sNZ8$aQvL5HrCVq7~d}xiXMs3N?qL##d~WOiWw;sCW3!* zITyyzB6wh>9J_k>rDrv$2`lsJ8FcB#qTD9RyR!?L%PeUuH7m@*jy%lT+pT!rQ;OUA zjTCqmk|Y?JI@q_ig&aGISvx!Z&SafbPDY2Npa0}%15d4@1se`L&<;=}(FP@BJC+PL zNj5G1Af;_6*-DMAt~J2H zVWS>pqi`ZJDzM9qHM$k+t=wNUdL-WmYoAuuUl`A@^CH5>mzYq9QrgpFGPlh#8vu1NY_qOYSc5k=8C1gy{t$j=>$Zb1_Sgg>sGwZ~b|0C_UmT?7t5TeymmS;<>)x zxHFmDRMf&gg<`0qYYAN~qnz3}cy`b{+jHrzdG_boXgmb6q;9VMod9?NU^7Akj3h6V z@i}uw&41fp*A;9zgMWP4wu~7!Y(-b?*^u@$@)GB`c2^9JPqWWN*>yE#=SCsnZW%@C!gN~{hSy!#w*$a~K z+~>%Vp0p|PUdpA)$sMa?=^0IY4D^yWnV$lOWas`n($-D>8uHP+bbq&--Gu){VfB!4mnZSEdWNus4 z{04q*TPwfYtxyNE=>^>U=0coz`;VeQ>0V**#ISiR_*^(Q?R595V__1rPeMj2LBS%; zmOnF2UuHLIoZHPflWY)Lv=dgiU*5ga%r>|hKio4DPOie3m!d1vLS!aFE9B-*$`!dw z^zMOUYF4%}6?JziKojx6vLTvUiSk;G8l1FgTKcEL()zZlByzP;IXEYQa^xe4Yk;w9 z$&?b>d(C=h6W>|ZqnsCg&*@CuLsI1N-!e>Qa1}!CDCL@JV;^xA5P%Xr6pW7b{mH5^ zQGk+Kx78VA{zBWtVdS6c9wzG;l~(ai4 zP?~?F-lSDw-?S`v);!#EN(h^k#DFLMte}~((&d&eT1;4pioa@!_f3VyGRD>3-5-<0 zHmUON{+&hM6nU@s#HTx?Mr%peguw{Ds?Ix|d4sXx8EjXJFt1S(iw9A{hgEXznKvUojGs2H zr0&f(bQZWnEwBuqP4zMfiqT9=y_cD_n9LmhsNrHp$2A!8)+SAjNRX&=t7st^U&Rfp zO&KBx11?9gXM?ta&iKGw9?TeRrc>x*b#iMR;f*kZ!@!LDJGD(ooRL^>bL-1Yv@q;& z1?XxBY)PHG4Oa;!lP40cG)Nvc>?dvENGwW3-EdT;gh)a&z;^fP~_E^6~z zyf?hMwy&0a(Mn;}vK2Dh(u%XVFQS`aW*F?)eHeF#AF$XXs_$QOmG%z3>IJBKv#>*Y z)`=_0#aWSRqr+hkzCvt-s$iX&{A8axnw(c`L=A^0GyKD~Sdq~tntyRWt;!C_oi!G< ztV*gNkpU96Ku9jgx1Ury=%xwG2LmTAZe3C%x7)MdoppSVVJmc3T_OJ(aXW zCRfB)LPxytpO^sH!(DeeGf{7ZxnED@7*LS1)o*0?>~o&d<6d4L!&+kI`M8)bz7}$0 zJDol~uqgX6!Jj0GXTjd6l(paR8K2mKzLD3mNulDbZc98ldV48Ynl*)9|46?oCnrGr%z8(j z|5-MYitl5>zO0stbRn5s=V~RHys-CB7xJDwz244QjAsoCDrp0$0*J9;Z-2E#3hY?1 zv0)rwUpd786EP;8$Xr$!twTg0mD1-zu{7uNhYbOb)%7rX9dU_65^{wI}m)p-a)M6sIK%hLxNxFCg;j&)fLYL#$#af(7@u zmSyWe#wpM>l?We3Ph4onnj?d21QmGle8^Zs4hvNN(E3>8bU;t)af*SxmtYFTlK3ed zT3QeTCedUSNHOJMtztkUE(0T?D`^vP_py9v3e%BEcS%~+%Hnv!6PLy@{X&GAs8jJ2 zoUY!UOqL^9%UKutE|)AW{^>TwA%oKN9Vc^R4=Vh^`7+!XRTa)SQJFThat$0+D_*f~ zCRvboW!KK&yd07614i(0c@-Ol^BnJd|bZU$AHmEvwN%VA=;8jVIVRU6m z_dM}i2l+{?i>Ghq1PW@tiuqJeOUk%;#bp{gsWOMNU&;;diV^=(bBwnd3(6{eRUI7d zTxs&CPRX;c=2d^+6)HphBo+cE+6uc6F&>4L$aQR!YB$rkYpM1KajA)HKmupHN_?xIIO*6***xo#wIg|Z(0UbLly6RO4tccP=px)Y7p*-5C+*NJKg5Tuo*ua16!qoQ4XimU;} zD{6EeP|V=UGia2BLo@6iymJl(Z$B2=Ilnc*#`9oa#s?FtDKJD8prZT9E=pAg*|bFu zIG^roYwJ>L<1fQ;ClqGYI19wsRK(bng_0U1O6x33OoR0=o|#-tof!q;E9N9r$Bh~G zq!*lnn3sT*iQ9Q?iaz) zBE%m$@v91w{N9%*O0K1keJ}MmBm7!$!y}x4DpyX<}D8E|B zgY0~%?9J!iQS9(6hzeBCWVCgTaaD%4B{gc-An}844E2XjL=tZvw^_(|^LY=Xn9gz# zw)8#F0AZqn1gu=b9YBR}>rmC}F#ev1AZJ42QGP(_w-in9+}u#jj4yz!ET^URw@dTb z!0TyFm=3BkwildbCxH-0_>GbQ)s2&?CTb9QWshLC3!4sd|Jz{88?-RyE%_y3$DHF- z-H6Bxg8LABXPo3}BS=T$FAbfRTB-s%JZ#T?s z6=k%Z=BUs;9fK7*oWpuKYHwRiPRS+S7#+h*MCkbSr()0F1q2qWG9Ex4h4oUr2<5L8 zJSvwCe^cN;{<_Y3rY3m)DtNv(1jopfm&@SAiYlkRn4g%gRwsv7N$<$?<7BvWXA$%~ zrRKsl-`8*WLB`pYiK$22aq_+8IY~WjLR37>zc__Bv}m0>IfZ9AzL@RXn-zL_%c%YI zrsu87dz+X=B$@mq&V75w=ea2@J+ly4Vn3~Y|L}Tb^r88og&AgGqyg8lD@u%uAO0=m zEq+9(0Dbc}&0GABDj6Y0%+PSb^O$YsRO$95dGXOK+Z8_kxq}amZGsT~sp&~|l+*Gg z`1?^fDbja(01U|3*XvBykGK5E_o4p)-nO)~tuPQemsjgx--AEQl=dzh*pkN3&+R+V z;V7sDS#mXa&7LAh3_@GjmHag>kdJME1AlY`VNty}-)I0fYCi&d*S#@Aaptyg?i;%? zhMm#Sivb+rB29uA>wrk32=X-Q;OmafA8O`_2FoQSq7!X*L9ILDmi^*% zgWm$sa;3C?)WtXgz%w_9lU8k&)u^i92vWxsPDE{J>q4xWo2MS|dRDz&0l^%#H+4RX z%rl}#D(H1s^yI+ix33KeD~;az{$d>7^4-ag^z;|X0y>D!4hLO>9@UFB9@~+`Y%Sa! z^Ff%HL6)r5;T^39W|#tMg81WnD@SksbW``gt?vfwW9!vNh2{Cs4Y>$0c0%blh$`e9 z+C_bmDh)kPc0TQpz*Mu-5Xl&RaA68k_S>gCYwBu9sxN+*0TDtQS`#sDw>lG2uEZzC zIAZ%g=5Xn-eg8l8?J6IdQknm1U00!jfd0Lh{{Q&!K*ia@`akcaV^nsOP}R`BQw3Zj z6jokwmkeoe1c3lr3G!87^8&95sCCG+)@-m~i838)`Q}dr%wM3{t|iPqXVQ9Hi>1nD z$qJK?<1>$Tr$4)$%qhNZ5kx55rlxK;yf51iJ}2BKxu0L}XH@=;ZS;E^A1}48J5Qx7 zKJyHV-vqsU7l?09-Zk;#magP>El2kjL9UZyIGXdj`(3Kmizo0t_39JoU%ZW)E#|?W zA^(f9Z|tr#T+;4zcRIFhJ3Hvuwr$%^Cmq|iZSUB&ZQItHGv~ZBYtDz6`LKV$UaOwF zsxDP?W4f~G=x^?c)Ad8943CNn)S+CwW(~242kOWjv9d) zzWHKT{VYj4jR_2gJ&4X$PB~q@;}qQQwBp}k9U+(%-m&wwEG#VONPr#ydK!Oz_W7(sONo~`%!=P60b5gd!9-(+Ke(82CRgE@iM;vYbJ zbg5#_+fxU>`M;*i%ysx z6;B=4V2gNx0c%8B#oe59ZZ9p~62hZ(y~5xo>(W)Gn#huy`ZQiE(EYosI>3}$=*tJ; z6sZNWUlIk!B*a9uK3Af9RB>zu%8>Xf*rwA>t~7Vs*0`I>MK^*U6SX&ksQ%+qXTYX0 zNTbil{3E-au`;$SL#I=|0R;D+&<6r;CpkXHy#~vi>y+p?0F9&HbOZ|YUf)rnr`x6f zn9iuyEN0#e&baSS%&g=3+-&||myHS(NK1FbmG7%Y>y?iE7@#t}@E@x9gH3%#$NfF- z(nKoZt1)fO#MOr+XQDK#!e~}^^;yZ z1G1Lvi6-YLBnaE86$D!5Jb;H5(STy_c zfeBOcxoMZ-tCmN$*6Q6>kH$pl=yx$KrKOU9Bd zzebY10x^%Rsl?R@UOk{2+v~{qrWsOlUr`x|QV(C>KzUH9l21zyHE?*)8-8yZfgLVpYx zKG9!Bqj;rF_>(l+VYX6T!XX5nuEVgUciu76bA zU4Gn^ou?eZD;*Nmhp#vE7bJPFNdbnpt8V`U+EGS)sBPQeeDG>mRXWD05<84=f+o%q zh$%1}1iXN3UYnb&_(+LXvf)>{;FK*y@~C$H^f}3t=Io0w1Uesd6RpYa2lkmSp~#~U z04XPn>6+i>0b{a`<3&6Jnx>#^Ubwp!SE~zz-FfzhsxBG{I=27%h{QEM485x8iK&0nirHGd zSX#bSOTI*EVQXuC#ri-Gtd+F)DBC;Fi%t9nE8s5(-qe?{y6y4&(Q9+o`{VJN>|4uq zNLNJ~>!3%aNa5TXNkwwhov{6Ej4QE9D%~mQ{G3Gp#IwBiZbuFZQ$y~xt#XCqfpNoH zfw)r#;&FyD6bcP4#iZjz*}n98?X_m*p&GM@TAqoJcZ)i?tpOi^vVJ5Yvyv#NHIo~$ zc{>39%1B&^s3>C!Dzz)_E-QJq!8bFRN>bXvW`ta;(lmrZiiR{l{CiVZj#WQnq1<>1 zBqnI;z~BHWY0%7WT;8BGE*g0FSP7JQZZ@h3BJyk);Lmq!ioF1t?3(hg{)6mlZfHSQ zz^@G`KA|v$Qs?8%2X#J#mSS$WmLIO41kIgx^vFnrT_7mL??R7rmtzI{`775cg*$D+ zQks34P2}Zj#-CQR#d5Un=vm#;0ujqaZvfjxD~jzb?W6ku!T)^7BEE`e#?< z2Lm+RIDQ15q|@8_h$+e;Wl^w&87z`b>4dx75{$vBz53d{THhj7=63zM@SKeMUHDwa z4`&}7_kBmX$(Twn$E8*~#JFZ?)KZj{>pY2r9DF?+2|(Vw+o=3N6p^bsE;mv3m91h% zQPiL5hjEg}-P_-kLRlzFV$%dx1X^PjD%1iLJedMjoFpijRY*$}(dS7CWMaP4H2vDq zv{5yX&`0sT?*h~AY^O$YIEAcgzsA&7+q#gjxC%>Kq_*jv=)>_fNVogLehSkhvHAUE z&r8c&(-as?9cmbc?OiQSZ%%OEef!$=VcsEgzq zl9V8SmF-g*x=oN=BqKMX!)hrJ%Wy!QEmghh?lbafr(!>@31YuH8SzQz?xS8Vlpgl+ z&Ui`)p^3PyO{Jg1R%j+DnpClilT9v|r+mF;HZ-!*X*dS5ko;tC{IZaW<_xAQ1qAVC zE)|jh1pG>4WbBrcmaX@yRL@s0Xf*((TTUJw>PWp&He%G9T}^Is^ZVl68ul}4uG$Ge zUz}_Lo(e^%HyBaUbv;7V=n_VrCPU=mk*PFA) z9WtzzMkd+L5-v+&A$@-BZ8aE>92j3EvSx}B|5dWF?&VbdesS*#eLp(-$!YeE z5g&~GF7F_kMsb!fH2aWTfK*ouomeywq+*Po1Jh~wMZdUL+4Yx&&MtvLQ$<%Tu}#~j z#oJXM})b4T$q2KX#}$- zJ=g1rcp`gT<9touFW3|lGtq1FYy^;)6)w-tER|CeDw)_6iPwE(ArvA4C9CBS#Uv_*UMLyGfvtN*uQeFb9e^ zdqrS&UG|(UW5MD}^?X~gNR;dH+kbq)3SebFY~wuJ(4Rl(B<{jA|3Ijbg+J10`ViA( zj&{`hLoLS$c|L>K8~*9&yyx=g(64}_pZ)7CP?ckgCk&&aZK2xH{@tuvWg4S@(m9xh^7!zh>cx<42w1G<&yzBndkT!V??9OOKi5%BFAr` zS9=culFw4gRL>v~f}R@_1MK{W*RQTcQJ;6$0xLX=r;So{JA_T|TVnFN(aa{K*Rx3es@qBUC=UE+yg?Q4RD;Bp>%pKj;{VOlhjNS95Fmfcx(j z)k(_vjF>NvbjDZs-2dc}{?DE)V5(ySrmGh(hLJzA<}W7@J~S{PH3Mk3wT?^L;z4qFzQ zAy=l!)tKg_u|ZAMGCpgc7h6IV5x#J}BW4_Xf8*#tby?E?RBSinSkniG+-(X~FbY1?!odEWXsmc- z_BP2R;E)OEiw)r4E+ljs+7c^-C4nZw=Kq$5==(Laz`2n4x0q`7$f8M!M%#*H|MpYd zo)|4V845hPMQD~G2_!$DE5ptmx9*&(F&wFw%QkRk=)2x{yFy~lo^d1< z_%M3Mf84k4*?8!uic^|Q0yRUoQk$3 zBp4npD+pbV6yzQgC^Rjzq8C2Z!qZ-YO51a>8WVFD*f z&Gge@c;e#B=A#bK^m_W(l=Tf)FK~NwW20<@tf;%)DkpWKcDErNbP&p~lFsccs1(~@ ziqDHCe=83N5#qd%I;sV1}25$ig=y^cL%VjDsKT`DRk?7jGVIz(v$rNDK5 z3uu_$%@{Q54K(0zOn>`(?-DN;6dFdkfn4BOXw@5VAUc(%y+*EY|GPbU4#52v!YMm+ zq%VefT~V4WO-8GI;I+?pv6buZmYPOG6g91-%%4NDnd{{3uXIkmSub`hmAk?q7;E_- zFqOKzW8?#pV^)E8m|CoX+bvanx7t(iFAc{;PDd%hO+BO~SG;|WP#9-01^(J`oS{Ey zg0d)O0%NLHM92laW^Jf&AM3LZV{@cuxulH8>N5u@)TLsL1~^=TsdUVGwx*J$)(-M| zaq<*I^@1%wIL?}GgMf{jL4GVLC7*akekP<|T^l?(oQj$xj=tagHV7@I&er-sNMF^6 z+!u#r0}073nYv$l58!MM%jxqOq{0yFP5%C*-a-tlb6fLUZZK=hijOX!jF9^GbQ=^< zVP;LpZ{J9ezI~(lzidJOtjK@9wh1a`s+#i{UUUv7dgw#`{^TG``jqrPFzSNAeIWgh z&=DdI@Wh`1}9n1X}ubU4w zQ3)NJ%|8ssINhi@*Bma`Hr+Ze+curq?pNX*zOig)VMgMz)z+OCzAzBAZH9}Ste*Dn z-jCmJ_Zc!`0vM+S+l&|y7@9K~4GLpenwu9zoBSVBx8IM?3|l(>tOXa0AH3`dj^@W$ zhERr&_E;rh>WvhxpiV@Y7%!)RHwE4o{v@cYYneq+1`87b z3SVN&juAWnFg9NUPdnyyWkdwGW?&rPoqBgu{7CBy-)WaBUxP#d#vFHGJ2 zvQlf^fcPTNaz!mX6bfU+^3#i_w#GV#EKPJCr@EwJ4j;4bHG=}nCTMG#KVepur-kVM zXkM2`Oa)qUVitz|h8nCjlkdC7-xM?yagMd|`*IABQphiN3bJhHUPJgc6CQNya_Zye znnnd0i4i5RBq5ut&I4P?Of$xeb8C3LnKF(|b0aSZu|6k-e(o|o!r>M^$4SpwkTc6u z?Ard0;Vkc7T>5;0KL$rtgJgm6s7AH1-{sfL@2+9Pj52OvTEaBSLy)pw+Md-_LE95O zP4mTN$`f*4Fe@f+3q?Y^tw#u z;jRdq^t66iBcOW z(Z%$v6NG0MsST6TeA}TQNa-}tZo+Dbdxi^eD2Fvu`h3L>+cvT@Etyam)I?x`F|oRL zv?P5}u~ZqfSB0=dDTZu|Q}SohCe-_K$H{&`zQ1k>D+4igP#fgFtk<;T7B^qb+eYs4 znZM_;2}1VjjMoM&JMTod=)33#cJ~<7Fz8?VoDCapA5w*4P9eN<2jiBQVm`;sP(ODq9aXCPCH5{;`4+5CW_)R+S zh)llM!hV~L1-F$0YE_D_CPa4L*DLw6Ij(e6s1z~I4KmAa7r|4x7u2LtF5s)vy9JBc z%8q?nxFqI0?`k9;m(!~BvXCD4JDmrixA+nlF}Hs!C` zq_Hx=PZKkCOAUx#KT5MskCmj6NJ}9J#5Ob)6hCRY#?jkqC6-bmg6kl=KSu75Q8(+8 z%_U;@7EQo?gXf6_@EHHmlGQH0EqcCSqBiAm*)@3zP|R~R_5PHG69FHFn0>Eqpl&Jd3$J>=BqINfQUO_efq zQHlH+F{w1A@_}}mUTtx!Iv~XIpz`#@@i?*DaF$->8zFpRx}yQW2F9Oim{mH>Ly>n! z!E^Utv5X*mr}~pKjZwc+I9(`{*KU8y)PlR)5}+wYfpy5QgMmP`rA%%!kq2!zIBZuz zhm47mo@(Z}D4o|7>8kWy)rw3v!2t7XUruZ{svqku)RGQToO&=KUXjpGqJq)5#WXIS z9Z#IrOgQD@y zIU^ns0HAwe+i2FMhgL__$zj5U6a&sbKK< za97fSRFT#PIfPu#`)dfS(v1WK212NtQ_48|csQG1a%k(;-DCB4 z5azD;3qGQuoYRnEYA{_mPB-f3#s#AxSkaNDc1;lGYDJ+UNYREG-*&V<5X;|bwJ@gj z>NV@bvZ~rZ$bfX)UzL9Jr`DxSv)x5d=ND*=!R9J)))R3iX1a zizY&trONiyOdfjwbbbeZvN=B41B2#wGlL2o>!02xyEbI<-rhI@F>Cy08x5{P&81%> zhs9QpN%}$8o8M5FR70uI2@q+R*SK^@-h)sxrX=c!u~YmAD3kmDtb%ig$;cUPQggSj zUo)lW$feoHKEkb}ftg%4f5lmx2)~I8exIu>q%6U5xu$e^Ic%#0+sAC$Ct7c0m^&`J zpFhcHRO1}UUtl{DN$K54i(0a2OJmbGP49;&tQ(z>LtHssTRL_MXfdxc;kuvX@|Ws} z8){fRPWO=0W?PkhtEHGzoRAv-EE9iJT77qFn2*HpR8lJ5W#d#K+dF!@+w6^Yhx|oo zo~|1{>iW&4c$&}#y)xA8piE#sl#E%*K@T|_fklUqk;2IT<5^B!Yhr;tFlkxU zVs7d0=-kpUA;m7eMOJtoP&$J2lEeU0WX{yC<45IU^+Je3>I0?t5|~DT;vq1aY(u#F zZFQ9Yt>=PppGq2uTu!rTh9zX&o_$xdc0s(7gTjHW0=8D*oH&WpLn$>KFLw?B^*wK| z?dPZLdyT)v!X%@(8%_bGoVe~Q-hT%MlGe-7;=abzG1PD0DE`+m)yC4$$o`)rYK97w ztA-QG=Q^ob%bD|Oi-^jK6^X|bDTUGQe8u_SM3|l#>vDtS7xboKtF(I-2)B5cJp#&5 z8PC;{;80Yjlfr1L?BHSn_^jeBC`I1>M<}P)2Mq7Sjn#ZB@x>@QowQG`$G5NWaR;x% zw@uT4MkR}k(&>gHm2Yi7hqM~3) zzj8pgnxa_$$HcuZ*MvfK^g~OyWokctNN#pZO-cNcNdow)0Lg?TrAO#5slRuP2x&j@ zby`H2iOOv7WUI>=mYDoNQE-;1r)cG?bxQ?UX><5c`MPHY#59^7FXsac|4_Er9(y|K zhxxh**7y+&0#F~Cqxt%cfSTqLsfvP#*WsvPMM{=+;ekhu;KfvW=y&1=_P_7wtK(?_ zkrdi%zqvem3UPole&1tju55W)2`Rd0WtS>22xGY>R9pPg5 z3(SyzxC!yC((M%5^1uEx2xTBVQhU4n?aU*Y$0%mPAq7<4^g@7t?OZK6E?dQak2>stF;E6lFqiI#L?wPmV}P;8R)zuW-FMY+G|lx+T~u++y5U0uSrJjh zMp(kg_qw=4hA=`)CZNe6j=asU*Zc;eG7aQT>>Jdqd*NNb_3h9mVw5$*9fE@>=)pIK zo!j4;6O@0%R zsmzClK9)pcOe8lS2uf#)znazyLcSGcy!O9Sa!1jLo&^~?|9m|dsilK7>gbyS`|^J# z3{1Q$@362W9#~m}AvhQxU3ZT~hZ5O4ZusRXI~q^4AgU3Bvw7@N;zpOHL+L1ATepcQ z!`0@e`0vZ|jXOeTEGIj~e58WGBIBQs5+_em@n3Pv}VB+wI)zor7v8`Z$zFo7-!)b|@ zdS|$r%(nJKWBJ}%7_^Ip*lPi1_~5-_Qcl6_K~=W&M64re0ZBz135Fgjbra<0XP8Wd?F~%z8XD|tlM0TI2la7_K@?2t~v<03f?PRy)@8Nxx89xjcd+|<<=GdvwYGWesAL8`VGm+pcrxa9SHI}Gz|_-fbBQGL4?^n<7_DTTaf1?aqC;IzZYW)`P19zgb^p z$@f*ucNmriR0i&(-E4frj!pGIzc_%F_7dHB-j>x8Q%Gv4m=r+na?cQGOlrR2TIldwsHO@+NyeL`bwGRB| zF+KTK`t0O#U-YndwahST-Ax&hZuqP4muK}otSIr=O|PDGgc)wNyzwoM`T0pDs4t`e@_03BC- zTlzSi>gmkbBSl*TM{%lJT~xRQixb=Kc_B$b9p|6cX*IN`758{X?V$Dq_1K1yl zy*#0FakqjC34-#Yn&l)T_kzpao}g-XWro%}oyKX9t%tX&mCO#LDI5g7Avb?Cqwqs4 zKL3sKa>YN06ZoP8w7)2U{}q6h)pIlz)N|DPPeMS!;y=!6{HT{WHK+Q{4WEFrr=}bp zl7NUPPeM=<70e*Vle~Ohzs|@ZVcZ07u;XmU@AIJ>R>XF?r^cj zQP=6^{R*)~P>9iScHU0uZO?gO1EJ)Sh|{@E{o4!K8Z4HKFJD|w5zXI%05l5Js?k;R zMx$plltb@~niUw{?_0M{9pKrDoR1szenWJDq>}V`f`vl?v4p@*s`7m#OyUs@kD4tD ztQ-9%O-|%hpDWr|FZHJNoOh_pY7`EphZE;~py&Rl%7sK`edd+F46PcvuB(d0EzX5_ zW$Fb~70p||{BCJwUiO7BL(Qxg+kj_b;*Z$G_PWoH0(uc8ba zwWcom@rm&^p`VlGaI_YLVsts<-Q-xuKiB}yUkrj|cQ8Wbr{tW7fby|)D_*0z}f5P70Vd_&3KpHdM~D1s^#sX=rR{$Ab5Js7`=Fg z$bfwAJ4vPszs%8MVbENL389&gll^v%=+QaD5|%iGRsv@vC=HZM0$tv3*>NID0c(IM zWu{|&b{4UKR^ejGM6wx21X4X_(GWEIf3X32x6|8^B}hjic>QZGOE!mac2=K1aq5R9 z-#>q2xf`E>oxLke{OM=TjYQ~{wUJ|*J6l@<8IZA$IMy-{zzD@(wiV~0NaN|sxHUxY zBBluhpZG?>5G6rw=#cFD4>}+z@rw?SI{WFFVQOp;X&W3IV@Qd<+HD#|3ZVI0M{xbaNGj}(9DmYgET z@ww*Zs+5LnFD|b!Y;5{6mIreR1vq7+S97p>ODp*iAkW5JasRLdlT_v6hM$6F9nJj9Mm$J^5&-F0_Y>U?fF)i?vwk$c(}EESN6e2vki%7$ zE6Nv;D2<+CNEpvRk*=IypBZ1-Q=vP)T5CAZj)Dui(PppQfZk$k1dT!hIk)B;=wf+l z&9R1aYRc6{G~dzQpx}e(OiwK<%VVmNCXiN-0C?3 zDq7-03aFdQ+FUACFQJtT8?=E*0XHLrEe+94UQ6`>TvLb;#_4qItTwFk*jL#YaMXRM zmP*xqXs|9q2j5leRQTvOrM<90U-dWN6r-_>ZigtpKwr&c6N_-L{~Yv#goG7Vq*n=L8B}0Qwnm2PLo*2B z_000!*%h9dX$3UWeD~oD6!G7OA}+GZn?*yVu!9fs&kZW(wHBw!fJS(P-3?xv6{U}h zI>PNkKp_XfMslwsPA8*`XmWBM31w{=kfPOioT0=#ZWY_MAPkbiWIinKbCBP|;M3e0 zseXf4562qDZ71nX&ZjA?6^~f2&0b4)l3q|`K+^(@gnn~bo;wGaOJH9_7bsnnrRZo{ z93Xt^xFv|L11QV;(gnzC8MP8)Bp)e&v#dxsY2p|X2Qxi>!;1WK!+F-}d<~`s&D{3l z_0cp!uIUBkMs;nb$a60TP#INZWO3cDa1)R|cAcP=k1O zyIbwl$G9ch%ENi5DvRka(cL&xAVThvLKeAAjlfbk9lzqj9jw#QmRb$%-LKk2KW>59 zTN}?VxnpsOEbl*W9Yh5$!XQyo-Z6SlCj8_6@CQ)bw1ky%JuwEZKOuJXgeNoUH(pc? zeM%(;eVN5=XMqzd3W2D>0t`9t1NrIxNj%`ecjlg4v> zy1|sOqV7v_o~Q9NDljvtrOwjyAUI>TZYpM0Sd!+s19bI4(*;4jaiJKIm0rQ}JVf4t zt-MUHsoY9!`nl*GbK3ee>Y+1nIT6uzyFY}LWzY;9EPA@!w@JuPiXCYB(doTkiWiW6 zjd2!*!|n)EhC_6f&?2(s5{W+~q_qvcu)+Ih%=@=9%wt4$H$$M*Vok-j*UBN2m9#hI z9B}E0u;PMb#L=z7ev+93aj*A!Ia8RgGkE8@n*rD=F9wb3IYt;tD)MznsZ_-s)+J#l zg$dM$1ZWwWyfOWb+0gTfwW+y_Q%X7$)2Jn;9uw`}aijg$mR&sW4p=fG*V3{3i#(z0 zG7e!sSof1wGir`#iX+o5OuOiGmxW|~nH)UB@|HE+K(xKPG@82IP+(9dD6%Kmlt>UD8$(KHu|S&W46e1x*v*D_g~4iRCsQv*WZ4GxU%4-FdVlY^L(qnu1ffGOop z&#F{Gh+=vdp?$m^@ zc>gd-mWxW@VF-O(p|G!f^LtpMJHV?wbF93(BhSR> zKQ!hrDLOp7F0as9?tKcq;~d1~#0!%yJYx3bQ@52nIbi)ASQWXGrpOj(<3I>>5vMgi zEcVsvJ_VL+VJJG>#1hT`8edT%gUCMitBi72iUP^B@djpi!x_EdSJ}7&@nVnAu*k9d zWquIr81E$1h`wG!F6@G^SsPJ?GW2{$*#+_HcMT7r5Jrj`ou2rhha_|D%h_prGV`{qVYshtAPQ0pe>q&T)j8EtDdM&f}XVF1B*Q_G}`)Cd2JsfHN@u7!zf zPG{VbNdFdQDuR(|SSNP{c=IfEXfX=&qP(J<03DE6M+1kNkZkw?cKJOk4zF{RIZ!7| zx}-F{S|t$`LfkT}b8ekF<|D)R5dJ|KH^j>J*8p8EgREN}`3cN#%E2oWXQ%|M%8{^Q zWC(;SNCt)Wx}JGX&THd<+t|lgYHh3vX4{0e{?2^C)$&*z+*%Ffq55bAqtdj68XX|8 zL&6yftu-JNzg6_d@wk7EAN?5#G+fOo?9~EI*XI5^#RcQ*CZT;ID(znZ%&n(?gW5e6 zZu0(d?`Y~v8&CPajezn-CjU74`mYI4(Lw=J1>GyMI1DIE!aT5mzIN~(C@MNL;3|eG zWocG|86sAI=AjB(-9qh1$C4p=lk-^wI7c&0OZoWwQ7pY#C&3gLi4wSe*v5HztL^gn zaX8ueZ7p!{>b6W}6^gE&krmcoYZ{d~uk<)|+Ol3U%)@wgf+-b+&sjv(x7GKf+=10# zF2HW<1x7`q+SbWo3-SOPTEZ8O#_tHa7D z`B!4}(jAUKd0L__kpH^wwXk~ZtfN7NL}S_P<0#Zp&6cB;#yqw#J4^3D(O4AA5M7hS zYPNMSS`tP%vMeYFC0{f?fe(Gk&85`PgOm zBm;eINO^a|H9LYTxu~HJ+%VAel3JJTDhdVz$ z34I0cJ}Bn`g~CQOXxw2j7>BjzH+Z$=N>7PAshuwAq2+cPzYp66o2X%%@K>|<3~{{@9!a(Ge~A(OI9rrQ8Z3upFqs6*GTzk zi0+)TaxsXXimi zmK(;G5KGC_167icF<(UK*{g61t8ytrAWcWn5hT?PR*sEuhZsw?Z)X5tX*u3Brc0*X z^+t(C+nn1*&#@6W?UtJ2`KAk&7tfL3dcXC@XMyzGq2^nJNdu1Z=;)I(Pj#PI`Js7+ z0PC+uWX+TW!|mbVe?UmMid^WOW3dTh1%O#s&0SV)ScGD~#UE?#*6s>IK0Ryg&KD^H}cAx^nmFG}fSO!d{ox^FUmyASUs@W%O+Z zEoEzH`U7dNxwQtg8>db4+|m!2&71p(;wO;j-4jkmr|Ff8UpOO-gWUW4Y6N`=2|xes zKq4roQ^fySz?dW3EbBlN>Duo_{soePQ?1=?!4G0g0}HuG{Fh^ zuu;)5j&)~>t@YR}SI(OexMmSet&cLB`+Q4NJ&0Tmrmm7fG`|2KKW2a(2@2tbb-V;XU zRGG?tmu8LLOvi>Hu@S9bS_m2?(5}g2;49wH6U}pB-L0Seo7pdby7vyFPWAU7{lem8 zkK3=)sd$3AGb)}+M(7FT&84ATeOQ5ih#Uh6m7UPBgE2}0WNES#nay7!$BtiLB1ddX zO=EObs0CZTUB=5|r!RM^TsX$KRG?x+C04KPy2_3l zohkVH%3Tcmon#-DUYw>YzJ5yp^h2sV{~~b|A>ZhB(MX)$UfBak0zvCV6H1ha`jms1 zLeX(1DZp4=W|z2vl$_CT;$nA3C6)d+lQH6wrz23{g!mT&FT*R&!)o&%&1EirFe^rd zPo9auOxm}B|l{U~S27ysJ)7SlPcHXkO4%4WwcD4=wf56!Ot0Mm;a#VhH z!BRo_5cV)6aX$NP=By%Sp%zQTVXeg)8RtHnyC4y=COZfUh#k23UArevRAeR!8Bl9u zBqM>(yUL3&C944gLjy9g4fa9w8+*&cM!3;ZCY&fErTMY_wWGED_2PBVoBIvD%it-^ zSEWjeW6^;mSy2J4L6hB;Iyn_q*stVmtu0dthAYb=YqW?t60N?x5S3YaqPYKIEiEM#Iu!_Aye|6GpCST-RGqq{q*+zpRF)g zA;Pme?C%hOXl|99Vxj>@nr#2a_eP-Eq%!%$$u^sKcAM^ zK*54o9cxv(XR#!(@iq))J!Ig=Dh_8>Bp@{h_T36s6BG`g%&@hG4SUFsnxTc>&8)Vm zl}wn07vm<4?y-dupbUTK6%Aplv(Ti_m?$Z^$3 zrysmew@%ls<+nQganvWr({==jA09|!yK4u^A#j>;X~j{c``V&M=Z>y2K#Vhqfe66u zVz_&`CXNKVDh_cY{Hq-29*PTTHmd{5!Ebe%2jBJW7if>{H-h>Qry`W6z80U+K+<{W zpSGxW1b2?#5Cj9Js(ph#ZA{y?B1?3p*^-sQgy=GviAbBb+fq@tH`_;msTAt2un;`l zK6bQ7&J}0ypg1|N<>qyp3W6L_GLR~naM?H_{#0X4m#&ml3i~1%Lz4v9sDP}4k50uY z7%NU2e)1)wq$;3jvW)o1T<{%WQ!L-VkjX-PLJ4UaTRjVmfF~k6I!ljB+zkLyIrTR= zyS20{)Y)UT zuqUQe6L1Te70=Z5@Au>}%73swr-7eM6 z+cPB`8k-v9T{&o1=^ML89!zaUL{tOURrI7Boe{Vj-boeYpu7xty*0W!(v$doR?nycu@U|B}+ppQ09v(U9jcy zA$Y7)LbJ;JZbB@<+<0CC$)&fqZK>p@O;Qtobj_|Nuc3V2BtT!4U+cB6tO%Z9d*Q7R zXhK50g?963avAO$Ual&;(AUuOsOh~%aWJgZj@1NTxJHRq^qpyIn?UCRB62p+WWy|B z5JQ>CEQ`xSc$v4b2-gury`i_Hrg^QmXvcS(<(cNv?X(Tk8%gdYrJ2P+?ZQ($3@v)L zoNNU%@K~cNU-VMB)l((RK`n^kC->`p*Xq<`&~R9rsB@8l{|o5(DZ#{q|1Ws?S&@h5(>$vS;fQ(U&*-X&!DZ zVr2%?vs_lxu27&QR_j7sHvL^=a*8N^?(|Qx6cia@$xXVxaYuS!RC6ZP>^89qXg&9@ zqUF%G5NygoShN(9SqbT|$3v1{Nx5RvSo7joo7@Cz+Jt>nf?nCmtdZzPyAoPO&Z_DC z1EW*xk7h{n-K00hWy?8%$a^rv7E~wf$_*=1;|N^jqMK`sT^Bp7Nj-Q*p-vh~gq)e29m(;u4d^=z zQYRDP#Ovm`_64Nd3L##Y?!a!4ue#nH*yn3EngiU>SXI+_tlHGNHH<6P&EFct9-&@X zNyl3}%5oZfH<>$3U>(DTd6Mr$K_w#alJ5*b@x;3W%RH5?isoZb>VJ6etIU~XIAvPz zm$ZKQpk5CD-g^IczCs)~Wrqml+qdkmAM5|)>>YzF;j%U1v?^`8(zb1zm9}lW(zb2e zR;6v*s8l8A^zFWP=6z?Pzm6{>PGs!!=R~Zv_Tsaj^>2z*3tMLsM^ghM6DN8R6KfM^ z6JY~uYeNGgtAEA#m>H=-0mKor>Wr4pezR5OZ;~q!`c>l1giwJYx+aa;O_{c?6SnjC zL-^h_2z>qs-{oNNc{#$cUQB!JeD!t+a)IojOJTQLH%=as&6H^8reA(mW&s#j9gCx@ zni?g~OeH$RgO~_uF_=g#11z!5nQj&7Wc$);k0mM9!?#U-R6a;ibv&Nc^4CTa8AS6b zP(h#RyYsbS-nX(bKx~Cqb`R9Ejp<8#iRRClE2gDpHBENP3gp{_@TI~8wUOk&*cCIv zd4avbPQ$dP3`lTe$ZG~vMC`^1j;={ok0E0Yb&vKIFej<8+>j^Ns=6%XGX2cze%|(g zki6N`n{H_|vT@O1Fn@ei9^mkY%CJN-$Kjd{ts6M1_RM+0ZO|3>I3bjkr_zey4hZ1w`79usUNKnQy#6#O$- z1Pob}V)nI*jO`>0P}2w~+-jnF0}+I1;1JKv+7DN=aC3Ju6Xe?60NDd=favP!)&!E1 zi~JGrILzW;a&^VkG&U)iB@?|i0X!A6QVI@j;}ks@ryPf5o``ZnE@WytNP5-{Elyp; z9%bSX8vlVub9|7l1Uo5-qh>;QdUf^m^qh6V1_f-jGAtv_C5;Nrarohz5hwMovNaqP z(&5f>NZ$S(uaNXWeNr%5H>GF}y#rhpc!P3!PCaesE!9A3zC~YDV6?8Cas3RDHpevH zpZj^g_B)ZmHT~GfMt|;*-ir5*eT0;%0|JraVts_&T^s1@Lx=3zsebsSaDgFf8k!ukYsG ze_LSv{yU^D5TGkFfUa2ob6v?BI+-}S{x^;?Ietot1n~5%G8(%VrB_#94k@aTI8F7g zF5VvzilYvaUTHx&(fRTr_!=KWb2%vXs2}n+AH5RtUEsFP=d4EW>q2j7iT*1m2Y45% z1)PVE=ZDLu2<0zrCQWDLah~;PW5#rlITS*kI{RyOw7TowQm!lz3a!yO} z&N=7RoZY5ss#t;sr>KPHmftD4sani!Bp0j6f@U}Rem8(jq7z7{Pf00BO-bGY8PVy( zy-K3ey~@tfw4BzLJ0khc*eU67KM%JkhK76DKuy3Y$_>+sWzan?M)H+w@|y;=jDl`F z>97=VX0`8kn(lcAJx;%l-_m`5)IFEKYQmCcRhCffq|fAMsDqxl(!Tek!KB&fKyJTG z&UpeitL;u9Yzy-l6CE&ZTBDJTcbErlr`B-qW6XWIrTqYl&Gq)au-Es*zUeG;d9eYG z49CW%GYCIn0r1LL<&d`nMfUmFvw%wD(htG}L)Q*yHM8ewUR~rmkOcwYdNi3w0F^M9sP8Al@#6C=C-fyS~%Gydb^iJCzV5uur_!W3~xBO;TT1ee7T z3#Nlaj~*CjH?OQW3kOK_*Hdr+g$cu@IAksThMObJ{YLG#RXq^u&1T7DV#QU2#>{%U;zVpe|FuR8pkry|Upt|?__{$KoB6L>erqn0@8EvMnOqI%YXnF#WWw621Ena4xsP_=;hi1Zw%Xn%c+@(D(=5^RdGw3^8*Cl4PN4`&QND^Y|#HFGkWGZC7o z{jbM`bkgq&>7MEgINHB^ic~DcTLc76Jd1s->2LX{j>ygXJi)55=onSY$j_GC#Rgb+ zUBNoZh7e}=eu9mEPhFGPe#+^M(f2ySK{`%nj)YoHWY4*IAD`=hT1KAH?)?LPPx6eF zDj43W^pbx~E@9?DV6&a;DEz~T9xL>did>Z|srcfx>v!*26aT2Knyhlr_F=R zHIR=}_y;(ra&8DEob<<(bNWEam2Kn3e*aki=>0C}i^52GxYPUbS8w`F?hHLpTfjG9 zg3$w~Co-o+FGrmAxQ;mGavxQk$mlz|>i5tz$cEr}_x8cGbG$Pj>q-g?@O24gO}hn{ zi^X@&YiHNUj7Flj8;t5^Sa?)oZ7k!)KTDUMbUToQU{Pv4a2fc~-+`TaYNdpi%jSDf zC+~OlNGK1mVZbdTEH#z;j`6FneC6}#cN>O4sUmGFQ#>R)BzI-{W;<0Y+mXQ^MiQI- zhdRR$y%A>#_+^)~I77fXI1MI%LTA^+?5Bgd@xr$0|9a~Tp+QP^0phd)%ohH`ltJ0T z#@^cGA2;uB!6-rAZh--FM6Xtx`&S1X=GR_=a@cYR5u!<^XI>eyl4vpbRUbI#^u}`b zfk+E;Fe3MDGzXExF6eDOVl6G(ND;9@(yH$}plYlC_!wQW1G>e$W_)pWbe#P_EdGI; zKV7gT5mi_%f$Bkt=GHKq-8B~H90b!YnvvzWfuxKo-tx<)iTn81zM6_07biV8lRFQ} zR_PB!tB%r((PSl3+`{@pDIqtnlf9?H?9&4#28gMmvZ%fQm9bsuqfzE?sS)N!R~aqK z2sd=2a=Z*i4D$n#<6@Y1ie~e%R^Uk3WwZCR(TEF49w{@5AE4*3`+f}X3zq4EK6;jC zp0JizQ-f&c14m>m`XT+6`Mlo#Am968YnsD|S{#*zg)O$WkBNe|MP2+jYNJrw;lW9# zRR*pe1N$}MXOPvCV9_`1x_Vr7Pe$hSzSJPHxY7aZMqCSLC6`Y|5^EYhD6e2Y{cOg+ z-P~n$lr~2{2;4pU)FkzCC#{q^m8^#<9aK`u&vhM_^G`~LXPN(EgMv*lhm%ZsyzZj(uu|uxdb=M{a}5yTk62{dykR7djO=+Q;bN^~M8I^UsgaE^F1AKV?Gk0z6XhaVPcSPII;(Nx3B7Kh+ni;{^PI)w;MLzmXzAXFnu=_As%v`TfW10jZ z*qii>v7^z`J!Ha%r};ckJIZE@mGUu0C>dQXBbd^M@bSVy%a}Q44#i+dB16)Kuqvqh zNg!yoy~E6sX|aAdkNCA~9y!;y-ArROeH|55VlHxVdp|{rC)7w{E^;GmafTxh`EOOu zokQRbUI&w9U4AK>D~92!AmlxP|5fsMuwq@n0I940|C9V*(){SS|0%JwcwS(=l*~KS zM2vW0c+p_cx_%imTd-#v4_>$Y?+VNI-N_Ap@HW$~2jTeO_Z1!xodMylORKi=43l_w zNl6?^xin|e`f{}a>&qtx0fwY_iIwWIa2fycrHF_Qdp)fZ$q8C_LWk6~Sdn#b-718)p;*S85S1N%% zlv+GQ!jQoA0og`sbH4!}CM`ffl%WnTA!+&ez;BCIojwj1Cr9(BAN_BZVFgAsEZa+A>v! zxiE-W*3D=})RWO~R7UOf%eDC0g+S}zh%CD*0CXrwwbfikvlm_!I2+UL6h}t=(-|v~ z>fD}YmxnrpdB9#bj}}a&qdUZZnLq0YWZmxu+R>CEZ@rs7Bztfl{##Z&arZ$)^YwwO zUH>*~nXpGi*0w(ig*J=dF=ZA2+dQq=U++yIc!cv;+jePFw-f>he**CNcT^nCc6QeE z|1EJzKs@?q$G`+&&Y+BlBjhc%8;^SQFuG2b`5Vo|ZE8p&NMM5I(zOY)W*gRx;|*)o zkoAxR6F~^O!r^BH6l@H}_YL0%q5 zgQ4XSo|AWkC1nh8brgjaI}|tk(MkA) ztpeRdC-(7{Mw>>Tp7Dxc5XHma`$HTo<4Y6H5)A%R!j54ot`V19?b`BDIl9l+YO9`? zY`00QkjVmeSf##e>=Np_79n6zFyAqLR|6ACs!K`gS%Vr2$|;SN z{S1TTUrG+@TBZfY)qtI}`Cx8foa}9h3~a&mXDU)LDOxALkQ}OiNF=#)5>;X=i#aCX z3^gYK0M8Wpa;K`?~QMyS@q-N{h($K}0yD#Cn!Eb#1>)7Wm= z<`8nDl|K9ZgR*w}D8k~t3t12h)6}$~TqfSmLC2vnuXhq7WKXV?UI;(|-p3-m@zq5b z2#bf&F37^5%sEkv4kH#9{Wy*Yzpw(AytIj1C)E>G)J7Z10MIp)$TSAG9i^z5j1PxT z#(mCc#|)zVp|&ENF6;pjzQ--$)VG1+AiN(@x|gL4p@_fT9YRl&)$xWH9=lAI8RS0- zS^%wNvCKT9sC)-ebeU^4>k0-2`PPVhRub8}0;ONyxG!ADg?~p#J4$zXvmtz3$ghK) z8>*)aRXCG+oX9LVR;F$O7k(5+{zUXPe{RXSgnpHHnH6&4^6&la>UnCJm$)4ZJ-1iN zKg*RgfwymJO%VUW=lKj}=q_X=oh%S03@mG${cDr32tkL%lb8Uyw($9Pe(ldgCUFhI z!e^+)dQkIR#oov}0?e@^rkpQCg!e|spCxavy?JgF%WnQ6RJY@!6r{*6p$-JD^1e5! z3o`SozlK}n7cV_n4z4OogdcM^*h?}xpM@{!Oxq=$J6{Mt#9iY2vOE`|wFLR(mH zdUZ7I@cMJIGuR6}nKyL%R;i9tuJ;JS{v2#|=G39NNbanhLftY5s@;)jVgWtxHGs5< z;oLU(A?YNZ=H=UbdEq2_{bDFon?yFz#bmMK&BLY~+a{?&?_#W1#RX6K6mpWNu2fV~ zawE^1w(NHSYV`BiWQln=;tC2PXdkDu#opRz#Y2-+r$4dxWdN$k88$?d{$+qfuX3Oq ziat;`l;6>;if5sA@s7+5cX&pl=$$!w3fs*?(*1Y4YrZu*qHcWV06z*tcN||U^xzM|Z4K8o9Phh7(S+>`wLJ(1rhr8pBD*j!Q;^%Wo|gJtqq43bPyB4rE;F2e ztA%>0@$CvO&0Nl!C>ZG3+}AL*1$9yd#iF)atM3`kt9HQkSEI=V7O$El-zaV>_wbW_ zlBanSQez{#>>HKF$QUF_!yPH3${7t7yfg$Dol@9UZ5N+ZF`NWr9tTM}@VMCtuDl zS}4^Ynsk*ua}CXeM4Q_(;59bes6SR#o%G;Fw1A`JiP=XwK4r4l4K98YdIcUdbsBbI zCZCCdjCjIA-+zGi7_k2{X6>QZhHB4w_w`XZ;1epk^neA|dKW;IXkyq>@NTDv7_`KJ z*#H|1kMTG)Ti3M3JNah^3(nYKOfP zL=!2y>@dt)VH0NX42ga7{t(YiQv>d?!P%9wqT+Wgy2q0gt}ef23++a1QobrtbkKpf z!W{ByBCu?ORW2-Rh7{GpFz1)Q_u(0`7Jhx#(Be<&;Y;!5Nbw!H{M&d1GEe)bETCRb zg8~BL_%~VVe|en06si7YIt64bC_0Y%|Kl(Iw$Ss5iL zX6{#2N6ko8%^5oBawQ8q4>J$#^jE=QpZ;=w%B5~L@rc&$3e5PLoo+MTC%#upJ74%8 z;JbW1MlX*`l_y8J*$~eNBCF17xV=X-96jeE0f!EG14`no;N#74fjEL;UYkkpyn6&` zwxb->v~YhQgQ-Vm=I2bRN(#o{MPW%_mflyhR`26 zF3t2UAe5LX;X4}$!LVIEe~coH;i`R^1|pLabYd1xPGFk0OmorixxXkBUxEbVazXTqz7dY?@6R1L}evgm1l zfx540r1!!|1Y>{S7Lm#MqwjJN^O`|r^C1T97CeYqp%VLsB_oS!M3PhO)dbxMHZi*u zB-Bst)lH6DC6x3Yb{K=6B>uWi-lOMwbGO{)#uG783jeppSpHAsBj6nvqNX; z-3NV@?w1%)J%t^Of(_EjAg|&^b!5duT#5}*tneRk2IDF*C?p>g3k;*?G9lnT?B;Ak z&6(7+vc6CVKIEuF?NC%8su&DNWa?UxFJImtS6)bi7EWale4K!EyrX9z=2#9d2_CP{f+&iz`sHzgoqBZ!~)z7w)X=Zbi_f+{v=-7p*Q*OemBv zLUx07JASJ(GV!0#!u2OJA&`yPFk4~vrdZD(TZk`N*bBG|P*J9)azz>P{DZG}IL1NNUi$L3Em=*?Cr?%Dc zAFjU4cIqrqb4Ln3%=J$joU$U@GaUPZLk#_h3_N@GGp?8r+UGxPN6ME;$-cj#O3wAv z7(|?Z*Q*V$?Ly>BN|rl-3EC+D8tkjAB8L^@8U@tQU-LRiB9tI&=fshR(*e1{S^I3a0^u%zOUH(N;M5)0aphgV7Q`=kXm+l?iwL<~!m-YKqzb{SRqC;Z5>)-{ENF zWKS>TVqtA8Y-ej~VfN4RK{jsdA4T@?jKX?NGnA-^BK0_5d4A_`T3a6DS!z*zOHl~f zOGCO`smZTP+eU&eME6_%`|%-26upnas8qE2wL??Clj(Hk=g-%V4@m!&Rnr$omnAp4 zNhA!jd4kNhlC(7L5~!~Bc^0;}{h6u(53;8N&F(py%Pa&K9{=Mu_O{tlZ?jMw49GZ!d^OsLVyj5mFnEA zypmrVRNvLR&N_BB%hQHFPW!zP!YA|lOehqnP|G&kD#2CFP5?X}fZLOclho+b6b@n; zGh$H9Z}!?{ORQFsce!M?IQQG@PM!6VV^u|fZ0IKU5nwa9@bRBW1EknGRRR21EH(2c zieq1%L#}){8g_Fl*h;*k3ETZ>WA`C(t%6`0ECH8q5ZAN8^5H28ggue_v^ylaI=jes zT-Q7I5O+Z#pTe(3D>wOCWW`xbM_uosr8%s+kL>(Tj`$%pi@dB z`hPUP{!8&jcD7E=2DZ-hg3iv4g0{wDF1Ese(ec0FGFo9?sH14P(dHu$#0tVMu$a~Y z{@IvDqvM;`n_F7iF>5-KsV$r_pzw0!qFnL&tCCsUUN_xb;R{(D;R~4yUT=E)U9FvN z>~F53P_KObcD{Ci=Nvp0|P?ub%_$o(EEmPCfP|vuz3- zTIMv9^eyX;wpRI0*1mh*C?lyESEfGg(1*pZ_w^&irU$?7f4w{IO@?@SwR<$xx!Ml+V#L zuggZ`1w5A0wPsu`FCMwJEo$gyS<*PCbUwTER+U=i^yxUiI@3nK!T)H90y%0^>?t;kpZ zEwn({P61MKh4~XoICPVNlu2HaQ8n`IyZZVVtcCTAKP7m~^wB(6jyPpa5Lo&w7^xZ2o~<6A*DCO&ok8YD%U)llQKwHUmp>+woPKhu599n2IBOGlpINQ(r_4D<|$^c+X2!zuJ! z<88GlwQqt;xn6^$Xx8-24|<@yd&}k2Hg5 z_l*>Vk&GV5KC~0KV{hc3BPt0A5*eAP5)|gUzv-8%WRi#>=%dN_r){O1Cbq@RCEyt< zh>bV2g!hQ9v$zuGUKYE|;2Fw-FGo(>#C!G0DU9wy!N?0>?WqApUe3G_ha7~(Sa}lH z8}ZPBgt3UC5LBS8AcZ@$1!yx{B~5Y~1gF>wl?mfM^OEeh1H0!rS>z3W4}Wuzjb~!V zdmKZIpR~;wxyrYDO&OCB3YFe@c;A%Vq=In0CMBh(r*a(c+PyZ}~*%*iGYYk8oD;L2T+nNs$v^YDZ$0cyd%ttkQA& zjIfHt)fRGT`$%c1`+k}QC+Y;CX+)>=(|p{;c}w}JRjP0L)gjYHtjmbs@ipvypd{R> ze}#Qij^Fn&e3VVKd9Wfest+rNyV;DGQ8YUYF&hMO#Uqkn6_9$>_ez$3=G)=~!8+^- z-1iOQYNdV@wV;iaN;aQ3dIDY_MmPe%m6m1+VsOU#g2eUQ9G*@_%R^pXy-w) zx^6r|lO5-_$yt1__*zNgm=~{glj^Eoxd5rj3x!YQUpG=gDV8K<$bUfa&}2#2>z_HS z7_*%$F8(lo;h??@Y!{l;NIC(2kep+;p#{Bgn;}18Pa9cA1-U_?4JCEw0evI(D&pLY!KBYu*{RZ}fa!o1>^!{)iP-dfC0E2gm zDpt%z&4Cn7=gbEd8GKvXf+#B=j1gKtt@|oM0}=#b&~BMNWV}H;W#I{!DO@nmgtkI1 zNELD?Gj7_CsZ8eCRGnJ$_8O!Pz~c4H{B2Wrcb!c5MJjipeG3X>Fl)Y4nXsXUKP;w( z%MGXHv9YgMG81iv(PV~_tTLn_2ki>D@JERd&K0;U67C&>r5zc&gd+-E9+z+7Jc5km zMKK8UCL;oF*Qodc%L4feZw?`eQ70^PKJBjBLMp1|LOCkXfVHTzdptxF!A9Vk5YfrR zT=C>EZXGfmYufkjgAbkvI{_1=_oPdtXW)x5JFp6H`3WbX%jn35kJ!4Ze4|_~>6z{? zyR8QMf3V~}LxNPtn7sp5>acCqe)bLFIQR>e{(PcbW~@+1)1Mdk=Kk)vRT$@R2K52M zL$v^l>cSu46C>2H-r=Q{t@f-N4Ts0a)ENE|{^3EQJ@W~Ielgy{0mlGm z70&-FbVqtktdE__9c6b4W*fx4GO!hRyJi>9-;K&0V|NP%AEHaV-wQaF!X0%sEpQZA zp2D4AR}%aN(mOHmo4=jfEpQ(snm5!ft$!G@ciIOYKU1UMZmV`27l>bMopv%-D==Th zu91H%wL8o$GvP=7K^6WoYzGX7;r;yp)n|JfS3_ayFx zH+AU7gVdKOeCN01`}rYQHpvs~PoI-;A6a6*fH6JN`_!NOwEHtA`!i_!@|iEp^2;}f zT>_Vyq%Yt@J>Ly?nCfe#k89)psE@y6B>bT#{_IYB`Hj4P^I_bbiu{F7_#QNrlZxb} zD|hJuUVlPVaFYzy8*%E#I`@TL@YO8xb@9`$mi)6f;P3=z{Esh6d;GSHZBc6+&RO-L zm?sY4C}&&b1~_H|ju?QWtZmVA-0ufn@Lq)5x9|@F!Y9AD)h{B$uQ0%Y=#@|E!6)kU zjbrW^y5J^}6hD{v?u8|M)J%ehPkR536FGJ!5$E;WVdy7udw#FTyI0!Fv&sIB`cFT- z@1MLv?{C<1UoL^Yg3E7Yd%dDB;^DkIWKZ5 zXkLlxPsN7{2ml8mnpevDQ!`RfUpb~-48T80rd@SX&>TXfPuBikqR)?%muK$%ottn! zKf=!s#-m&a{@EXcH+}0_{a;Z6LjxP!}qCJ9Q|_ z#DrtF4F(`rG`dfKl`-9?q0wq?*1GChQ>#|l?9^Ck@o%B?mu_w@C^K(%5w)%csjjZ3 zecI%9Gqp_^J^B6m=iz|h9@a&BM%)fX@bhkm8PEnh#VxwTR1#7&f zL)E4Jx&z#$UPaH3C*SO#{BWR0B{hJ@h7^|9NZ+V7M-%gc)o_EUy+>xN!j?Cl5q})f#6d*?eRt3o@K*xOxs-E1H?QxvcPgKX*{6t^&%jc~EV@TFr z>Qz*WMC$MseD<{b)AC0|Ww?+kt;vvoG6&tDoO?uFNcD$?dl#sUyEtajNpftcYULhJ zfx(TbsYjNXs_j*tXt@Wd&E(@C2*&daNml~J3GgvwUNq#(aelP7#@vY@h;ndG2uL)9 za0C@b#RcNdRu?~kFnmY^5s$Dw)sFBa>-6|dELfNAG0FJ~@!~myUYj5emikKdOId#- zm>60MMfAu{N7OzEnB})sj7`i(gJqEG02B{hj(|E`G*-g50(>6G^}(MBEc&BDA;0a2i~YM6w38QP{QSiNm1A=E+;?cipD#KZkwm$hnpI7SJZ}SJquIz% zUZ}}zv7>R`#V9RHr}8+AyjITDbVFL3UxuyFU}Ol}IU!HxzJBtDCYWl*&F=5Bq1gDp z^KdkKhN0+zY$q=y82lM+{EpS_e0lP)~!26QPm*J{C%94qElJkJZY2wtR~>+j&-b~))FNOWA!t0i{rToU0>olPTFHP z4~qT!Jz8qp!S4gCJ2hi`)!ETo{IXfZ3vU9-Ao#FCA zO@j+OQNN$TH^2rnJ+MLWpZlDy&~rHPDRLog+LLeU>?z7D-(P2P?_O}B+RDdmUY_Re zx_;g4{9wy5f4KN)b65&6j;`zP9@kU(2S)lQ{fmnH@G<8fWs8AYQfa zvCfNw!-9(n(w#nx0NLJn9|N1l+z$L5)0YXv7tBrH{riL~@4`gYP0}tMSN=JXVDca@ z*ss=$@GPXu5uG15HVoliAlE^;lJ@lPSpvUjHD}o!1Lgcjw^u979_Lkl8PtNkoxVJM z;*!-BZ?nG~b$U`*U`9~w`nvne{Z0j&Zb1~wj9+?Sp(_}jZESA}Xh$scR0s?+SE>BO zP~SFolXAZQ2?kk~$VP1uZgwk77_RI<{vbn!?_{vvSgz8d{@^YVC|*8VjLsA4WE z&;}+ydu^t9ihnNq9j-M;qHF}5lOz%CgNL$Tc`>mX6HSb7Ho<{ z#mT>Oh~iZ@H7HK+9@rs!OZZgPoen0;U5&wNMEgnH#xGqROOFoKd?oA}t-E9=hp;@* zVf&M3pAQcF9EAY8BY>9E&KB#;CvWHuy2g7iBOE#}NksANkY8JiRdO~+{Tb9@-n2VV zY-ZFwoMVDa*{X&7XMEvY$~EMni4L6tiw1B9if8I}#$m%3HK$;= z9HqFjrQVo9$ylX{8>?UQHYRCe+L6m!Gt%HVNwRx$e+2EQ80Ux_Yty1}=IEK<9TI-~ z-td!4!{!JsX(Qq1=ww8D zyDJi=*?o(sS3_Xa?qG7&P-<7^7y70k!PaT_!vvV`O+~vg+qRkW5c3@^w6GkRvZmS) z)_WP;s8_-zUZi511NH+brEc2}tIxNOt9IlGnie>M4jIt?+AzoWJT6E}eN0$LA+?2_ zNI@Z9p;@#tYH(iUM+!mp{2KHJ^F<>tUi3!}!B}x#!C4f=6(~>Sit)f2QC`tmWkq?E z2j@j*Fr6^Zk~{#lJ?$xH*$GSszDrQvNq!FfDR>zMj3?5$m>_$;E&7AuqBK}H>LZgN zy?D3KENz)Oj3?UpQlM_oD~({SXt&&~Sz!wJmCzNsGqt7YEdHWRpsn~78cTK9W8hQ% z(>E@EE{apcbGSe?#W3*d{1~VX&_^*rJE1Mg)2XrKRHrs&D1q0)*{IGiF1>m50@>)! z5H4!7oQoUa-Jp+hf;U1w`FZq0A6SBVQLo5?dJ(UUfuFeN6JQ@6i>cpUVHWieACk*z zksmM={Um4g#6Hjj{m>p)z&>0ScMu=g75$`Vcf@>}^Lm3`0i-qf=T=}owC5LKA3pD2 z7Y6L-%`#s=mu)ow_epwjDxXsZ^?8=niecLkR>RAgNzeCT$HCj&FD5%t3k1nZtL;j^ zx!wNBSeDjG;48J;(U6YNr;`l`S=Vp7uA_V}!=QBtOP?RN)ZEr0M&w2aL|$!Uzc9J| zFZJV9kM;_o2&nrVA#w#?E|76eA;K~R!~07SKTE*G8D3Zhc9M4`AP`8rTc9fUT*P7t zeRT8e(&pJ^&$LS(Y?M7GlX{G#Vl(GSqI!NllnLY-JeU;qVw@U?>50BV2ILq&uol$< zW*mif#6Hq_^o*XcXWSsX{imH0U!=40m_7(+dSI_0g#?7WidqqpruIxhfM0F~vzppP zW#-s|m17NJp4@eZ;1_v$M$XcQAkXNBf#4T;$Wv)NjVB zV!qRaE1eX}7~ZuA&V?#rSCW!A(KSRll`VNNMbTo-6oeEqgPu01!`-Vx&YH*zwiiKa z2ntXk#?dq$l+j@2v69L)Yl5+879cQnhMlhm@fk|OXDEi0JtIQVQXSlN4@Lo7;4Q)G z3Yo($N(A$yE^L-4g?eBUD<#U-#jeWf=L%+)t_$d2gE~plM+tg_!jY;=@BagZk+f?F zfk9+V1K2LfM)KoFu-n2$*x03Iy{g|2wrE{uW5%9>TLf?NjaxFueXj=C9qXePI_wc$ zq}2V&H_JSJJ@vkzmvvuwy|vLh6Cdn~aScq_<9^Hs<`m~Xjs*X^L#8x=nt<>_xik^@ ze&c(l#RL?FVKoS4n`VZs7EIICb%T^E?=+hUf$l3R^SY~0j}|Y3o+}3peJ^nIbvdEL zZrF^gM1%Tn=#(`y4ci@9>Pt%VdOi5c%asAkx9qwRU&Q70*a5D$w_V3oL5D^E(K#p^ zc<^Zl>(Iv-)EC@T;aLZ`U|hF8h*98KTydg(cLJ^~_|?-au*@vk*|Uc}k7*~O^DZFg zljPZ>O}MS;H^OUg5aelfq9Y#gvj)ep2Gh2Kp(P0aIaYc zE;>9;(ArsoET*WpNfQ?Rw9ENCeYbQU{HV8pIzO>3|DzCt(%I6%K$NA`#)j_DeTZ%TU{dtN>LF(ESwmgY}8zSi0Q-S(m&xIa~aMwdvjw(JoSAO zTf_+ugKNKlt)#mmHHhdFiq%z^E7lcX+~75hO<)ivbX%=E?C>;J#Zj7C-`cRyOt4IU zg{*eWYlT8&4FL7`18jiNg8h!1s@q(39B#3MR&Gc&rO<(ty4{5My|Bcx8C3OKvB(dq zVX8f9T6u}i>R#*&vN~+`0j91HVU2J%RIC<mIiqWQ{0pawX-Ou(L(ujwYSM`Nl+_ zu2h!hirp8~agK_M3}mgdFD>s@C-uTPoDPHZhJ1?k$A>x{W~$`yXXW|Nhs5s;znAZ_ z=D0z^AEOUotNMSlknVv8RCzZ8nyz>UfwJRmNnpn~F{4cmy;JXGHl45-hS+vMZP3zj zftrWWw--X#9x(^7jwuJTxhL+xf6zx;<8SP}G5+9>KF4El`ucYb-7(Dz$Ee3S;nouK z@4qnKqr`w8mg4dcQX@}8&SYYai$--e|3O>s74aLHun#Y=cNdX{5C5C#5oo*$Hv>ke zi2(DX`}a)+DH*+g;x1G??Ef`D3yIT_#t}pfoxzl4d918fTR5N6El;y10WbWC$gZ78 z98PN0q&{KnSb$>2zZ&cRQ}=|=j&qw{(g8cXh)M1@!=PU~Z$TQAR8b62XR1^xQb)1H-3?C+-=YM24u%8zW|WA6 zXkUBzlFEwsR9p##^e}R8#5SWJ=*?W=#Fg?~PK@A7uxJqe{Je_FvaX2coM?QIwxH#WapBqAoOoNUy%S=BXO!SUQ}5qiRk!E|PpO02CbUi~(Cb1&y37>}>zpTe1Nd0LVWKps0K;%qLTk-Ags!RxC~utiiTk->T`j zI_e;;u(7j&U|U4zA+`gi;}r6tu%J;b5Aj==&-U->Nw4XXl{ZMBtO2@!)RU9W`@;Er z>#^(_B}EPSaq7utaiMvEHo1P+PF$B*X*r*mDZa;VRWoa|2sV1<4`mM?x>&rZ)?8FS z$MH_8yv49QyYF}Y=u&)#F}nWaP7QNpc-H2wq?Ds1098cG{(#wwoPfg7_q-Iat5gQM z_LRo2lz#C7>;m$*?9@s0t%3$7HJBq{2^ddVRp~^~#u*|DTv7sYwc?Cccws}e+Ja@$ zb*j!5c7j+S3UeAB%&{@lOW7)|q=xlT%eYTsO>+2cERHwCS zENBh|V*siDd%$YHffY2HJ~N!;Dsf%a$Mi-4(@^vfDZ^VFXY- zS-~sS`DaDX3u1dXM5M;0mb!y;G7nddSt)nL_>uk!a)C_#fIi?Bx2yYjZRD>C56AUM zEEc%@+uM-)?Mtj&0OZjEux;r7;$;78Tu}m`Bmnq`|C*KmQ?(%)noc;QNI6H~5hW5p zi=vurc%%{EHBrBhhFfUH^ZtPKXGQ0(Tmz;Yl4BzTi_hyLA*AGXCFP#>*?B(NOwAs1 zFeI;0skqM|=Rcz4C$#gpQ?4*9Hgg4{%ZP(h$$xt5$+^zS$yw8RKZsWU5`$`w?XrwF ztJTA3ls7@IY^Hu}mQHU>Uq6~0m$C72DV(daWnEq=QD3273b0$sd^|VB8#+2acD8BP z?QCf8?nvkKYG2>1%AK^Pk*!r@FTq(K1#Mn?t7NUSnQ9r;+qPv3Xw$N@2~;OEmCxq% zIp1bZw;CL37?Y^$*{WD_iZ+Mct-&<8$gQ5uIW z;+qPq0R$b>KS)(uTT{Zub>pOBFr-R{+%>g^9ABa9bz8@b*QhgJsE79KCTwh~a+&*BMB-Xn0sn5u z*ZI}50K|KjA*$4)&v{~)=48P)$w{p6XR7?xt}pAru+RG1B>A46MFt%=AKX0508OkO z=4+H#SRu)S{M#JF7j&_$*&tmoXFnYn`kB{afTCiswW4f7A1SLVr)sf6lqea?k%MA^ zt;W-D5SB>XS?h35O{(^?ODIX#IY>5|JDMOxd<7H-sXD^L1g*mwjtO4%KR{;dfvF)= zD(`$0_jKHtHBG*exbV322op@=SB7iqLTv)nWS7QvNGW$ITDxxypyrV2L4QIK)$GZw z;^*LxZV7Gc`;LVwAOu&Yxm%=sW1KX8DF)f3Ldwu*o*`=9X(oa0J6}5ZSYV{-1eYkN zy|IGADQV>eUM>DHCoHFdMD&LUFbbMrN<{2HG|dLW9x-Y$j`KWDab+yz1}g-9CVcy5 zf<9IU#2j`GX0l-lEc0@jd0rt$)I`A2T_5zS;{3@?H!sHIl1>eYrU4;rsjT6ReT7cu z{JS5CQLynh(Q_fwK!+4Lh8l7+%u;u5^+vPGtTFqjRb^msA}s)Y zHAK@>TTtG(-cl+$z=iMzdB%_;yjYMvi8ym&YEH4*zxKL~Rf@Z`Yxy>8#!P}op^1w@m^ z?&HI>D9>0)z!aNnF_IA)=Ng5wq<$*?@<8qp8j<9knvMJgfnr|0>^Sq#$Ff{vXWg(w z3q2!K#TgSDQU6|#1-f)*5sdT1ncY(369LrX>V+!F4s4=%?55a>Etx`SXdZ+|r zZhQv|MxnbuDeAjPc)Eb5?hF=YB&e-qA}ts6t;`i?X(gmhOsuY})ABh?AQ${i$E~Y* zKyF`jO5<|!n>LKfaDtbtNjl)D)1CveXxn@E9cGNWXU685saUPlLor{Ro|7ASbR5Sj zM3nvVa|69Ja%sUkYxk8^`PW=8+-gEU`W8xdIi-B^Xib-nYTCCk2qr*YVHyWuC$dYISQnw> z0=RaFM~{}@4wi;YxcPm+kKe(dw;`K%KgFBNo8HLU^5(y}-GAdm&Mc*Sm=qk^I9S1< z6Zr9M~9EU0K)AENd#Tg9~0ZDs9c8WtW5Jkp*#ylZ?@=0lyeO z8cEs!b72e^`i+R!2P*n4&~pL0=|cY?s(2xAKs-nTi8tI>11-Qj0#_%yoPe@JH`;zX zCXerzLSbfe#B}yodwOKt8I_JK!%{ zW*?rjFYj|NYpb0}pTP8$7c;}P^}g`0yrCaGsHeyAU-0v|A{@eRSo79}rt#CW9}cBF zuV^#?E^$4gaXkd{+J&idTyQ^LU)ixA+I(Licc^%t;TIF5J~(T%c<+&7HF%%iqdNto zU-U-bK83yjr}%fz{7N|#Fce2h-6=(@*kw}pNgYjgkn7*H_k@iOn2YV_1|Rm zz9^@-f^Q@7J+iqT-Uv(QilsU^B9Cv-(kb)Y35@&V>r@ z&^(`G_G5_dvgdH4g9sZjKSfpZUg{6wjW9Vr( z!Y0jSj`$(Qxivp*zQ1Y?<(!pZ)P+O3aCK$n>XMbd!ocadg5&98l9uLdF<;CiN9HY{ ziF1VPbN{pX7^_C}iHV8f5fOm^`3EUMKtKcq1@Q&ohFwoq-!|6C5v#N_zGpek9Aw{b zaXy!P``m*IIpJz2o}4997Nt#`rkhtmv}9*XYeqkWHy$x-HXDXCAIq?Gwfk+N#?S!+ z9z~!_X;AiSK&?;Vac|IN@nwp&q>yHqSkA|IbLmZO+G_kcpRw9tU5^3oYrg?@3)cI4 zSazEDoGHOe&zB$+7_#z2U8lz>kPk7KqtO&>C|kv$yaTDBm~sr3cN(HdjJNd6%?s7@ zxkx(auk5&$=^*9mE>TkjNqJGijQ~?xq|lU$suWICg*rhTZlj;3qBeQh_-a9~IDWWP zuMuzuz_2MS@Q-MFgWn!Sd`Vl9RxhuoC57B+?9 zoFYVnIVGw-y~ZS>lcK03L!?-tdzRUlz8*7TB{8Q4!$KdY-W;Sg+*plmbJBDiJw;-x zR*g@dmand1_|*D%E6x$wFnq|)=f#@D5nYJfbR3zc&uPcT!cT(6B|YIp@1n6XmEm}) zyt_7T0W$NE-G~hfRd%AUyik{^vEN?3UrBOU_+-9~k!i)!Q`w z8gN~iN_mPiHnT!o+wohwgLF-KtjQ9=bLvr<%~Kts4G_krbn=qkayGd23ha#7BB#BT zeb`k=8vj`dxZJJr@8QKvRR7>il19TeY#WR`+m4Bny|1kLw&u&l;2l|9tU|^MGv6U? z$1ch0ek@g!WI!dqr$1FF&80$#h^!u6^l~ewr}*gwRPR}-W?n5(35cj}`|eiRv*%>| zG2z-M^gL?T3eQ5htvaPlQ?nZK0kij0#`JvdKb^Dc;t18;{=wlPz$pUx zeRFK|*(>IF1hv;fiwX-8r<}ly;+a4r-T7}h9$Rq0e)4Fx0QB@YOfhqP%!cTLG-vtH zVj!Q9^z>_O1I|&J{0R|K)FDeItPSKi8hbE&Qp$lA*ee*+4b1($Um$$(}=gXK`- zcIOrK{Fuiye9t$sbYm-!JTnK1CYM@3edT;k+H@DRlB?I+JK>2nISsGT5D7EZy*^7v zXvO@w;FyWo0T5nz335xM7F8$=>}ijw;!^^WcHEArW5MvmyV;n!HCRoVN zYM2&&QfXZ#tR$Q&ISlKSv!}rnv-VDc_NPviE8}0{dMv>PV7K4aRTHrKO(b*JR!5P= zsND-_q|K3h_Qldnine)k_F6Q2rmr|GUdv9@dt~3rf*%l4E1S*>b>|Xu5ApnDUZcP| zwRD0uh@rpMt5S|#1seMz>(MLi-H2B2x{RF|{Qf2geTr<<`+=DO6P3{);6ie-ZdW2? zWz8~Kw{SZjn1=D1Oe?|Q_Ls498Gx_OAFmF49~gwuEFcCZaY?oY#r-dPAB5 zja*_0sDhu8zdgWb6@#zMET}o*^8Y&kj2eE=GZ?bZa?2D z+L5KL2ZRk2MC?$;m$``yd_d@;n$roI*Yv6vcgln-bk)vRJ(avTm_R6E({>H(UXSk# z5hU5@!lO!;!OVW=0DL;GJ%GA2k$y357UO?j7l0jka0p6JqvIN`o$p! z2LseY>L2R&Onf8V`;PbmaAOBF(F>0FVzR4=@B)9c2jW9}BL)-;6is}?b`uZMjr`IK zqT**OyUTQg4e`OV%Zd0xvs(bc1?WZPe+|Zy-An36iugiwqXZ-ioFlR8>31!?`|h`s z(~FzS^D)wbIAhD_0AdSqy||^x^xpN-{3OlwJZKOX;=Ywe(FN_8{WdeVa&lcTFyIvZ z6_x4~y^Zk+dr0V&bAXBQ^^J0{g4Pqo9F&l!;Kkc-2zB5L9rLtR{YAEu_>vGX;)ph* z#}#dld>|e*(s3ViZyj6%?8X%!-|L2U02C5IA8P-^k)^(#-{4@9xHu=>UMt=vMkC}v zpCB2p6>~Tw=EIc0i!_ECei$o!H$vEkGWIBDBXlQ0R3lQ4IA%lCLa-KlNSCle_*y6S zWrU=9qj~EvEVJqI@X~XlH&fly8p0fRzEQe*PPd+~0Fg&FtZiuZcWf7QZw#p}1|3sUwC!tf1h^hKHe#0r0lOaGg8;b2Q; z8+OOr?Hc{zOF8W4c%_UpPK^XUFHR|W}fXg0TS6$^Z@4s))GlM9< zVtyPEP=B`P|B=P;?}G?MC;cB+%m0s}@2sNfx*!6N^Ba#OC^3CySwwr}0xIrEV4EwX(|A#N}yY zZ4LeV^BULp_Z;LW-Yl){jz$HqNx6?TtC^Jvj){e4TCh}A+Y02l533am%5!=K;NfL1 z&Px`+xOGp1+6JseN7l9u>Al@VjcY)#)cNCn_KpTLAugOn#q%eI)kej@t7ex6b^t4X z2XGC1<+g@SyR#?zyPaOFC^fyA2{yB9O06g$c6+UK~xYHh}{$irdo60F5;_p4ZLVlyE}^<~>| zyS@#Y;rAZ8xV35m(gwAr@^(1^9e5GWCQK zwG?xDhaW$U@S`8CN&QI}E+$^YLLI+&qmZ^el4T(_su|6)L0*FS>UeLcdPrLFnFUfu z65mL!D>Era$ib~=XBL`x{$3mLB-lztos`OWd7)c++g`Ht)NiPW5-!K3gle=Hz6L?w z@*>-?l>IW1ZLB!N6UZ76!VGNK00Ly;0zczoLrl}ap>g!=48Alqc_pDWl}xcR46AJA z-gr;Ta{O8M7NuGt_1h3ky2pfKx;Mv66ZqwPf-1N*X?v7FIj!Tu2z>Qqgu78qRf^vb z+D?T8EF%suPAy_ADbyB%Smyj2P zUu^E)MYAo6$viDdo_e?Auo*>lo2OIAzGuUkB!WulTY)_fjC7P5~l=-tJ14 z*rciO#*N`PLN3^Tv0VYpZ!JipleRng31?=4HDCl$#Xqr40vG4bMhOM>573y5HG*~S zPBGPPDk&JXh5Vl5N=!--T2Wb5menBG@N!QO(#XiQPuOi)g2mLP zJZY2@0ag+4#9nNwh|+@m_`E z5yls}_Nntsi^S>8B#v=9Nn5>K6o^I)BRP44PVwdy5r@CcVZt zttla1F=#w4EIdv~tu5HxP+=Ex=B~m#o?kp(5RlphHw6V^;Tt`<9eBohNSnC(u+&Kr zE{}*-dM$97S4b*h?*htzThHdNHZ{HNUm0?M1%@;vgbKs%iRs|fPu@_dW{|IIoSLV% zfla;-m8=~=Vl+i-lWg3x9T*ude+;Nyv2qgP$^CxQ-R|F;qH9MF_pL=50{J&6Qj?+BtB!ix}44hT-jP?`{SR8l+t#U} z16b79WRPwsuh;|EoP(C}ThHEG&(SsB{R>>jCtdq)g6 z503LX?a6%zLEGw8Q0^8C6bC_>Ea+1ltgG~X64TUx>nPvA>4n<-e#Q9DF#8W46hVm} z=wRsQ`XAOq|5eqE-3*QG{(%R%QVSN0THi1=fcnabY2<;=esned&7`^#8i&qZOr5lPNBcEk8R86U zH7&lEok&F70~?A6aoJhW4#C;X(GM~xHF$082JqTIf}8JdT+UqPHY2NtiTEPQ^9=zb zhvha&8b#COWt35BzeM1`IFT0UrwlB=M%v*Z+6$FoQEFdzBq2ZR0W|3?<)!={Vg7xy z?LWvsGyG9fBY*(_F#WHP-hVHPoW6sj@jsGS|6^^E6|H3v)scK?su~yNC5Kw7D%mO+ zs;EJYR>mi)8JwI~C6j<7C!Cwj{vpKPmity>B zkGCDK+_Ud99cMmYPPf1T6iewoKF^jkzJlAw9!>k#6-t!7HK$73x2(`fo}o9!SuUyh zeMJBKq#(h%wq`8327OIhvuZngWMov2mR5;0k7=q89JiJnUpr(OWPRZKbXcb!t|G=r zRvwPVN=L;?%aqa<=t0*xcU+zr%+Y}kpdHOzV)QdPbeL?-ZK=p`tq4n=jdA~tp+spN zkqoW=)el{kNC&FmL)4kGcc)?Qs&@qM9Ll8q%b>hz zq{zd#NkccS1|{`SA9p~{?qy`%;>bTX2^>GfC-luo6MBytVQlufkZ)RjfT2?toyOwm zNV|K)k)#Eq&3T5ta#+eD5af}=O+n0>OiYg~M6s1GqESZ=-JU$;7Y!v_s6SxDCqF+{ zpo42N{yhA4Kn-zaQDJ(R=gFUWvZ1@@CeILkKeUwq20@MTN%+T$YMc;!YG*Ctfg)S) z;AVXr2+{yeo^ag|lmRk@!M&2t%)4N#BQ2zsvc%4%d~xH^r?Vk?)i@&&eiXw5t`WOW zw=U}$I>#a6+fFl0PlW}LfzzoTE_!hug9KDkPG_ou0M0)V`Ut#=stkl%9i&CB=+zcS ziI1C!9>wJHCWYi$sjP#U7(-M8ue7CSF^1n`tkS;$rDdbuy60h(?QmHQUtk;zAXJhd zB1uW9#)2XtZNv`AQqYhHsMupJkxr8tGV|`VV>P$IST~G9JFXljLWn6Y{}$VoD?p*a zs00mvB30u>0M_GmBg+>u9?QHnx00O3w&}0HopOSy7$BwYDE()&eS zi3=VX2g_6e(QEIHLf}6GYgLc01xbGBA1yy{-TyFZ{jXa34-Zk=|INSmA7*a<3LPp^ zmQ?(4Mfwr}LJ6YlAD$ivN1Rwq;WOxyMb}3lsx46a1q~ufqFg;^5rm@BP`-r>kqntU z-XkW{_L^A^vcX=+_8K=nGa5TeUT8{8JRGvR8oK5F@UXJAp#TyK&Jddb<3u!&4m>A-5P6kNB*VqxQy-%qVd zl>gXd6upvI9BV%yrhN>S<*Z=+DKSuQW~j(UlQ%D7;pAoYFz@!0A@t)Umat_9Z9mZn zGQhUBvLdaY_SXK`OTXD}vwW7qLz~QXu&UcmFhMQpo<-O<+ZqBJa{0lrbJ#v~l+L58 zff|xJjq69my{FWQueGI1J5Ou5Vxg6?@h1_yw2Y2w%M536i(0jZy0eIym6Xz@Sw%*+ z2%TVNV4EM-> z(C@$FrGL%94y`krODtpk z_~u!!sfdN%;!jf)k`1itN64HvZbRl*Rq2Q2Wn9R5W(!thlOFi6uy8HR-xr_%{sPs4 z-s3WW9(kHzf=+A}7a!x^&}VCsJfv zhF!C0ckC3g?l`t0VQf#a$SyQtKBXZhvFHXJ(pHJW$DrJZl&jrd85hbH_C@OVYaBS! zOR7?NNHE>@Fem;QdZd%=l-m1!F;cKd6;Y5~R0M_3$uO zO-oFWqXHzUrTq#r(N#`zh;c`;mSs6YhUDM$LP%GTu7s?`q!V|bNa)gRVNUEuoL+m7 zTB!=M04898fuVR^x|d(JpF)%&GbcO3hH>4R! z18v%wwA0)}*y$rV1|l%Bxr~#<*}EJA&uAqOO*`6~R46WV+xAxkZI|R`IQ1a{|j$M{(UkqXiac^nK}k<5iQ>Mi1?YxGJ<2`rvxHAi0W z`+}|!SDUr)*Vmp>1XM|7 zrnC}`mE~4r-Q%$IV{DQjNMH7(9gWSUbTJiw&>dl*IAwAabg_q{Jtw9(tg&MJRpb1I zV;Zl?(*alh=}ENLr% zqkySMJ(;6@kdw(FQntVVPE(2s7m3rc&`BqPe7&wTt3t{|*{2+pSMJwMJ1*YL1`e4& zr+^iPWcHtcjHa-ldcU4Nm~Md7C~i7(1Ef<=1J7AO<*4I=^xThg-N&N}e_`e&8F}cH z?4GruP1Ge=73*mqV-YNwZ>eudVx1ydU3Uu9ko#)Y8qKY~tm=75y1QSq06auh>sq9}uzA4!5wa_ZCUBN6B&g$O6W1~MN|Ld?k?YYj0 zF4HE(@cUE}M)OsQ#Ft=R$7{ndOJev(=b-}teVkY(W;#E;;Gl_F9ihY^ z$yF1YaHAFGc47M#g;{nat>)$xB=us33;)7CC}^#yoH+9}&ROvQLW+NvMbd^{2VSqU zFv<%C#QUYG<2g<8D0tI@nUW%l)0#;bt1cHv~Hz>uAk;VusU zfz}vreEj=VBYSR2*GhvGllAeGQznpR@kp=N2eiM=Chnkj?&m~8vnlEDB|We`Q4-&% zUS>4!mVW&aCfY3GPAFo)x|GKUUT{G}jVCxOUFpc}fe|sq;%`ZAR_w+}Az7Y8Wn0_@ z#gh0rY%Mhw_t3Nn%u)U5c`H_gh{i4wU4-##4QsR#ry1a+-iTxdSyanp{{@@}!RniA zq0lr*q%MU8x~}okm5t(>tMr8gZzi!q(^!M%duP)OOc=O>-^nj3pKRo6r{>&MQw}ob ze{faPI=kkae20a7plwxWN46U1$Vt>svn+}vxb{?%?G;EYcg17x8mg_KkY>EVwhLS; z20b4OJU!lKYUBW}QPI+ym&-WOHpxBSkC}5)cLQ~9&x>#1+$nKQUhIkpnXMWS&|bn? zyoRAPL3#B4qDxU?V3iUiVb@??@(S6PZ(ppq7p#a>n?}9oFC$;DLpWAkkMG%~ zC8zXZ3t$>1k#zg7$p@|(^NQzz+`_q;#m7u|5)rkSgE=+SNc&Z9mLxs^zv6&Q=7C=f zn_0FK+bhA-3VZ{Eh`U30jn^a`^*vf$pJD3V5bkGgj@z%#FEAa^N%lnS3f%?)zUI&K zLS;%GWJ-SBt+> zZ0i}xoV0PKGRk_UaSnSn0X5TT{6=NRBi=^CmL{zPhq{o%mQ^AicJR~>e6HWlfoIui9zdo& zNiL)2@sws5s73n7uTFWchC#l#;VC&lwJ>0eW!trxduF3I@+VBHs(qUZgSk*X-AS~8 zbcuR&ejmF&nR`)+Na+V*%UNi)N|L@HaUh&xl8eHdN)XnuI?iS!5$N_CEwD<-P)9YI zc&HfmvI1N~NxHbY22v-O&u>Jf8uP)oAJ3)|TIIlMT4RtMzLTOiU-#p5yAvw9>4k7_(^kY(G# zeoNKi!>#%P5+_f9?>8u3m_pQd@f`W3?)oQ^tsocj$O;DxW200Le{F4AGLIZ|#IC&^sx6XAnO z&wY_mrW$@_=>dCg_}(2gUi=pdjiOKK(I@E4{;|{7+~{w}kJA_{Ep$94T=o>m>~0y2 z07wRnAF(|}Ke3XuAlh)5d$OCIKCuj~T}%rV^er6@zPpWOw>97|_PxJP1zxyVu5U2{ zcS}fl&~Gn5KE+52z@}}H$WGFu8v8uB0~=6m8>Y&q*p6jNL1j)k*O^O#m=QQ0EB!bg z4n9Gyv{5(N>fW9DoBX^jwSiAF7+09XRkz*2c#S7064GNH)o<#%%OSc3{_*QKZtOq3 zhbehW=H=r!I^`^}O0KaDs0PBh5{g%gITCKzrDY7Z>kU)~)&~L9qM|jdk9%lMGfm?< zYd|b3`^%s^gAYUVPG5Cq@9be3g&r?JUm?N} z+Fj#5bf&u_S`gG*iOPvS-E)=i1;ZVSh$gldP87ng@8{#;ZXW&FXMJ-$XiL&1g{n$o z8*=S@T^l=bzz+-mRY$fwa3UUg5V7$WDk? zY&yeTFJN=sfjZlsSI5%5hojraPsawX8meTw$x-djQ~LHdRpB&T?87lgXg0J?lQ2<9 zwj)oeAR;$41ur_4kzJR(NQOughFQ{tFV`p<@4h6xDed0u(+|>i7PVTlA~kGda1iRl z$HVfS7?I4+F}uv*-`Be%1y(Fsgap+Y9U71}Jgb}guj&$poL(_W*0-?|?o^wc1jsQ| z>Q$04O6QKjgsSHa%kh?~Z@O{k*ygjQtMQ|tZDk;$Gtu4}Gt0-VyhmL@|GJ>5>~*ZN`zbjq}eCojvS_qgNx6M+8TgH@uYC1rC~4LQl)1*fCDkPn`2pC4}G> zhkDmg4vX;}IsMAgF`J%X6a5vR!f7+7%N^*?5*@x2mxMG^*K_-d=5VqeGa)(XaEDuD zxP~jw=4|F0&je=(F){WalrW<%+DjPEV7PZ2?LZ1Tnw)=ORdM>9=W{t*9~+io>Aqxh zA;n{y0-@Uzp&OCb=?8y_G4?XBMNoO5#{plY2-c#f#O_*KAz%MJ4n@z*G0gKtk3Gn6 z1Mi;k_yo(|<$lwK?jtqko~T&S_(}yAYhU1lAf_o8gzWbGPHyLv@coY%>@E?*!_=S2 z)Y#8tiu8XSC;!)EO5ulA#qaE7_OD4)vhtQ9rZUpEHUh#gNeI9qPz!4bO97z02?24< z2~|*N+z>hF(gzbqd`Z?dCs)Ce12t?@tR3$K@bi~`wguEIj6U!ZS(jnaZ%l8w8SOAR zeQ2JGEAHd%``aG|)z#PAu`DkzT0d}zEDpCsj2HZ*-D5VHQD6bTGa(vGxkz{E>E?2j zfb8}tLx;C+JQ=JI^r33MN&&Z0j5@q5R=;G#n`<;?BAEx;uvVhO=$0KPc|RLt?hRy4QTZHv=4WU^@x&49fPJ3!nqS5x5)kLDfUe56+5B5%ko$i-zJF z(a9HDsy(PSVBaV^f9bPOSq!1lsPoo!+|W4O@GUVkSWMLF%r(yYFVc70Y4APdN9^(< zTxq?a^DM|mRUfOdjxr>U{q-*-OC{7vYzcq;IdF8m z=|6$HP-_@kaSvOi%Vx-a?JIE8EX%!! z1xPlRA+wx1;l6o?>G_Si_r;?Mf<$4_X+dC%qVPamC_}UEI!Dowr4u)7j2tcMEBBG@ z^DynVL%p=W!k@+oacEw0$VH9;U$H*cu+HciQcHF zsiuD3L@d~;%*8@dsTLrAm{a3>x&!_+`p1zPNY+t_`7G4C%x_4-qWLVr%S{7EFp z{><4nV~BN|bc)h;{kh7kjQQ*8lq-faC_3MU&NDGZK?ls~`DY$+{#G;4m-dBt+}SU} zX3A;Ml#j zJ{?x_ff;ylF5!0?gLnq8XS*t}nb|+t@1VLu6Ro$zJlDmSV!MB7hFxz?eb?FIN6(&~ z|Ga`hZJjzXNhiG9pgT^#wiI=8sfuv4cZWV}so5`X;*t?|^jz@FG9{jG(mXIkP;#1a zN%emY=8YA*f^%i3^!1!5xVX!o3lB;r`tjC&aN1L_w@cI;wI;T|A*BBn1vpSz6>c;L zM(dH)@)ff34RL&dynIQ~;u&!#s6MQ{E{5#W?~KPdh4wlu0i4SAxZ4R(d9zul&Tz6D zt@b~+{dcI0s`|^V?FTAz`l)UIyZY_lYui5xoRYrdztUD!tQ`@Rk$i0CS&x%*|Cq7e#HkXzQj@44Do?jZIeU zjzyRBfRE~0kY^C-E4vz_i(iH_Q0v+4wNuoxNJ}ymi+{5c&>c1z##!6=)mk=VcVMX^ zvEKV1!;-O%($>xy9UIOXn9u}GmLRkQH(9Csa_8ROs>!JocbafILRRLcTt?>4jkcgZ zvMBGGhP%3uM9}IxymHP_S~TAz3{}y5APu1t1=$qD7z^Kppi@Jt*faVez=qLjXdOFF zIZPC7)%?69x=C=7CBA&qdUh~%99t%HY zGqOKC4mqe*-E_3w{EtE*Y$@2nE0OGj_n^bW2BOU}UY)^+4Z=al*pP>g&`CV(KS4-J zk(?#^%xUd&CSE>Ng!y4@C;ZaLcIos)Hp)M0f@DUKgRXhp(HaN1EFfhLq6&NX8@Bh> zepmg}Q*YBHSLqJnqueJftHn{t!ecP+xiLsb^UnjfV^7b$G18)FJNr9& zf@^V4xl!8HRRnf8L8KpYkHPaGJZOUAR@8O%?pF9!-g5ejaDD<%iz7YmIk#Qe#QNxw*VvwhM1|QBH5b;$ai>L?ZbRtWBzER{O@|F(D?XVl_lxGjh z=|bTQ-Hs0qeS$LV9e#f2W6t%T1>kD$NKsgI_FS%PP?6VqX?Ui*QPvi;y|Oi9E&>{H zMVh}jmq*8|M04)7t&DP;rV{Q#RrI)OYon4v7^PaIZGB1z+6`fm+g5hB!PDXQxkInA>ht1Hq!uV=QQHrI`w%Lg^gde9ip#goKa6w=T#o8G@E=OqT;*i%^$DaIQA zusLa?%*~kv4yS={KtCC3<$!B$(_1`OSaNgsb?$3jV{gI#kk7S1b1|RWN~T1!Ibcw%icPQ(+3B2~x5+i^d`L zC7cXG%`>KX8&`?o;bP30&ah#e9XBU6JL$Ab>3}SsbV&VhWRmrE4FWT5oyPUlE6d-% z{O{C?AO>(y#d58W-=Sgx-l1+Y>9F6qB7%AAPgt1m7xFgy09U|>Nnj5l7Ezppz4?zO zab-|OqkutyNPSz`<%s0It;KWmjdUFt1+pLo@pjxee2L_g87whNqVkqOrZIpi283>B zbHb3K6-=&nE@y$O*#56!T@dTuBiA^^bc&v}6O|9)fs z`IcmbKy>)F>#!B)$x9H)y_Ho#=HZ_eL-76dw)q;L2)lEAn2cq z0w>hJlozHu;-v(4rXe-5pNmrQ1asC6T(>7zS?QC55_PI!x*G(IIp1 z&!UmK*<;IwHaN)7jRCAGwOFOqWnp}IR^MSYDD{**YPVQo3kl*}Y#gWCz?%yW%={kc zEw5`;N&=4ox$JaMWzWWAM$D+#=X05>g1FcZ%&h(S?yS2h(I%CR-kj1xywe_1X=FG) z^GC1UqxiC-Dru%s4C=ig-mixQp<*rIITwf8b~%8bz99K89eW9)nmJA)wfK+{XJTo! z-CYwmeB`;l{vOEr>Ae&(BYk454mH?iM4qt2U?Z3H5Z{a5p`Xq|-Uv9MkKn1AyC;!@ z9$HF!g!yT*cvWK@`AV)S!y}7LNcH6@H}|a>9@i|usd$l9W7ODhi^wMMw++H{-Dk#I z8^m03JKKYpZEEkWs;;f=?!VR8SzT(DiA`8`C+piQ^XuCuLz^m4=-(D;keurr?~C2d z)7#5eS<#o_!e5{ZA1TYy(VXj^Fag`mG0WB1UEz-(5XGPo1$FHebyY1@jt%(%t;<(e z-P6@FoiuT(!t?X(4OMN-W8e|k)PwGd6Pz9z9q%3<9nBLFjE+S`buD!@B~1;&DiMDo zimRDy&8@ddB=6HuTpp}c3enHa{XzVpf(SZz0+QY9p2B3ING_prD{W>1lI*l%uNJ&K zDoOtEDM?#EVWptL!!-p1+XqRKF=~}J*mr2PLX^m1)LWWva$=vr1f&wVaWa|F&G4<- zalu#if&Ahqp03P+?L!A8C1$chY7IdEg#Ohe3uh^Z1g1}}MpiBi>`_U1Aqc6dc^eO- z-L}B5s;G{mUOK?fIvahr986dYH;c7s@T)PyFa5#jTJMLgw2Zr0wK$-3|9eQo96S-Z zFg;>a+s^)tjZkU`c>#tj-NW3K=dzGn%F)n6OPvaSo^YTytj)mk$OfD`ugD>QN3M{) zQM4aeWghP?7X@p%<7tl!&o)P5ZWj;t^>R^`&e;1p_bLEd6$|Kz>Un4X&V0{~=;~}m zdz6!2)k_ZQK+rW9Xphf~Er~$OyuiP5NyuMtvkRD31rk8zonS5wg%x(x$vZ{y+PtT6 zpGirk#97W_!9%@KbfYoW}x2+B^kK1NAJUGNFy8E296G# z>qoqZkoc-#>97d-X8ft#40qDSPshq1aH*fi{uS;7Z8K*O7$!)$Wn9u>T*cP4j0FLv zFUkbM_ee^l8y)2B=g4NK_FVDeqO66mo17Yj?S$(+FY`SA3A-+oar6Pl=OdDvPXq%o zjcbt3m^;GR$hZ0j!A`YVwg6;eX4drb!QA6dnU}~rGaBi4W){|idoeSzI-AKDW|2-h1gu4#iu-#+V6%J&wyo$aUGQ8s_F{A;^gZEjc43Lp zttG4l)BLFXE(Zcif(NzUubmj&h$h_Y1HOH9 za`#vx8!$0~Z?zCW$lNmiWH+(ss&$Fs15gA)CA7bY$|}+#Si0aB3Uzh(%Q(06XhDXC zW_kujhH8~Yi^Wp8#z&RSmQlgA(Pa;GuGJhIvuHo~P%NokIsYd-L2k1-QT50liTa~b zZfRH!VcLyTqAnmKPy@~;y(6R8kTR+Z)pIp>#15Cihf+$E zSZHFGGjL!YY|EZV?dVhVItF#V&^!Yo?R!5`j>BDtyELh28&<@^`9=rU$H~dN#r0^llhg=qd zsdHuIwG(Cf56ZWAkQZG-aN+*`PSe%U0O*@)G14d>r9n3$1l&q0^EX#&8yrTwB%jf-=d85jq|+t;Q;s1KE6ui3_S#v?C+*;sGMDb z-;h%!Mmm(AoM%!>aKf->XGp4*G2!IkpWvUSJfBft6a2izJyRtFZ*39^6w0OW`t2?( zDCUV=E-BLxi@te~Csa>Hw7J*w-w>&~#1kp;Fmp^WV(o2suf`G#VpL@$N31R$vD+iu z77>nKt@q;$p$)=hwhfYWcYBG>)u?ZB=&_9zD&j4N~oq5SBHOynhojGBJv)5w&c z5<%Q=aSdcL3vUNRp-cVx?^bMHjX1nxJt{A{te9Ww8D~Tp%>7`G)|MU? zRZ`YzY4=w04>X^&A2Y3XYs>Ee<@OZ0TZ#=IztXefl56T6$uHAVC!mVvO_`^VJ-r^L zI#B>WFlwIoUV2%) ziR9rn^o-$&Nw7OJCx)0Pqn67s!J>nr?$rNakV=*Z{`6jXE|^11+7^z%O%xvrh6CLv zqwq{p*P3HX^)|3y{26?qCp#Sl3%oN|QPy@^u2yuoG}x zULVZ3YH9t>aKlN!c^;3_DeGy)vBTPc^jGAV81UBIilQ^(Nq}H&nCAyc8kJK?YKr&x zVUN4=FALAh9 z($7SUP9zdz4J+aWUKzz%N&Mr^i+^wqqBJ1LWpKRlTKfk@C!MoYLYQN0^67(b1uZ&~ z`kG(p`2bA5LwJj%a5}Q2K~M`v?Xk+!XfWKN@dPf12e;e5qmo4iLf(!=35XNyEPi7G=EMC`iMwl{^Y{KVJRP3 z0%+#BIaG835ogmrN0imZGLpZRA50b`xXk+$j5XzwW)Kw@rSe!^(mVh~cJ@+18e6?Jy!f>v zIbM*kQ+B=3MFqKqiy%i_$5Si|?RkDzFk8FKRqV1_u$yP=SRq0;S4GNmvXt_0}=B8-MW zjd`e(Z1-kuGE-=$$AmSHFozdkFvbfUG_o;j06v?P;xSYWF2>MQ^*b31wFF&Wr^yYq zB%07as{7oehux@$aVOAf2432u?6HSeOry^6Yw!&_aSmY652AB>{B4x3quEg76}y?` zXHYDZXQUg^9}FW*poXn$0s9c#@3bLRhUqbGfGPDe^J}_NIS~RJz0;C zJ)^O2O=rx^Zeua@NM&WW$arjfWJ%H0M@!UNur9+qP}nwq0>jv6G5z+qP|M@?8DST+{twrhmjb9-Zp#w_+auy2_6Yg^fqQEf+qs4iYQLU?oJH6T*FNA;SWc~y9x zh*fg`YNg4}blCv*W^FxUDs}C`MmLR~9@rrm&|O8}NX=KAy-&xT+h5%!<&g6oI0~#y zh5~@-!s&(|FvCqbg^8dNR~mL{XsAF`(CZMlN!dHzQSMH`<%91lP_@RF~{c{dYroQZpb+p?pUJ}ZSr5qH715- zUUC)N!>Q3zb}KniBzk>V2v{=WHQPsC*P76y_42jvh!Q{Uh~x+K zz`j!VYbJd9Ub)D!?6U2@wxEvJ$rJ^%2^+Mn!QMN?vXYVtj8n-YPMS)AS|~t~vLPo4 zM})>?M(hG*M7{{0shBw>NZh%vbe&Vb6#t1H0zN0JlgN|;d#-?Kq_f4`*OR|m`bsLz zcN{t)_?cl|IHiHMwyAbLLHwWRB`AaAA$W`)?95KOoy^n3pKLP=y_=6=KjnU#Ku#24 zKZ6l#C9ta@M1D)%Je02V_|OozfXNal9=CNy4WFj1b4UH^(#y@-vrD>TyL$PFYX{14 zyj=h?I%#tc+zO*9LQIbez6rC=wQ|$JobIoR!?e%~w5bOKk9bGg z`rXd$fD|P~AtjI7`#R*InqnRAo#xa#K;g(D=w;8~UsKbOc&0byb|kZjj<1N2itvgZ zdQapioAOogPGbysH?CDaEKK_$aSQ?* zID40NJ+N@bp$xhxaV~2`Z7nNgY;>{{6)Q}`(bjYuJ)W;vG(0E4ggR4!tJs?Hm#hZ$ zSZ5nMhE}Hg|F9TcE{g|t2M6UUSlpOVMBlq`FiU36@4sPt21$0{Bq{5%3}MC2aJvz* zVv3a^IH(NBh-@(SW=;;%MW95qIc*%_99M~K@D8mzOyw|aMc^prO$Ahy#0{@<4K??e z`xsrEi`$oS_JfeFfmM2L>|?X{6CiuA#m-?Sr$-|^qM-yH+wgA#;I9RFGk3U*;h8&? zE>~L)AURT7c&0f0uU---qmN{V zL5f-_(|E|iardXO^X*emShjRcG>v>U*{vOeRJ|`>xk=c4p8ls`^gR?Y|UJ}>UbtNCPbAx^gvYMjhN^cR}7p0 zE4N|GUu?>AnJUWU_oRxP07Bpl#C;%mT|^@Hf$Hpo_n*iGO278M4Qp{+oKcBR&9*BP z*^r6yfS}pcvcPyB9Sk!E+m=H808+UlI@ld9i_HCN>5GOAdUUMh)61xGq#PI)5GN;h zL(SFzdfOjiITJ~}kToW_OqY|$@BjIm#m{Atconh#e5d?0cFbOsBK=r5m_%BFsb3X+ zRbL~%4|B2{3n$!Ib`u?^yxoS9rrgTPJ zNohM!hm-{(v`rbK`tPUi;@CtXztHsSx#!z3Hr<{m_ul{M6Ilcni!uDU#@|2z0a5&a zuioVB|KHA#N!9KD+~dD!13>!(fxiMJ6ToK>kkBk)lJPZxn=Ja_k*#H_1~VtY&{*5K z+ObRl!?F88`?*ZfvNO>KG5b6BnJwKS~d`sn;ux=cBak z+%L!-Ok4)<&ld-Wwa-rTX%~BOC+BD`?G)JzLRr zq_tSBn%0PPINKJ&>{>P^7F#oCy!}vCo9G(unWZVAKbwYw2aL2Y2w zz8I1r*Dwre>->O&cGryqJcs8hEC)+rrvG)&xO}xX;JdoWWT93TuFF$7D_eqCT|&A@xNE6CvRYvE;ZUkC$!^BtPtANgE<(0p^ab#O>^~fy zR?L(zNbAfftjScu?B18g^yk7Hh+N z;JwG>zdQR1+egJNH)-1m0KDboSD%TefjgM)_yus?{F?75Bikpp0^W z9eBdld!wZ$nr3{2>}WH}iliXI-9{@$uTKr{yxJPXl`J2283kL8zfBET!vk zq+TB3g@S4jy;6Q=I$X-4aDIEB(7>5MIBQO22?(21B>f17v3U03aO;T3+gn<12Zty{ z&SK#*=`;=WSEnGs^IpCmJG3F3AIMck>1VWO2s0nPMphicl3ZzmvxHKe97!`+OV=`<{+EWg) z4t7`UVZGj{SUO&};<@Np-j_V4uV3Gh`$EHwa)B!OBn7eXt6rBbOP5+!myP%LNp@Wj zH=M2*ygoPjK5qr?30BX+Dv{GejgH(n%hvVfKR9JWWwb^j;4KFDaiQ{F*|QZ~LSE)* zF>StBr(;!%4_Bl_k5*u8HZv5+$T`FqXP*jvI!@Au*O6hTRU#RAS{r&>I}(05Kt>a2 z*ILDrR-cCIxA1>0>ih?$tgN{*v{YQ`ElbaZt5ltYf6Gup(hIx2;;O;fsw^z-RnKsP z;lR#|E%L0hE+9R>{BD*EwO>?`!fe0F&FZ-F>_dtTMCgA-&ZdH7dbn4#2!LgkIjE#A zDWs1kz8i3`?kq%$$-p1piskeZrwQlLL3S!=CJN8X3~&(4d+(s^{w8=oB>(``mz}weIU6zkpz_grS;+{qM zsnu0D%_w2p>ktVJOruCGFVNcRSiXs`A7kxTmg1P;qw(z}B1&n6)E!)<*X`v9%}JzV zbvLnJk(s9p76=tzb(Owi8Ne__60_Nu{O&A?eMT7uJGBTGun2@PAP$~~HOu|wMbVwz zOa(1kcHuS5Wfwvul`hB`P0V<(p2}ebNWo-+DYw*)lRy)jrPB zKachL)NW1{DCJHhU0@W+sExPo9V1XD8!*fJJxSZjpddNQbiX|~j=9?2+z{D*YIjRpt=Wl_6BPKesU+)DU3XJ(Lv z74JogVXwC6a|t6I8phaAwY~N8CL$U!(jfH>DIRfpEbRNczru{T3;>SMHu9|ub3hI$ z5g#H+eE)_?a+-fkg?2xY2K{zs9WMus^ z9krCK9H&rF+#U6NaOjo0yT?bLr=OWW{-j64Hvq}r)c1lQLMfk0KNB)>o~mA!F0yNV z^VeIvV7za=PReRyxA^AdwCIV}y=&1@i8!(TG&+{x5NqSa`(XW%<6$>s4UFc5TU_!hPG&Y?l%Z;#N00P)C{GH zAHlxB8lTiBB-JM}XO|#JdbyE4$qP>MfovhhJ#V4v|gTuzcPDSKyC_$B^8~fo0A(6>w)-8yg*nQU8Wl z#Frezz&Asot3Dx}KO?#1_j@ii7+Gk%CkR;DR!P zFOSD(t6K!+kj5}C>Et>M`xJ;2ocqckJSwpeBTXPrM|@Q&Vd1B_53Jb=ecJvXmrVkP zTiAymK~V7j8nu}I3$?0LwCu1{5WZrQ+>MrHvg9?_ki<8FIb$zvG6b_=0tO_Mf`sI? zRU+g0htG}7k~%G>Ie`f%2d+m0+3XiuvL4 ztcyOd=+0uh$AxBdC$;DwY)~a8Wuu|iqdymm)Jswk4nd~s4aalQP1-bMp<iJ>f!Z0Ta?C{7w7A3Z9`;5>^p4Sg<frBIb0{F?9Q z#+pNaAlDvI1Gih&zu1qgef(?tq?B2jv2Z%5e9m|-il*3#*vdUlk$C1eeozi??rB2% zIW~hde#|MmEm1%HvQQ-EKj*j$N%bb0tD8{E(F>3LvPHPz$_PPRPgtl8gAwQJl3m*V z#bUMn0CSse!{Hl|IJVb4CKVoU`0HVYFnE9{=bM94EEn^~eGoZ9jq_<^x(<~0yhU)% zaxGvOrIbl^%5Es>SbEd#45EjA+lbCeT>?Ku%c0E+kLlnGE>7{MPfR{XB=lzIw!8;)bD*6sF>;r;v!LN=zFxu+bothQNgecsSArp_L7;3-Yp_kgN;v(IhvTT)xHwXx zeXLsWSBj435tym3kZtn^SM`K(&h8P@#2lmO+iMA*ktG{v+YQoqcj!zJ+H*HO8aOWD z8nkVAvJvP#)G5kz*#V`1&x)*FAT^3IwGcmEXV2NZ(FEZGHb-a~9Kt3s`4IcknzP)H zx}PJV=mCoy^dp5&bfO~=B-}or*PJ=j5i+^QzCCre_6G6c^M4Q?JksBrm_LN)@qY~+ z%>M^ERCVOA#87yQdZMyr=nEw>m}LxvFpaG3@|XeA7QG02OTj4R;??D<`;Yo)OYIe# zEal29%@S3G7{6K^$szCK|3;F&*K zLf?+`cYz9fBe@k78(pTR#s*V%m*oa`eNNZnD`l`%9s{T=7|o4c-=P)6p`7i~_q7k! zX77Zh4b9@I&1ek635-?^+xVI^t6@7f>L}RvzI&(?*w%}M?2Cuwr+s{YkoUNSduWT9 zX5cRA;j-I*4ExoO*=8@*wo5uv+l8y4T7{=C(Sg39e3JjAB(!=HHBkcybS>auvBwr+ zZTur1M=&0ZUx22W_pw!@+5K_+glyLahHc!3G|zyDE7m=fudu=8*8~go)-_LR_QN!u zrF38jJ#m`ME(`NJT;eN~s@+Fen&(G0{U0#GAP-H?FW%N)`Bqmn@5oX zyka#LsZ@pJNqS?uHgZ^mJfZa00&bdG3A}l{w`<$Sr{uU59dOYBcO`1}SuJg`moQ*Z zp{Mg8)w01;ZI;ZCwbd(I2 z;eq6kRlDDd0d@xj^?I*7E2gX^7Rv#4k2IlRe!EZ&Uj@U|>yWSMm@E?ZSi4LPIm+PK zn%#_}5O(#7{I-)oyR|ZGy{QkRYmJrSkG?o=N||8uUtRO1mI)JdS)|qs$S*5$9uMby zh~3!D-y;`t^=kYerRN@LarD z6F57dPK`EV1O};v&JG-)j{vkR8;8LWuxXl-+`raee4#Jq4OqQ(YG$qs3(R*W+id>Ie1k`Hf!qQm#Rc;9X~ zIyXi6CjIl3Te)Ac3r>$`bPYey85z6lPkSwua z63tazONg~(F;S3KNp{;o%Dg`Nf!KO+1?NLsejTJ30Me_>9g2%u{$@vMDW8=JD zkU)2bz2Y%LeZbKO<3UM9%^aHpp;M%RgJBt`Eh!sDI94~f$0nprU`WYy4Gp5VJU0{! zKz{xP7K#N?b^{J}fU&A-gEvCS#qJC5K$MV&7m|4^Wetw)SKj9epRLv&N->Ak3x!gF zZ5)URuWxs3B%Og{oY>9qbk*dq3U=N8(F3?O+}^)&CP}uvo%JQda1xGoF7Pm z_H6CnOs*q})@fF7YHVd})=pSBOHqzlRw~BZk4W&CfV*>H9DZ@^|94_2$4)C!6g6?6 z?CIz!>9q_tgrL)m6-$tlo~jQZ_3gBT9$%jG(zBq%9#o7(oL#1H=N-}a)TU1pgo1C_ii<@_lvo32O_fBH+ zK-2(%Mq^j~i{x$gF$9L=kD&sG_87X&1<%^K=H5veQSZz|^QX*0T{wp}s@J5pB8dGq zp|vz=IK!?0)i0_P!pT2f!clltB0idBeog{s>*xsm2+S#mHxbDgB!{nH5*|hDS4PSX z-1;L8D&2lZx+<1O*lxc_tKfXv{*pZmk!Re$9C|GNoc z{eRf|f1cp4A=1jrKYK0A`4;n>p`b=y8hOG0d4dVbf4EVb9$2PHAi*t|-ghIleTsy8ZF^`#riHC(N>5~I|D1OBOco_wrh5|5j;=SL4G{^Y+ zAjirRr{B`8uui6aQZ}V{{~i+@pu6zAjlmCxz>k@?3d!LP?lDlZjRzpfY zs#2@kt|H}e+S?9_lLhlYz6tcc0J}1FyG0`~8?1~+>qI=~IDgO({kJbQ^8kiz_q-RJ z8ir^e_QTxY6`MoL4cnI3Mfx*Fgs%OU_o1`X3*k<^_&0W~#!Oj{yD;L=8^oVDoe(J? zD1{Q`r*W|wwnB~;hLVK~D z$bXWt;&zAO(R;TX6^v~=er994@nXqRe>Bvd#XFr}Q~~2NOj30D@o*xdcfyb~lv*Ux zjni2H<3anfvh41FLt)vIBf?=r0b+wE=wd75Tl5IUF_A!#7zr%&&vh2L0_xF}5LAJY zqya2=6;=+w)DU3U;=*emU?;KfU{iC{z&xR_8Se$-v(X+dT;z%SjNB52)W7LBu9%&} zXq3{%vg|_s5(Nv=S`HkiPZ7Y_MS2vAbH!-=Q4@K>LuLE|*CitlRXx)_+^-xrEhESD zf?oaw@7qb`9?y?t1zQBe;o0R`T5CqaGk+R{l`ZE|``j z7$bg`(e?=x^ME@u1vDyl1NFCb)-rHO0W<8ry*(riK+`oaY2^Jy6#>YR=Mygow4UJ( zJYOkf!2P9LIAR*fI)ZhUQboh5vf7qL*CA^93}~J=68l4rO^{1F7p(aOIe&h-`k?lz zrtThdcjfs27$?^8@ghw4-3`S!q`c`oxt-t0$d~*LR{(Zq+tt^v`}d(pHGGyRkZMF7 z-H}D_19`D;3vtQo7oueeZh}xb+>V8KU;-OtN^@T+3Bv|lpT0R$;K~1JwQ-+~gLeIy za@wD~_y66Lv;EhU7b)A=ttb(M%3wtBDRTDdc1dbBC$e|AiEGKDJX}nA+N1kFl)~g^x%!VB3%@? zE3x{2ia&@S*r#^5g$U^msd*I>`b0trm;bV?b?M`0A%IXuDL{1h-w+7e`#Fcd1^K2TjsX=k(GY+p24h-jokgohYxIe%9wae2w3DD3kaL14KFp>uPCc>-P(43oLhoM<(EoKtbTnj}$b)m2 z$V(dp?vB|*{GD-)o_w?2w4(Y`Fr~@REMy=yJ7PO&BoGpywQ%D$sghI;S|FJVxBVRc zzy&+%UA2AYMR{eIK>57kp0<1IHFU`&Z>gj?0)q0!QFpEe$OFDu|0yF zYosEAsYjpuy`P0U2^@2}F!MlJT71jEoA9_zwzLFA)Nj1$I=EjtkMhN|mF#A4M1^?e zv9!E#j3b~1o1Nx7=@Qa?b%T#UENk0Rybrd}*hPU;9lGi20eB6per0mr3CF9QNal_! zlt|1P3`{OYZ%g;WfRL7CK2YwX^ z-m=hMWA8~m)#DaN@ob#r*QU^zJoZs-_{OwzX+;Pn!|+sgz*Q@1zG}xP$x}fnm^tn~&>R-C|Jw)zbRU!{=tbr)npzL!FT?%G zKYy4>>qIIT9Hj@o2Xg;AiRF%sAcFZB-uC}BiDm!4Nvzg?NbFZJSZXRESO=l5Iznp- zm@s)-Jpa%3_^&@HZ~CdLf5@toYqPK+@lf|36};tNQeHsrr@|1E4S~EQ!e0MX4inS1 zTi5l2v+wuoEpiX}5C-qXWmVz!8HcSc3|Wob*-;yBUS{>BMq*g%d7(8Mo%trZ;tl`I z5h=XlQ89gUP$14p(z!OcA^$V0BI~oFYJyRpbevPt)Y~b@ho^v~<_e-Oe`P~FE;cSE zHpbHSVi3cC+Ge0#q*y8nY_{_D%D>=-XqwkGHjwFBYdK6R6dErL==M2GO8_se%`J|t z_?0zayp_fvR7r}gF8^Gz|3Hy4O(ao6Nn<=Y4XrgPt?zoQIy?`*-)sXun9nEJGZqrm zt=xgiP55e!H386Tt6v#u@4`01d2Ty2B{wO}KujfKIRn7`Cd^VD+S2-Va!3V$m7fVLe_h+|b0NYb54 zAn1lQS|p#w^xvWu3M%nVE(M^`2`iakV}Q#cMX(j$DC@---XD34p#M%~-Y_xe6(|%i zE7j2QsOy>0ERqG*X+akvYr`;=Mb9lb?;T0To>1_Xc6!|&rT4bI#`HvPiQ#g1OL@ak zJXVO8$-`+zag3)<^&KiE8Ap_Zag}|s;x4($JU~XYZS$}MG>eF{p=^qU$rKPLxM1&^ z5yJxuSj-0+NwU>u#URBJG+ElPb5p+rUM*^7;1U8!u~zI-R?}lvRD|n?GvX*j`nzve zeATpk;jr;3iDu`!;rJ9hM3bX{Y>`nAKs>0{d^*`)uhH4`gy*NNXd$Rw({`~(^1pL=L zO=>~?*l`;9j!hHk(!KeSmVg2fH2SE6aX^Kk2tgD5iTy#8u@ebkiJ2TsfekCFG}CA; z8#QBeYF&EE8)c}H^vgqNXEe2}o;RNw?dmSQe6Am9#tIHUr$4(^6D0rzmtJ>HU6)%< z(>%{v->Z0xKrc!?ki`1!nb^L$R z+eqO{7dF?>1AV(IUm0y{1E;CtFKtBNsEm_1O*LKB^~v-jqt3Hnk6Eof_)I0CFmRaJ zO8p|>DfCr%8wgGoH5Rwc&Etk=xK^6RV9RUGtS>@UmjNRaZB+s0YF^e+d`NJ@u#`q^ z?gM?Wn8VDJLWZ(Q>ee$qF{`u;rQ9W89s2pCr8fWTgB;52#dXGLd#r(HLcIBABTV9 zk?PYU=WXeAI0ehpucqwDG3m`|l??VQ4>YUc2NVf;W*9HQ=PQ-}KnR8P{n(h`0#?54 zD-Hu^(;s(le#+vE;pQ85Gcg_mM#7Qvdn*uuU2M4Z0ajO18k zPHMT%4ZM3R>vaV4>*S~V&yQ!p=1Y!*Z|E{eP?qpPH37!7c@^eZUfmpy?cn_{3YV>Wo! z@a=3bK?LV$^X@-I;v~xJBJJ4?Nn5`vRLv~(E$W9Q)Mi;obp+0%@|JazQs)O9m&TaQ zZoD=9;TinMO<%iw3}$%AVXDr8yqdL)3ud=})c_zS!9&_4-YHHBSvl!z=QRORHEP)s zmkR_owXj7LP%bx9w}3)uHTQ#;~oS!h8eu>M>=(Rs4DCBhBGeqX+FE+VSJ`CFc_VlH`;EC z@CQ;<^_mBso+U}KGwpw{_ZmZ-iIfHrIISzUmGEqtPI#m@GJICFuSV{+rJLDLNj>Rc zler8row4S?(5hu?x`e+wDiauq4>Ft~I;SO?=ig;C1*itsc}E(|LG7((bY$Byo6;L1 zX%RV|>1psN1~4BC$TrFPROgEbFNidR@Tod5AMoc{RuS}p1~oYDVD-T+gk;Z(<1(Bv zst|GbVx6B&<7e{z3Y9o-h``HwdWjz3VFk8tm!%a-1R~LU)vxtryRmePiLH<^YZp%9BA#Y)2 zwCGT+u>a-@r{|7|fxPHv?MqMX5wf68&;)zHHLFZXf0`)J%)HR4i@J$)6Mx9rxBb7FAHo8;3&fVX*x76&mRIFf4Xi~ zH+yRV+=;vu!@eTT_hG+9ip;%XJ=k=HqyM%UKkVKwWO#s9Qd^?sNFEdt6mCn*6k@Ec zG6bfuhU+>mOgnwAwJXkKw3((b+$!`inZTQi8|dLP#moc_Jo-$yG5FqcWgnFb0Lu0U zBbMUVb{e3&eQ+Y+=PS^oPXSU0e2=Y+67EBU^O0_jm0t|-fH8<2 z++DB@DfopZW!+nADx0EP@^DQr46PTc{qgSs!cr9s;T%PahH@v0#JrO{~?bM~a zk4U={9?cz`Fa7r8&1i(1AF;RX@35QBER&Ok6wEpF7W*udLf~$_d(GU8oSsO zHz(7?*_w9_1F$M&HM09Yh4Z0&v5pcACH@WZS(5Z6{0)}$!A9;;2orJ9`wc&yQvA47 zEib+UcGe|eHXeTB*OSZDuh26*aAplhGXI_aMMyI3QH+7EJgyJ^a9o_x>jA_uKFJc2 zlqnrUBpjTdm2%$-G&LqlFjdNqEg5U_PYHK(au8?%G&8xxrIb8=)=9y*WGE*2(DK*E zFTar;21V0L>E^Ca@iA&z7e}Zx)H`w@{+WYYOdxmQr1?2HW_k~#IJCzxg0V58r99T@ zITANn$)$+I{X*>poT4Vk%8-F3|4~$Km7zbTb4nRe4kYsj)CFLgEYRuNCM@lcD(=KH zh`cD`bn1VaVv`fp&&>!-L=hY24m7y27U8D@$}Sm{P8SYZ|IS*tYCKGwQ9|Kjl8#yE zK#cJ~-q)&SObfM5dz;eZFF}efyEqTUp8WGH8HMpsV4&L>giJQS@dQ{?xQxV@nETHL zkC~y&yUtqP4R#2wjj}2#QdtR->KRU&vHaP|qz~>*E0UWXliM9XUBAfk8-_>CSWJuU)7|Q`g^2db&4yiBc>+Mru`wd*<=&^+okN6^cKZ0Pp)gm zUuXq`W7qyE{rSDBTLl#~UEulE+ukJoZhEy>LE_BV|vQ?19(%<@R zZ#I8j(Hy3|>kCfTKK%xNsp`1PKzLD}6rZp-;2V@(LN_)4rQOR*f)@wVOePKv*_cw^ zxxRo6)+G5;Zw&+6W)c+y5yB1|u@P~{f!2hZflYuBS`g9^XR(CfWeD{YM8vfcj0YE1V4(saKNR`YV`Vv?it5-U<~(#&ySC7d1filUTU16 zP0i(Qg$?6|zO6Iib{F=isUt>7_FstCAQdm{QxJDa_Ny-$*9%dIH`a(cr$y80dy?N~ zkGGdpkgYEy38xBfT_8iS0C}?Atd$dE$@*%23BHJfC3hR11>9XJc|S?au{P zpq05?J&&3_n%g+Ca*V)6@dg6|lJOx9nw!=}lFdSfJ1R=dcYZ*3irEF-A;~u z{XpuYeq6!bKCsi0(*s|PQg=NGb0J^WEO5mpwcB z#xO-h%J~6;s?}5=_RI{-k7EPRVs3(h+)J3_s(;=x)M#aJFG8L)mP^R* z(7rICrvkwux3sfR_pnmQy1w#>jKL$>pJpWr<8lYiw?+4HGo@!T%Q*QY+6O~x@;CF+ z(ToZFsz`AqnZrOs77-O7-j9s!i7Y-p-uXs5C4w7M*9T;1Y6P&qe#l^q$dRLT=7p;0 zMadfEW5l#*qk}`u67|`qPP){IMt+wZW<=zicEn8#U^28~NKtFoZu4EmnhEzX-M?~` ze*AQm+52lKk8-w=vj4`_qC|@lJT0%O%vkuTs$Xc<4 z@zcV$RH(|0Ur|;J1+ajZ1!{!IYZn!RH@ArDdIUFwY9&AZI;B2~TDG>Wl%qKP(pIp)BOl*7wld-v?+|;PJrm5GXB{HyUD5Ye*Qi zC|WC6EH~XlFQQ6&uP9?Z_%@asDYjd}HBwNa0a`)apFH6>QMdwf2;? z7E)>px>2Dj4&xhTxAK*)_&G4`GL@a`ES1-5ffM*MJ0N1!i$sB^{exONnny1Rb?yT3 z4j{>4Kk&s~^-qIIDR3CO5F}E(EYsF5mAMwV3W0v=%fBZnElaJk#-d z#}wm`*kn*^L$`;SN$T~6AlT7=UouZJdRlU+!YW((-`vhxZ)f^z1@;ep^vXL!-d{4S zv?p$QfyI+c6!2LYUnic%HaBOLV%@sJDt&Js(7gRb(mwX-bR)osLUeGCJyzgSD<}^} zmWjKhI|t?3E<}eG%9!89SS$8RQj+a%d zv8i8d7^>an%h3u_cNvzuRXnq==GzMDP{87CT%es#dC7RD_>wfW#8@05G}Wresqg%j zFc9*6OPW=e^m_Cy@yvY#YB4oaqn?B=ZbJqIkGmS<{Kt|+8mtIi$v5!Om8C27MI$JI zG~6lc68Ba+7=~Of$-(7@ZvOdsMs)Y`>mbP9Tq^CWtDGb2D^S6O=+Qr%&$uWjIk;7b zOQ}tS+15|mM|*CH>?aSb8}_mpbG4vy`oVaaY$GJ`H0f^9A?OWdOyoVT1~l|=Uf-iN z9~bLJ)@Ve|bAHRB)JT>$FNa(?PSD&6A2TXA?#~&;>(eRNV?!D4Aco=$(}@3_lP1q3 z^QtFJ)(l%4>4IgNse+OZE=N?gq8|OLsY?~;tiz|{SzpIXm4{AEl4u#Pl8a^#FNCqV z)WT))+h3I!9y<>cONe~Zv}bAyEy&`xL{5rC*#H+S311H}%kr8LpqjE8&QYqA_dspR zi^mx{72OIZjn~1RO~eWzM>Aoc{^ zxywn=I17)wa8=Qz{rydh%qXsah?--)=d-YA z&Mg-@-Ru=YG(CTC!+O}B39T(-5;l(G<1FN}`tP4x`}@ff?^};UTYc_T=nOngiP!rn zZ*EOj+7+KH{DV^S^x;)e98QVc!+ihSN7C?VLXNNJgqmw*TFytJwCX2tH|ecMTgVCm z$s_TRz%I9R9ZZ1k3# zBD1`sW4ymn2M^2`u|@|YP6p-E&hvn03(BESuT2L|+O@|=V${A`WZL~Y%@ink$w~{u zct^;b2rD|&J?Mi`T*n}u1Lu+VJq${R$9b5pP~Er0V|E{ft5&%gHB@G4*myB+St&f4 zk{7bOp?-*D?^+wFPN?PI>EZ9NsMthucs?L)zUQzikMrYQ;INEC%O__=*PdRd5O*`k zCAkj+r)fM0n$T1prwpZh8h9mpYOzZ%fF*Xh`T+}APiYI4G5SBhR3sg;pdjuQQ5Swu z3F0Xnn@VeEoj6`&I6k<`&NHG{zCUN)HCFT}Y41^(e3$wdBYPj@?qqiRrD}59UOPF* zl20`h3?Du{IU0;D?28}fiv3})eF3LpTrqg}KT(49q09?GKTcB!cq{rHua}f)HuCL@qS?k3vul8kJMoGuDbw2tnEPSkeXj$8oi5BLewml>vQ(b zp?}X3a);!sgsLN39cmf8%O1lCvLbY&U$a=ux^l)ppTAJGWCa#Od)_P;s69K9 zw<-~J>)Izc%HF753 zZ@+Cu>$-(75l?xV7I}B9xMhmMxseH60=~sr3n&s7`%nQp6sG|#@BDZLksPc*LNsNIWTIM#^c7?czM~2 zC|&_$S1v2y!e^ww zD4Kgj6dfu?zo-o7gjpnyhYm0ydC<8gohDY;;Uu{SFLnhT$BkrP7a52k9-^nkjQV9q zHvCSiTEcJU7}{wF_h>grS9h0(k=H9<-$^!H)i0f_?;l9bL_hZ1-hFb+`o0I)JY^N8 z6DF5?$CQ}Mvgz#Ind-MzAUXrmgbNYr3rsUh!`dy93E?$RpB(j1ZouIum4!IVJMv? zKPzN#2L1ZreYp$U*@OoI#sl7cLs^_j0(!zFzu^Y@CZ+)fqRGdbQ9P)iI+a@pe%P3h zT^k~4=p3N%E712^fnDz(Fq18{=qZX`5rL+rP@GpO+VpPQ+?b(N{Zn-dtCCVxmyup| zOYNJs>7F5~%w7M_SX8TMeM;2{945ySVuinV(b85mB^P4>phl}}%$8F!8yVlS56zHv z?aoOj^4UW=y%vyEcs5qh5o88*#cmGXl95)3sJ4b}A`n>M-(u#NTxaQaj&C)(Qfmt(X({ix{eW zF%eWwsXc_@7pMS!^%A#miY>q}+jMVVhqcWCc+=BblWJG_bk1<7{L#m9pC52>`}DIb zkl6#%(ji-L72#>BO-!yWOyB()H_e4W3s@jjDDxCzLCS^*r^>V_R>Q0eGUE_5p_#da zPVCO56HQ?V{rz{CAb1SNzc~!3xze??!uoyNa=zuTZ-`%FVewBfJ=TP8Q{Ha`{W!a% zuAH5@0n_O9<6rz2gGs3ke{uyqj?J+fIO7QJW>_06yZsmK2>FWAx%1HWi{+F%iOof zmDUnU%#YqlD|I_FMgly7OwCZl3-Bu>r%alM_r$z8CJ277#o>ExIJOlif|~njCin^B zBnJFWCL#dkRtzXV2X(>mIU8bPmf~OCy}zKyrn?G?Mp0w)Vy55Lyjq#Bu)Pj2tAK}& z-rlUaLgZD;xpsA@jIUqxG2FWQXz`@4=JgcBK{b;enWxQ^(G6`+4FcQIb(~^3AmW;{AUy_Kp9U zZp*f@la6iMX2-VCv2EM7ZQJOiW1AhjW1D^7wbt49-nD+`oV`Ch&mS;qR?VuKRb#lH zhQSxvSGg5kTwEV~0lg;xHgE@tU6e+ll`AD4yfulO;{6@o6G;0sP>I64_-I+9tmgVt z&6ZM}cxz{Dp*4pq+NL|z0?$yX4IC-1dh$-@vA-OHwRkB*2?x>xWoFK#epNHG5WW!= zWx7pMn`^p~6@%&6uzj36*oCFvlOh@^kcqU~PHe)o%J)JXT$>apA?>fxQ6`|hZ8%%V>UpBG z$J;#nr%uR7m5@tJBTG#cSX>e{_M`!l#JYyI^O{BV$BwzXs(ec zqh2Q3cQ8D_htknLw)WBE+vUX}tY`5Mp?sj9$*Vf6Q&&@gK$Mb;xdHQYf<4ZyALVPc zQ_?ySC6D=q3O9l;EGM?(nWWcf1_IM*ZBc(t1e>2J{Wzwye8hy#Uma+jp zGjxk1k2@Bm*BhX^bsey^2_+1iPW14J0(?i#rGytm(S~tDoOj!g&^}F0%b4@GB z`H>6`CX%;Pl;LhVlyK< z34GV{DDl^9gBrP>X!9gMS&GIV9K-ynYamwD94w*jH&2g%;hUmOL z2(e3?o%YWA$3qVIv3Gq+7$9O`AzwLO2Y&y9rJbsZRRapZqbUyf zc>eq0U|VMsM^ghM6DI~kYZnt|J3D7{24NdxWn1w-XfzF+?HvDl8J3OdlLBQz45d)B zp@ZTVMkt)Msiv%bP!mN0EARozFg0^)nj*JK+>H7e6nEGMd0jB5LdhAndzAO`@gL-^nC=aWUaTh7yp!^ z7xqo5grzm|!$^DT3EKGc*}M(ET}!N(__R2HR_*4%+M9p(3RE916n33k@<|FMXyPXW zwWwBv)DO-RoB|obv?5Z5)Xoxp8_FS@9J)zREJw`hvjO^`A{ZW2Y+0h*G_->KL=P+=wDbXING^;{Dp9gqO>#s;oRp+yBZizT?Os>Z)kH`cB-g?3M#zE zg7fFrS(&m@iRhyD|Duass6p$tLC9cCx=QfQ)4L)7st1*Z+tSrzpqUZOiGo~IRDc)3 zwFc`awW(-N6H7xzA$p*rK0vVec~DE5Nr|sR;ULKNYkXI1);1Y=i+(KGNKfUlJ-@4! zxpxGwq31se&!`sZ15WM}zj@ zO_*W0j%%2tY;ei*)3!)uN?fo_=ec2>EONrUwJ`J(5aB{C2m*KiK?AO7)jCT8ux$e1 zWBzxxHL@{gkOcURgn_NG^}pz6eH8xmnH-Il7RVbMN2OzInm{Wrt0+oT)Cc-ifIV#* zH509o2Jzo%zxetSkWItzK~EcCZcTdGnfCMu@B{CFyuxj9WQESuQ9Q~7sf#9j`6sVwo$2X^jJ2oi zYtUkk{5IEdqDPN?nF^e@eQ9FlKl8G=t;TA|qAfD`j)icdmoNGRwFSd&5uAO2{yqoB zA@UXD2>>+}0P_EVdHw&zt3M(CL#6m%jLU2>d~yKBWib7OOJB;vEfCTz_GrWeJ&=?x&uY&zE-)f3J4*YX^RTGCRjG=L6~_ zSjmoTsY>Z8c=pcP#Kvh(`;pK&C#WySDBO&AKH8ogqjT=LQeE;=%@LnYyh^YBsGam5 z+ebA_z}Y`v^x+9}rtHkzoL=}ri1go;+G5>H;9dr5IgThDZd*1m%i?~Jo$d$a86IuaF_5tsYL4xW^VH3c z;+?a}@U&L$nrSaNhmdS0dV9j?b^>9?Ei8r^Ep3`OS(5RK{z`@UgVl$yr!5vuXVgbo z({)+pl1{-oriKRr99dkLpW}-><}AZO0az%E9L+|)gGSmf2TdjyXk02zs*d%u%X(q( zfu_5akR4$OeRZj563#7I#&}<#Ac4PwCs?&FMGF8f8t}3GJD0cqFREz<84E)hI|Ji? zdA%%vbh;lv{0&|L<@=2{!~JIxc`}-j;Sfu%gbb-C+k~rDt99Fytu(0^!YA!t`sIv@ z+3Q|+TUl{4bx&V_+JiwM?5dW0?)%G>rsjsdM^*d1bkIC1Vyc}D2EKvJ)%kpFBjmv(t~@p!oduh zE-ugM*S3id$bTVTFmE26Oj7PaT~j+ou9$@_@(DrD!8|)@k7w!xYQ@AgbtDQ&U`KOX zfKx^L8YQ?A9~dmxNfuPJa3jW6k==SSwMr6{1plVbw|RjQW88F?-~@i?hKc*zsjxDq zHnqqs{so5}{X3pt{jc@47ld{OxjGs>m6 z_sNeopuztR`>7mmt;X}`q6|?03b3SA(GocDepJ_l8L)+w`kJMl=nW<^<|XB@GG|DE zDYG{sBQ|IBKf|g~RO8QG0H)&LKtK%t4%a{F)&FF(|5sd{Qqi+Q5k$;uSuTFiYxYwa zO!JCI&8$U>vQUCyr$z+{V11^}>XvLg*}81-N+UKTc%AnxMSlnKrF6K=jHHSTK)=Vg zbu~5fz3a-zdU*tF-vNCOq=1V>__DqE(94TLftq)@0QZSetxRAo1*vE5S(lAx+aAby8v!j4ut zznx1MWfI7SVf}f19j|DM%&&DsEi=6_{i2O`o=;;1pF_}~k%||TgN3muHxgD!78Xor zILif!?C{AZ{;uo?WcM-UZEW_)VCd~YpI|w;vUCQ+{6At(+icL*5ayG9r>%YNoYUIj#a+>s>OImI28`yF`r}xiH zJVH)$KPOIgTiT^Rzmhr5)(_8)8oJB*_uW~Tn*xR0NEtFJPv3X&EpZS_;?3XB2mv>i zNxT(6ImKT@yfl1=cXRY`qrK|$$-g1L!cidp0OozKV2JO5lJ3}M<|W1{nXohc=V=kg z5vKgZ1A749|3JR~|89^!Pm8>*ppmnMovpBewY8yv(SHe{n8eS>0m%1<%L-|Cwxbwk z7qB&{2M5t&BCxp<;-PLVr7}Y3H!n*!|DfJC^0)@}rZjSkz&I($d2#82}RP(Tf0T@ED5C|Vf-Vkz% zaf2sYzp2bAuIwPVmf9hS4}+9foKD63cgQZV_jO4>%sVu*$TKb+StHb!sZDlb``bK^ z9VGKoPaP) zkUs7JKJ%{~uGw$o&HlZL8GStyUv}yvIf@ZlPOJY}Uu1d!xR?NTp#4wki~q94pHc|_ zjXh!%{}Mxp?DWt3Q9vP~K|Op7Gc5AXi6rUo&Q=1aKzZ?(G5!*x!0NJU9}U6hzSA|^ zYOdQB$kPL|2c`hySF6&!7YoywRE#rEie#!$G(c}q;Y|<=gJlt#(N-D7dmW&1D@ZR) z?{eNXcbZHYz>cBV4IC+$WUCc*9tx>znd|h+rap`y(>hY+Lt4Tyd$@z}VE`dgxXfCF z@lJ$+)_HxgCRdbXSFTfQPnXQe$8!pZJ#4S?;@^lkk9^XpI0ptkM=sxh%gn*jb1ZGo zt-rJnCAQeKRRWXy?F0-4CMEWyybH+%qF6HUFpAA(D4b$wD8p=W;qvG&O;z7Q_05M! zVYAeQanuU5h@gfowf9a9l;dJdM$P(IAiU)xwd!!bq$k@vw;25i`dkpHv1Q+fS`Z5g z*9;1Qmp{0O_qWkwLHtNR!{4v2$2O2tFo2P80lWU}|51qjOS9tdE>oiP=T2_7Q9+0h zI8xtCnoqAGCG7AZ%y1Zb3@I9vC_aE;ZF;L!+0-m^braj@pwDkGDdNu@;%2&)RCbbF zc4KOK1Tb9PkAht+Xgi9CZ99ZUfiK>RVC_WDK&-G; zB#KMu#gDTp4BI1?EBd*9W{~)?IK>DCcLPx?yGL)o_(LjWp{(2#v?DNKwQXm&klEg(G-*IReaxssA`}kUt zj+u1-KKyVB6sENE88+nvk%ClXQ5cR1Cs%6F`uRbK5p@e1xkzBeX5KAe;LwY*6+LQb z(ClYZ(*PIyxjoBeVwtfSId>(IKr!s=A#kjPKhN+peR!xrJ;oNhhU(I_AI18S(l48N zR+ysR*7>bTM#PRbXcx+)-t=BFvmJ9f8fQDPP$)8=JLY*LR5{NA`-w}MuHuF=2Bg`H zS3zRLBsDgm>sLUBvf#eY8ed_?9Pir!B(2U|U>_)Ul;-MYlmb?p+A&poY?Vw{pRC4s zQ0iTQc6}n`X6O?1@i3_~UV z)vCv{>_tA!3S)P%zMJ)+r>(PDlTn%@M1PQZ=$UxDX>bwBpk2)^j*djaWYxco&qiDz zs+)KMZdL{HeMB>brw1pC|74{3{%RLI=^))DBnxkx*y?)et8sEu z&Avo_c4+UigN(1R>{n4o!AvP;1v#{NK|$!>K>Zx z6rY(^R|yUnNQ-Curr}yW*b?eQiS4Mt%8CdVccTu;=|^10%*jb9Y%L@UTGl?zSP31y zvV>`0Y;Gbm+8}^9souSuuAcOTW-^DZ{%|=;mcY4yowo&#sRDH}!^3Zb_D4NXgl=U} z-8dl)doS^9DJYWp+zyv;dr$%8Z{SQ;v@R^kYsK(;Jj~*F6cv^~qB7uHl5Ghw<*wY1 z#}U$8_ZR)U7saxRf~g`V3cykuT9Ij?JkOO)bMU_(v-rRQ&!EzqQlGmBBuqHHokn5 zn-Aczpic>BePj(6iDJp5h+W{B3V>x;qtv|4K+E=lOTVxJ`fy1iAk@f!|o4e*T8YNMA#m#2oGG^Tz8G&Q&zcgH;|{E*+g*h?^l zklGB2;#ID1DRNDB!x@c298W-h!GRCa^|8j`?i@qO8q%HUo8<;#G8d@jRUxOV=t_}< zjq)BLK>}%JUfw*WuJl~yH`fw3zWFKzs)los#2Mu@IPg7E!9y4md{zOEI5qs`R-#l z{S(^P9PncHX#-cF-d!Q`pn1Y>zF`w}H;}r9*IpU`9aJMmd{?}YnXj|^Eqi_6kjb5A zNpS*$$Z5@6wh>=D`9QeR%^I z+-D5CGnE%jp%yH7XKlC>qGGCCnEW%&cu3fZAfU;Vl2kEbW`>#Ha2*nGVp6M&nL zZdrqi1H6E~Rch7R>bj9z50@KTiVy@r-?mHc>~N_2g9HfIq>j_CNzj}*^5ePSvTMPa z6QV@7#Evw#RN6X_bF#0PG6X@8bQOIt5P(({cUv&thWpa|{?AV6a5M_isBYf8Jkz8O+wz z#1Zf^@mEXACU)wNw+DX;wJsagYb?ij^v)QxJ{KBYF!{jx&935;bN2P~FJrb0hF|zo zAqjfJkVoirs{=?`wvBtn{?t*^>7xp2yI_aWeHN-@Lzl*POu1%KH_^2qvHFJYt4p8I zE*dmXgr+|KVi{t2k-2fhm@vGXu3nKhF}_l>F9yD%G^dU8{zwtS1jcTTrwI*~bTV|{ zIIic_iwXD3#0ZVwJO~bK3L`_TNYpg9#xZ49G=@C^Cdd3PJoc@T5YOQY0@ibz1EzQr zrT6547z|023NIbA%EP%W0Tbuj1n)JbyCsE*J^#iP_6Nl&yu~?XEYJe0@0I$FU)cEB8Z31dzXKZ54@JGW` z($>`Ozup{_*X2+YQNN9V(3Nb!KoOhciNLhN5lS7Br!5yl6Bh&rQ#f+-(Sa^xj7=t+ zhx0%4@tYHqC5UW$Ul%R$FRCCUNQ54|UdNphT^uKHt|!~+{GE?cF_;DjBL)RqTQ3t zUJOJTX=9|m*%V7loo?Zw{lv!Ulx}K=8lE%63EyT9*4FOk`$q61+a~H+ilZ*)gT(Vw zdpqkw3@hnZP+Ov4)7zu5t^mdtI=^Qmkwe^sO}esC0l~K*xpBJqG+`h|3iuMVhxJ#kkaTA=>*X&N+xetib}{*QM%exLdQB>+=|5&Zw8Rri;-$T+(SnHbpq zm$Rr_DdVhQ`Jzi!BSzWaT8j%Zw^~vNA*VX%;NalEq?1OPBw@p-W-sd&gQLSreygdk zuxgWCD1It^Vz*fvmXv0ghRdM}T*l%rWyv{d`waaI^_7syb8;2bUu++MJL0?QX*=r1 zdw%o#?1b1M-BP{2-Rx5Lv=t|RIEOEakIIfQE+dYRXysIAzU#C>hyCU>lr7j}asc0L zeZ3#8dpSOhxr%c*uEXW%Dm9Z9BT~$|$yS!uDPyrO(|XjLTT;E$R3M-_b~KjGQO#VF zIOkOT_S}H7nZV;q2?J6z6q&-7%XAkSi0~>uohh~@GySVhbJdZGs`?#M$D{Jh??Fcj^}kNhGfhV4sl@^>{^ zl%o#G#v4%v!Wmf(k|%>JpOBdxin-TsEYw$fp`e0m1RxWpNKEi;f9%d-u;h%rG$nNi zM2jjFVK)w^2c8h}WM);^VpZK@bWv%YEpo}p zM4vQtwC`hwpix#1Einvk*l4~_4AiedYlCg5;E$jI{_d}6NCFlS&-R8o4DKe>x0`cm zk`bEAVhfK3d)KcV>clEpWHhAGhmIA$)E$`y;*ON3Sl{()E#?B7jn+ucYyz#6?HChb zhnt*@H!iABiwoW&EYpw)>*uk|oMR!*5+kUx2nWqx^4t-dPQMA!bnu(>P$N}qMrfkZ zlM`*&H)lue)P{D=_zNDT25B^}#a1{Uxe&asqR!n{r6y~kp;?6&H0>=3CYGgQp>`%Q ziS`A1cOv~IPC`2ZL|W?>uM9h}Kz?aw2EsO7c?=y!jPyF+aeLElQs6Nfmqtvh_hfyT z?aH62Su`4tjTe9Y!f$HdWc^P5>rT}>CddqfqrvZa;6FACh&@CeZQI?ZDK{c>d!6Z{o4IUv*K^w z+RxtN18p~Wf*)#vutr868ls(^yS9Iu|;@Z1x9j=JwqTD<=aP|E1!HJ2&^z~QxH4lT} z@!EgW;^qDd?48lH<<5zJ&)*OjS5s5i6j?h-wVfsOoepX1sA~)3{u5lDL*LNhgCK&; zAOIq@c;fBd2dXFa%Um&Wv3EELwf8u;;7te_x!u0H_=lvgmc zBO$M#1;5xk9U*RjdjGOv?$bL4U+zyBxep6S_X3BXOPtg`Ky*q)-zu{`G)e?3vt3lD z=OW^cK7-q?>=gK-uF01BSBzHHP-=M~O9|i!2=n0z(IYoYP&u^JW?5J}Rsr zjPOTYqZH(N=rj86sm;UHH@AXjO;7%QwX+cPK_pMOGWK{@2~V-sOT9TL1I0wi2&?dN zoBlkZ|Kv9juY!E~RiE7M^X-5EXaBqKAlhe|cD*)k0*v@U?(vH^ZBJx_OlPEg-ComC z#w5qi(_;gjw-10!$DJRwj`%GW@gmMdNEH)B$<&VavRs9UuVFOz@F6sRzrmd{+iNDT zLt|(|q&jj>1Z~;pi(l(x{0|enxPbv8#T$@?XW-xbo12$&M_B9~ zoOtoyu50erdL?KSR5o-m1}Kr#{r!Jpx7fiW-y}7Twp0ZGN;$HVJpz{M0@U)^6yY_R6!5u3KRtfeT%i_~JfT9(S*<4@Z_ z;KaLJ6Wm%ooYqC`2x$0jG~s^)SC{Q(!@yt|LsnLA&J+9qTlStKAq8{pBtWPNgKGNA z)a=($^Z+TQuw@bY3xXdBsabkHKy=)msyg!hm?yxD3eBR%tCAG{8(a{Y*LG|1H#+UJ zAs9Cycs@8EVt1S|h3~)K`iaO|W#?nH*HG!}M2W!Fusm}kDxvfkNheRfa68|ZD`B#Rx)d-gMyIit$4XWb2;kEG(cRy%@=>H?flDfCLSQcp#^fXLLW9=a>wzE%iDu@U zSKu+XxW6O4RMfMXDH0!y=U}kZlUYe7fBK?N{a_L5uv8=08wQhJ1aUwIswnGB0Gs_gwW%&?XU=_kW##m2Y`Tp$yz2k=k1{q|L^!%}2r%=!(t?nF6 zVV#)SeWN-3>~t|_QC;rlYivOC;~VBlU9*`+As5=+iElh%43UmiW2u}b#WDGoePJw) z-e-g79t--NEjw1*KHqH4M`*(g-Ry9F*mCezfw8(u!D>x|QFO~Gx#6{YwVN)-rkq>g z{n|;@ciP#UQsm1)pI~gnnah482%7Rl51=Xi#t zy?eH8$f*J>Nb+4x6^5*)((`ORrW4IXaXGX;#2Usd1=4$p&P$RMll=47$4FHg(e7+S zfmK=W?3+j@v%8qcFK#!y?W9;$r2;5khMz4kWy_W3Qrgw$sLa}M3%}ODy;-!mS&y+3 z+lxs;did}4{fRV@`YdS)4NQrlD|*-Ayie3HLnkLaQ#d+G+O-?jj$sByJ*p9<4xt1h ztl&0Hvn)gg7{#!}X537-Bf$A&cOjN0&RjC-g{RMrPe}op$Q)DXP52IaiTROHdgoUR zXBqv*I8XiTBJXdNFg(v+4s*h9=^to$kfx%g(oNIPaUC%wOwjZq-9%?>#C*mW@6)y* z4HFopCK#>f&$(%qnWCygu?{eYC-;6VX(VKN;HfjAYDTg45qHyv2DqF=svFdhzH@vp z2E&Zumi&!2pwH^j*g3X5D}RQZBSQ)We4lYKc+Ny`CP4DR^yv4sDwMvnEKHDR0Bw9O z7P~BGZi@v#SzWY!+0BIOLwY{=Ac_k!={s=!$W;4f%X*hRM7G7=Zq|DJgdv@T#%H!) z2=*y%`da)^qndkuHRSRivqDl+Q6S)eDkujDaA^ORfU9g``;Wu=$IdU#3fkwe5EMY^ z{W?>>dOWrUp2ij3D0>Ih9NQoqPb3GX%OP|QC`eqIm86lgHK}=O-p6i%yr#>Tg3cE9 z=EU_?*<0?jC_4$|$cu#p*pN^PLHzEr>uT$Y{;KB~>VNd0!^AO```pP)D;@B~d_rdglc$^4*+t)1pVyDV*Y-|Uk@QM6H1xxdHS`CIV8OW{Ba|PbE5=?Lj+|VPu`S*b(DP?G? zEXt4GI+R@Ls-k7miw(s)UqHWJS13dC3Z<3c?~&0?7(AIfkMGWTecQ zB;{sl?J5WxBjh>KgNLznuLWdQe zKx9Ycq%@#(1wrY@McbI$gb=h%9NU+7Gi%{m=0y{(fjyvMH4dyZ6ya%uyFi|qi#3H- zc3ngb&(l|R9*&uxM_G5uY(}K`q)o9cXs~uOt(|I-DTPbyKd3rwEMyIzk{f#h>4y8R zc3ZN>=63)_L3DqyOO%#}(vuswf9r6|(A7zJy-9H*RQh4r+0ts62Zxm-$Ao*7*kL+G zA0&xIAjZi-8H)QjXKGVFSem@cftrd~H(NCLm#ilR<>9Btlr z&wk^9)=4aLVP5p|#b12)+S3AGm?Wi$rwNr+gV-#&v4XD{i>wB>mufjfi?-fMTU?#T z;}O>So!qRLA0Nxeoiki9+Z4rESFTCUDf8;IM!Svlc}(KS*ccJs5DW!@LfO7`7-rj#q7!Jk=>$giq=F2!YlEDcu{HS}2P|JW z)}-WdGX_nnZ99-DP^kIn*@cG(AxW4Jq6ex)iuz}@gdN%vx@=R;WH>R^ox~K4^-0;u zuG}2T3iKQcYzm>wq!S5Pc0BKq0Vmx)6)zo}fbf7ClTpe;e{}GLRliGn_3v*F-}@qM z4}#Uz&xI}ZXlKA3&}LAK9_G3ZHoBhLcGfo#N>t`IVq2%jJqK!$#2&tVr|i`u4i2I) z@B_ujjaI+zR?~Icu4B=Z9VjLDqm=m!f5?Fg-7JG2c#a6ZY#Gz5dtoVfadN#e{^4WF#re>)mYkMo*-A_tYsY(+*}TVTx@VJ@X2xuV4y%8zm5yId{lJ@FNB76!ooD zu{)nnXH4GW5ZXlQyUaQZIto*1@;TSf!1l1OG20p`v5zfw| z`|hL1-lNxU?oXh$ZCH-rH(q$TZ^`TuQp*-(Bke4gh`tWTLr|g$K zWN==)x36v?kQ;d0^pRXVo+!Q+OhnVY@Y$NxHhjN%KEP~%`6*R)RFNk4)2T4 zjLKpFVqKZS`>;1A-bMuwq{5wK{2(y+`es)8p!6EzXp=ug^-a#|*S^;qdu0!DVOaef zfg+Um8iOI0g;;tsTZs`CP~4+_v+3tH2A)XR6>0{DUG4Ut<`jpbgj4 z9qY; z$4>O`;V&*?QsQRsz@L;ON0+v}>^NmfV|)xx*+&0C{Nsq$z0TLZwoHfV#4O#4<6TS9WEr=bTp}4 zwU=7AYBKqUU5a`taiU#LKi-RSP3CSixak#7${FYx=ybK|`DF#6j32rAM&jFKrD1eT zKGqtj=$c%u`Rw7^w3R8@5itRxCGFXBRO$>LAU%j#U9`*h zJ+H586jmlVl%2T*`{k>}DqJF^`8i)sXQC z%}GxxLq@yL$mA91#P*972X?Pg7s|0N9IWahLPp=z7ZD^|5^!Wwl`Gd5I%pLV9xRaY z3*T4<)XUP|d;KoHnP%_3jk3f++3BnD{brXs121e_8pDnLv~1B5MC9B}`>YcwqI|w7 zJ5Dv-b(JfqXjPb9ih8EB{@7k)i?iSBZ*nbdRR-`?QeEPWkY_mC>^2^4E4ETcxm(So z8sUqeGwFr|E$Mr?3?o7nA&D}@xMm1g6Ha-{Xr$%9CyuI7(G*R!45-i`{K&l z69xJv51>t}DAIZ4Ctoa}`MrYWaZNlEImjl%2$g+ja3x>dCf{GBx_8uvg)q7C_$f5` z6JFs3BdvU~W_}Pg$(%@!6_q_ctWV9@$hsvE%ojm<39 zu0BJXs)s7ycckx}J=Y3mw64z1-nV_fB?xf++^#}N?e~uvyPmw?AKj+;o^nw>pWn*# zBFw{k5{~DBAXy^30B`XYeT3D=k`_6RdF-D&?oo zNgi#g)M|1S`zk-`9PXtXJW}mh*cYMjDv;`=QE00WyW&cr{N)I)--NwAp10oVam$2z z(m>Jna6M^kq{cyGsuJxmi1$K8qEt851N?C*Gw06uVsFej*ofXfw_16Ax?7^UGRHIs zVtY!+XE2joegC?%4NN#nG9z}*iFO$0It%_&!=CBIPwHnuMulNPKIX(@$3}lar5m+5 zazre|!W+XGBWN>8QF3j%|2>4T3+6f}?EFNx6smVR#7`uF6z`$o|km|@j`N17!nOs(&#L9@jKnjlD336)k!Ur zDUFn43E|U?NKf2#J83mmpA53D9CfX>grE+Sm{3kdTJyt`hwG`D)gFF5$h`JvQaB$e6A6PDNYY z0U#565pryjENrz~vS=}~u5eF%$?J`aclAVcZ$FdzbqMCgbv?flG>w;jb~onLkNZ+D zfNUDhAEl3mhh1PU^LFL68@;0wNLht)t5O{--c~0XE&PCm&)rT}k!p=i*o>@_UktJM zDTg;pAncTY;c1pLU23wz@8=e@Jw#qi_r!T-VD`XeRo8^?uv|2~c2tdttnt zMEG+^Rs?-dD0}P6c1s?9d>u5o8$YjXvsSj6i1iw|tgO>yP5cy^U>EBYTgi#z05VFb z74t3Iy{6v`-+4)0>nYOUyv1oL?ZfJ8lKnXE6vW*q#aD9(2bHVuw8wXR`z&T@fe`g} z?uPxCx|O?9^ed@bVOjmW-`jnTe>URjBK?8Z5umHSVs5AF?x(U4XF)o%*??hyo0?XTmSYO{TI&q zFYTvpi(fjpZ=>-APdk1{=UvQWvqnh~#p+b6sc{5@=w4O&R5 z0dlfWK>rUVf#U_N{in=!5v8it5CiM+$@vcP~RhTGnTh|*k>BiGv3Jjhq(&e zZ)9Q4gzshfDBqYwW@`vTV>iu(zX*p>yuWEvY7ysU|9)!I$$!1QdT{>oP=NR=N3SND z9RJ`GRy81yuknYlh?AyaO$Ivy)43GsVNnb^G2f!TQ5af7au$5z9PHblx5#DnnRjmaF5bIikF?VrSq z!9;d5ru;Ea<0t){7zLnreDZ@rZeq|1hTLAwH;XLd)b%uzgL=<(i5kXD@^-AAV&?|k zEs#%wh?$j(fC&4*@-+=g@@bZO|G+)dZuXLN2&<++#Q?=i80XkWo+tEsH29K;6yuYD zUePb8epI4jm0d=(YCE*%1?415WEO*A ztS~LAyMcK6$cra?oO#kI-)$_e2-SJI!#1^S-+E;R`?>pd>RSHqJ{m=}`rQOD9rg_P z{`=*mzq;oCw{B80ak96w{nxspO{}!EkRa;FjLx=cMYn59J59^IDOiRGY?PX!{@k$W zBwidh_fua^6&*2#PhlXj`5ff2u;`JLkRn|6%5OhkGk*TXKIW?Lw7N^|HbIpSIy zab%Ki$w~kBh+<#b7E4W(n~3$KbH+fH?~$34AH_P;ofJ zl3N#q#`^dW)Pv*3;d;I{a;Y3O(lVl?05DXE%ir<)C60rU1PgYU2Q$S{M@A#VJCW-! z0gn;T$uZ$yRiiDrMIBN);m4yL3vXef(Cb*>bpVDBu%z-t8CaR4!IZgv=ih z@eVds$pk3o%#j_4{UAgkSsB^L*Eo}iLRJ3cDH$CRnM4OFX=%Ls0huEQD&(SZ*(aDp zB4@n3LATe@Vc;M#sngKmtY?K}LkjpDlHp(P$f}Gx_Q4)Y7ku0*2+4{HU`P6)c7)M4 z&c;RtpomL%q4>=U4ueD0;&@7S%SRqyn$?`wncUV%8JFK&QC>^8t46Gs4Z4$?Ce-Lp zGS6%sQ}ei1s5u4i?@&`&RIA(dpq-bGBx+7whrLzUq(ixu+wu(%#~2~(#R#=p@5b25 zbfmUMCpWgb8=FAFu+b_IeCVSMyeG-+ueSn>B4IHT+M~|(wwxEpp73UyLz#3EXD2}D zf;}Mul;OMXQ>6wdo>e;a64J~&Z;{!GjZ=W_cMz_)b{0Dg)DE!09a4nlyobBo;8*xC z+X0jQ*lk?Kw0wuM=w-swsVe2GFh{DH zYx#%W*x+kkIQSHi=v*9bdT$x12PVPPq{~-PF`>PS-?~qJyVVyDV0X=J4;+9qdm9T;Hem8I zp}{{fQ4r~bFROGMw0n+qS7B66?mlTPvD>6ft}pF1TFi{|5Gp);rs^s(w-;>)5KfxF z7KAiPkA?Xpw{Uw19JX@55FSe8Y{EV z&pva0LqB&tRn^_qp{(c^rxweilasrU1UDvoagz}%bGb1?;1>+In0?QMCRV~ z257>T_1Cp~nLu<6DW7>bB|B4>>!#Od+f#orNL0THh}bqob^5lT@4BcO`o{DQ7mn94 zJj31@@!eKmM0P>aD3Ne!gpMZyy}-aX^PaWghKIc9f%}$>=SSOX0&jQwu5tB~+qg&d zM8~9~-r~->!a?WdGH+}oPn;9{1Zepur?|r7d#@sLI5(D>R-;`;S0*sSBamf4C5@Yof4!K7lvmb87Mb)?ogRU*&%dz5mN; z{4X0q?LSS%Br>vmbHCehI65ZP5#0QW3K_rLA32c)zhDOnE4ER;!H}i1rvLtI)Oar- zy$9ZhKNk=lM@&UUMP(mHe25R(d!4T#KrANdr>uESEIDS~I85>aU+*>;y1+R?Z826m z94QlEhr1^3_;Exj?$Ygk>_bL z`tv$ktWO#A%y_8@&^hms4W?Rc*QXWOa4OVgm+jx6f44LaC`Ko1jV3(dv*&SJ0T=ND z>XawdEsN7vQNv98dNCF4IbIFCI&oSiY=0#u%+`mv%K4Pk$8`buYj!lv)4*w#XKDBx zuAHQKf7R*HjuPv7NFN0`bJ3DwTus}L!`#;L!JAS(Lc(l~x!OcsNV;@mn`R6=Y;1fE zeqMGyUZxnFW>y}~j5Go)ZeS*ktXxENK`;iD1T;JnB);NJZ}*&CCOv{>sbHiE>|)8h z5L^ccXBBE_rdW48r<+9=#~{mGN5D`a4laXhEVo-P*|=44;^^kjj7E#b_UCL_u4*ah ztC|G5f`Ap}p6X^w#^#DrBTeaVOEFxcFN$8k`@LK30=*tTc?Zk-Eow;UGd{9DB|bcX zZg@;xBGuttz1!Y^JigPQrcgcIdws%tc$(clFr{w_)nijMCn6_soCQ ztji5wi=h5_0@CDG%nv>(Rzrj{Ni)iy+*I-YZXq_VM#Q73nwCY6E}=H&RI%n^sf{^0 zMqE}lw_FA$=|(`XbJmr)iSI545ou*Pz2#QfWju(>ku+je{%<)IXp&SRs#v3CP%8H} zX5Xoe?hUapgMa#$W*ouq^O)%@NF8HX>(aKxnjq1aJ(aTaQOfD@rW6P_kEL82pxVwe zmL_VihYi`0_SuuP!~C*j2cz_E2A$|?53EEKDYCX@n|j>%VU_P+*O8REcF5Z&JT0i4 zsGh}S-Vu%AloX&=vDrIVQw)BKg&fyr{R8Xte6iT7z+8h~GDfyKd<8LqF$USts~K`8 zzMNq|m=yD1fWjjwQ}c_{8`~&$Wbms2RQB2JCdmJOYN`&LMfm6KP84Ln8^vI4b*;Uo z?OkVeE46p}Y=%oyzAfkM$lAJc!SWyv+C3@Q3sbb*cX`~4z}AyKR@pGQ>>AHts)}L{ zV@W4uQt^X*XHofY$aX*;NPWOg_j$(XbrhxI4uXyh^1im&!N^?3 zeF$oM#XZblwT)bq?4*x0&0SS^aU@8*3~VOT4s~iHiFXS8QE732n>m+~;GYbxGl=Au zCewX5+2Y4$r4AuO!F4CGxzBwLF51%jO1GyRt0NX|ax;cqQ5816M@_l#j#(2WMg2q)I z??P)V&2%ZPx(wb?oxc>qomXlsR^XmfvsOWKDK*Vf3<%Ug@R*WH9B+Qp%3}jIM$cKg ztudGMMORv}JCtK1#NhPDL}tepJ#mU1^UyCoW4otila&DNrX_u1QT3f96If>tT7&N! z2R-dL2|^$~0_7fkzb4=KQM=a)kbreE^__ZUKnH4*QOg@;sqV$O0A~lOHnJe%;Op|bh8Xb7gI%hf}Wt{)*nyxH& zznhlA?Q$80QMA;F{YlnqNfbwXXsF#H{)0ZRa$|GE2rsstCCw+om7QHW;E#bvg<)4b z>hDL|xj&?T9!=G1kYj&wQTvVVxs4N$(z z$#?`hjalPVY~S1=tdR~ueE3!?T2(hTDvaW8KK{ezz=yL|%l?#4$e&gR%l{`K|IcM8 zHFGDk|44rMub+dWj3q7;vbRIVW1h{-ZT!qiR>tNy1-bl!rI+|`WX6GhVskkW-Dqo0 z%`=j-eZ@4P$v2jc`Y9pbAHK>*r!(K+h$YBVrvJ3N%aPvh95h{gxxZ51+}Yc+f9L?l zPIIP~EZpR#E?ni3$tEVHN=6V;Ds8uu%gmr)V$M8G`{z0)4^5nm=ex{Z&9o4X&8d+O zjTOHLibgc7@xRq+Tgqz3IR6<9J)c-VpSa<@5W*My%_-}EJ55_4(QW$nvqZe?XUWFW zaDhNiZUF2C5r_1)dfHLy=r>YxV{IXoO(owsT-_Cy?!ta0QFc6Sr1uJi+gmx&t?|u% zym%?J9V)!QuV*W@3-V~{C$xFBe%%5uX3Yth%u_Re0_;r^Q#Xj-FVwY)zRFdRY!Qbo z$Cp`%X%*42PFdtewS9FK(-@(;EPT`3Zt|I}4nkO^y=8|i4URxr#G(iPf-y{aOZ~Pug7jfri1eX_kJYa(}X7o9$exS99*$^Hw)WeonmdwMo-O`7&e& z?);UvLcidaw(B2TaJ8uo5k;T%Ci<*5-~Zow3)mR_yMj(s9Jlx^Jprf7s}fLRmS57= z)4?B@9w^wTYiI@t`b9m+F5yX2%hR}L)(~EwE@h7B9>62X0DC+2siYGp=$nh=xl#X^ znRGsN#!g-E^ZSBzbGr>}?mv5M`Z^A3Yv*Qh(1}TB7Lw*NCWTQl&)8te#9TvRID{)_ zIG%)YhDoJ^{+i3Q)Gj)0r{Z2OCUOpWZe`mEsP8bm6qP6@Gz%JrCZfLgOmFpE#oly$ zjS#TLDiGZiD~a)wdtMjJjawJ=X6qf)9n5WKlG$|5W8C#{AdYv>#wGBXiU(WfnE5s) zZ)CS}-sJIN%t0RCWZ+MMRsO@&BUV=uB6Hp>jXvHi`nksp+371(q_gL!yh-&^k|qT{ zR8eHzy1$;ioIURiC^XjN8_&Lt=K)}yM_4e=xM2Zle&T-OL_Wv^f#xznV89@bh52#S zE#YyQ0b@=d*M+&m6cDD<%eZ(h5t%(>7h%#rwA56LxF>x>#s&kBgqZl2rxS#OzR4-_ zlE4tRvHWq}sL>is_kifa;IrF|X~d#UeL>YN6$XE~yJ3#T?$CAh4-MY9v`1p``3XpT z&Kv%p^9KGm*W|yb;J=>yzn4BzUglqsbD4|F4E&{-yl%0)D&{&EJd0^+MzkIY zR$SIfbxY(+XCkLPb-sh~n>~b^(Wpg1>-}jl?(QtM>w#Y0zFuFuv8`C#Qf1$sB ze?(fqI=ZdJ^oN~4bSX#)t?|sm-G`aote+##XC}lM(%Szzu#LCmd*0aYNjvl*ATbH- ztUc?F8OlFZxf5Ii9Arw2XAG*9j+}IPbXs7<&e7m`iCb z&y(beQ2#D7(4wXV^}`)Q%1DccQ2Y$h{XBiCS@_4th(83@58gK#GtEqf^$PkiFTym* zUp3AoK6UAV=YZFA;=F2O!}qJYP~=wM$cXICu$AM>k7j(wwfeUGT651R28`(Z19rSB zQgNg}R33En)dT&$bByRFeYl^YJELHWhI?e1?3`KSP-;?DVGL5Z@ebx4;(tz{7n>*H<<_o$r~ZjxJG zAUdZJmW3f2yZKYNDfab6rkYRq7pTU87;hRKY+h4wHA_z@II3?k0s2JIBNEb^%tAGk zxxfR7eg#dYSG6(aCJRp^eD^j5qBVj(>4wI&gWy%g)iaHvV<@2~Uu%}6Qc{1sN=$iB z4t3f^c36%=hna89_LO&DHy%xEH;+(|2R=N##bpwd){cNufGgn7 zW*XmG9%n{WUOk=86|>7SiQD*!-!f)`Bgp*fRBqydgYQcws1_CwDt0B(p=HhiuLBwtB zRt4AK#ug?n&--8CTl>E>6-7Zeb9c`ap+J)%nlCGffBYjR0+X7o;py{uYV)Tu{6FVV z{wExKX6F4@LLq~Ixt!g<0zQrZnOc~sswIzmfbkyHFcTJOumdj(5o$fxkD@Nf-v0|y z)^O{ma!Ajw0F1aeCY?1ft4L!@$Jxdr6#m?N3>T<%m)Li6lcYEzM|=N(cc6<9-?pwvGixXF={2 zxj#6q=42-0p}8iQs9y)9&04Io(`C#oj;gM^h{?qX?$cY}S#O%I$|=1hT%V0NwJl`MiP{ z-MUaSI{v1&$k;Fi#dzGgdJ;>#xJtI{i6f}c6~W3SU&6(LWFVOsXNYHaA#6H!$1Ax1P_@8<#nT7Jsc_2GTW1AOl}$pd`9 zY}9-H;30J3%SZekeETp_AI(9uz_k;_^+GxLd#cQhDojYnQw-WJAM%ay?oVAVTJCGrslH~XJmqB24~7ku zX^U3#gq>GE7{mWDSRAr@FLzY1?+7%9rLxBD$z{uJp}W&$ zcB`8Yv@!0TO;KQk44_RXrqS$ec`+Y3I(ynDk=CaXgHdfG%Gt|O2C^Ss-Pd3w8NH&x#93h!0A!rs8?4$=nx z9jE$6tFMJ*%ofAk`Tg0pz?+_`*0W~bp@)}}I@(A!blrAO^D?U!ff)NN{|R?!U` zB9j)Os@^@!BP1Bb1I4=HB~<5mfsZpUahxB< zU^<|Rf3r#KN!IHD$gtJ3aS6T^?1hjpub(70y zst;)}X*#wfTV1dy{2U518%c`Zqt^%1w6`{#ArPEC3jtaOaMy;VPw|pu&xe-&(^uDy z>0Gd*1~86hMC<>Yp2FMvj$4&&7klx52hwAGY4!Gnp&-|5yIiC@wS51TgVp#5#ue9Y z(DmyaGcb-B4en;|>r0*3<4uVjk?sM*i=4&7hM+hyZKTf7ju-0(8y<3#RiTanyn!*t zW?8(=wgX2@LK;iWzOnX5U_mH|T-*6-UV3!^sO@F?XW&7n9rq?AdhIvv9^e_Js0Z;> zbC2iB-ry{WQ=%qJD5ks0)7WQwK}kNOT@70Sdwjl&%5-&0h3tH4$K{OXVC`GF8mF!0 zsKsgldMmmYb5j>wi6+4oZy1K=3-O3H--*Ad0T8`A_;-FG_Th_T`!PoDnwjFt~X=u0v7ca+Hx-#z_X zLZ0_GG_gxtCV3KBpZXYoh_h{22g0c7KC^-Vv%EYGS?Y}6n09d{?k2TULRFjC9=N85 zl!tkGx!I(w!crV!v^;KJAt=uwUFp7kkk44y&w*X<+03*AePi~wZ~x$E8z7xB!_Q3~ zmd`HN|4n55@4r+leFtk1H@kmjjr^}4?SJa)0+p4|88EC5d^Gh|4f@1%^lA12R6#*W zfffjbuObFBg5cjsX?U0Lh^m*2T!89>H9L=|omvJy)H_?NoA_i)aY#kII@M*|5?_Wd( zNfh^E9T7G!`C4{==-^`ow98Xrm!^!EqtC%SMO*C#CWTv>(Sj_#k+O$A68Q0=*x9C#M3iMRE2yCF&~qn<^#Yprx^!m!~3zQRl?w+)1PK z{rR|wK{cuQoi5m$4mdl2!3LGxEBaX*7jyTN;7=ZLTKe~(9d=Z0(m4&s*ahX}3?nE> zJBBlSgZZ_kPb8r(N}L>NR3BFj2WiQRTGlQTUXekQJ95)II%OwjaGTOp<&SaZ-LRjK z9%PMd+MRX;3Wnx%Cld-3VGzcGO!x^6BtA@r zO5bdu0wj1d`3?n?4h--FQm5y|#)WXohv+>Pqpu^}iHo2rHwaFY(IS{}a1#M9(Oz2= zjn7DaxJe1ibJ5EE!a=%6>~S&5T2VB;;E+Lv|)q*+p?f-b|JZN&3Yaf1o`3dnFRa-|;L zrhe+<1(7mx{aD67a8N=V@;Vh4h7yCOj~UC>&>mh3vj>wWOp*dshiZ-@7+!wHD+kGy zlkq4o%aO)G&&TTxgGRELu2N4CjNjY`-|^;^vX1xhb$PgG?R78*69#3JQhtA(70mUY zqP#=MtxVgw)r60sXzcD^OuVF*!>`ciB4oTOE|zY? z!^s8F&Yx#Ucz5LeI0O3`dv0osED4tks*?E2Bf%^rnw!sUt zPv}?PtnrG$u1MMUvG6N~_Tku*~-kQeZi0@;I)93?sYM2q(6jFw>;&Z0G? zm7r0{e1Abj$cXim?j;JxCZmaB>@@Q6 z^gC->A}#DB1Eu2u>Afy6iGaQiZ=mPP3&}=c57zF}45%X96GV;0I$BkM-OF0f#$tLR zt8pVQEyM7QqD6%AkwF zzkQUFht&tI8^$MxiD({}7XGf(u(`>FNEP6IoWj)gKFCgr+*L(teuJXF zFelt-zuEsfpGRdUM59V>)oAiWE$ZdY6HEehLP?QyNzoUnM3HP4xwRT*XF9sGTXoJ` z@h`kH8(IOtJ(U7HS4?3_d8Mc!FE(2bqLG2S*}JltB9J;hhn@fgDQZ|C7MW&kwF-q^ z^hNl4Ro8wKo?6VcJx$;W`^Jpa9v!GS&AkCS{)klCT&_&lj2X3Af~2&hAb~-zD}n;R z2q--=#O7;7i0A8mVNSCT&p9IJze)1f_eE>cn=P(7rtnL!bU>8HLbZ4Xw9+;QFk$CC z{>nMALoc!YyC4TwcZ%PM^wv6?wBsN}X{>Tr92hJ_y~IIblz)k`Mh2m9!_31Yvr;tK zSQX85R3JGkpsK{SRcKUC(l_O3fJTV72dzwt!ZXx$jmwt*Y|R)R%xuDVP$3UjCA^^U{OlAbZn2 zxeYh!>-oiZIn{%1&C8b|+Qq6Dufgj6fJg(~MR=YIZ>lu&icY@qv4)no#_#&k>8tjE z;JFDlLSGA_b-*K?cxN1gOz>HmafGJvwV#4?u~d(i)Y&|{fOhkGqkv%u@K=0aKjf7t zwW+1$H}5+(t)4a|3@2#c9~`Xrq=G$64nt;K=;P->a7)t%Td_Zj>9EXvL7h6R#w^p_ zKeX(i1KP|cOmHb?i|Ua zzYvj3sFK!1EZNbbMGU8{eiC8hHH%Ih!R^z!DfgImDV-{3WL#;+!FA?$>GoW2yCh-+ zWHn7S%XuOpYgnTmeQ_tmM2`9W7vW=ylB*^9JTm6osQ&?RMHWydGOn4Fh zYr9mId0@%(L~K7?)^Es-Y0jt6Dc{0oJ!%W2JF zD3*yi>>+O3SJHLo{s*Z=di+*FN*0OEhsXAz-DqE5ADB&6K7+^G^^Tg(wvpP>wf%kR zTKqFxeL?OMse&K*jR=xmG7!(i+gHe;OwkB2~Yrf{UI|nb*0O1Rum*qCeyK z-CL9zSLIwI30SpjX&d0Bu;6CXtiWSDS{zrj!WQexu<-T~2d-KmxE?4NwKbI#MSg0) z(I|6(>cY~_IMkuw`Rh^O6cQWXjVX$Eaf}Gs1BFkBY@RnUxdsWgXG5-q_&w%0 z%6_3yI(f{ETKUYtENxVZW0)v*xW87WU5J=rWNH>Bo6gJrLZSkE0~L`)SV`%rnqF*& z!`~24Vf1K1E=-@t&6;H*ZcF;;%z#>JG*q#oFRvIxM{}JJlo7EbzkMjcAY|J|fEZqE zCLn*umt+^m#jj#^c$xY%9OTY{KSZ4YdxM-y2sF+>xS1M?S+>!WI7F(GuM>n^W`@Uo zQ5@gt^kppI+h|x~8 zK_@HNW4$*6&XBfnYC?0Ek@XpO>v~o4*63vI7-9;i(Um_1j*{Z^?jOmA6q3ctvUKhS zd4t3EJ8_0WV#4V;TZaZ>FogZ8wpxEiFgeWucq)LzMrK&+g9sqrJ36_{=5{stD-6g?H_;Gf;%qstFL7rHoVi+Qlm;VwP%Ck~D^#w4`YZ=6{f{ zdZKr#IUB2Q%`FN$pD0tFS^zVm(y&2_7AFLyZQfZ340&N9TaKa6MB3ukeXS#6rHRb0 z6v9_nE)XJZrOQ3obDXz1B)hlXwz-tvEr*@bMf4ub9-^~li&wlIj9%go>Oa0M$kqqt z%ADn+llmo{UWC*pmPb#xlzZd1Cwt*hJ-cyUBWUJgo|EFV{CHJ6N|6G7%rL*gR2&8C z5sPL>Ux7s>faR-5dLfA>4S{BSL#lQh;j~<&2*>VbB&d zRnjwQ+3)07MPJtRkV*sAYNmG>>rk`hpzHb!Z5;rKQ zsd_*b-d zDOIkJA7j*4=HQQ`>Xx7o%*u`9aG?nNSQRSKBV|G1%5mXA#S@DBH5IM?V;I&yFjqKU zbW(8^$NGV)T9)EVt`qzs;aqFLk2BKmL*n_#@|onvA|a_}16W3@y@)t*I{C9vlhwG{ zXq^l-$-NSr+<4tcw>j^j&pSZ8{%nW~hG&kC$iBzmFMNXv6yIkzeoQHh|I;&$G$6A* z`)oj9elkSh{|s{fm00oL09WNd$BHT?)NzuMo;9^BSJcTFa2rd!C16$4f0D<2h5Q~_ z>{i#(-P<{S4&{vZwE1CIo_#F#ii&5C$A1*TFUbQ;PvH8I6QAn&@R^X~IN?6gLizFf zvO@T!a!U$y0R)#m>vTxAXewg|Ys8BF@L7;EG&BK!O(&Zmk(uZ+;9%kMma zHWZ&|q1!-qm62jZAMWZjfg77!C@0^5;nB%eZ`B7F3sVpN(ENpRvz!IFElSQA}EyNC&>gn&W+Xo5x?(K++PCHR$9jc z&E*Z6o$?JKg#dj+PL-P?AT(N%jC&fV^^uO!ZR7U1ekr#^hoU-IfDad;*?qXXHy4i!#t-f)Rf-j*U4&gbB;JA>;QxIK!jl8w(dr?L{~j!_m_wW`j7SRIsM%zj zH*+L2TCvaqS1DgqgmmZpMWMi=zk8kx&JAcl6y`ahV9#r?2_^L0?4AD`Yi~nHf0!`! zW7fOa0KI_BMn7Wf+K2X7w9M64P(91&)dk&k9#-%itKW^wJErfgaQ75^Rbtya!CV(v z_#t8I-9AhI?&%t5D0pUm&9wd+jdtOP7akH#LV2%z7;j0)lRZ8G2}3{0mt3l1JL~ic zr*N0$FhRR7BCvxHqs(+zp1<825$4<-Dk6;Y&seVyYGhDLOmM}I0l_&VBnjM8bNGE5 zV7&(MVRim)sLD&~is!)4F~*n~JhGB{!G&!sXt>gR9XelFdL+H2l#GrINfzgkGjM^% zJZ7U4+tylfD~goHeeOksbGD{-b-`U&ZeAMn)auHOn>~hL7Y%civi4H0I{U4eJ#($; zgG(6ijysEgv(&{H^MV#MGQ>gZXE7sk`rzZA{HtZeig#lWoKCPX@+ZI6;xSo=@CiOu zTY_*zGe-q-6-Umwq65?4crh1yq4%cP-}2BulSLi0a}G9?oQAQ<70J?zVDCwoxTRAT zBv?Q`(kM*`1`B>+$N`J_ZT!eV{Q5Bb@sRE(foL!Pu*hyST16y2N!!`yR^Q=C%$y<>?OVKN8npRda9_dr9ye=!OexHNWBNH6SJX{< zC41jz++;G`taS0eLTqC38M@tGZjC>_{Sa07JPM5v0Wqgdgeo5%q^PS@?xhg@Elfk! zCBRafiIejHouzcb-nr*H=AUkH*=cD4*aVZj&sE9s6}&!+*Zf??a+IorgV8imkcdr6 zza;1}C#Nqs3IIvq){WI3KTw-yU?*rsz?dq3K{X5>ozsVDkdl-CR5V(GV|e38gVYl z`d=bSG}hC#-P4-V-LjdOBG?9AZXF}rf^!@*Q}x@a-xWmES{hA))&M%V99Xiz7NAK< zak_S|B_Qh=t*@X$O*FuRU+4iu4}#Y!O&COdbD~?&OgFB=6bpDGs;O#V&TrIai^LEF ztN^bW>oZ4B+)qBC((W=Tf(p@{n0TeZ zANM5Y4UL?%6$O{j8Zaq;tMzbR)!_1jR4mgK9TpZ8z%Wd+Mb$@Jx7wW|A0USm~BHFXg2ukDk0jd&oMw0KSs}7!vd(>+;mbL#LmEYcLbn56`dzi zQ6B9^DDnejDKp1AHiM81jcV9Nu`rqV^071v<5B57YoHBvPf-K(AQ}}mt@pAbPDo~= zadn+w4-mI_Fr}?q!zXR8VZ~TP&i}Ta&FH8dN6q@VQ2dd*wwLed*-Av z>LOe(D=}>iK{>wO-|*v9qX`c*C0@s=qs|j-G;_^kmp4V>E9D9Xl#M!uf5o*6f6Coe zw^(Mmj#bZb1KID1rX0Ad&!Kc7XtV8yXhBoK37Gm!@EqVO!@p7>MS?sYZ}2)e zJuY4poxuS(`U1J;PT}H}J&%Yin`AAr9V-ma(_gew9GV04o<7d7&}ElJ<{lOP>B4gg zBFSfI+Wy)Dh@N~ZBA#5#v$(p0XK?4rm+PN54&mX!t{|{IOleZ&^xiReNiJ)rW}fqc z>%Zq!L&zPP*2mXOq7l(#z?blT7C%nO5j)5`0-1J&vYzV!c(6a)d?Oy}PUI zHhl4B^QF{oFyb}{DqSL1aAyV3>znDZomSe%$OvYSUjrMY?I$<|ffXAP$M>i5Fvmv!`2{FCRkQmI6-e4_LQ{Fg7n|3jW<>|$I&7B z&pjTjk4#i`>2D(4@F5kVrNm_AKP$wiRJ*0fa=*?O))xei!+y7NnO#FzFYVxQeV$9c z7b#+BUruFTG&z1WGF?6*{B#QLxzm5jS8wMdd3M%q?74QXJh^;49xMcZS?^5-=&iM| zFxk=ajNOUo8}|n2^WsJYIdgwneCODW7?Vrb0$yS%{%!t&H>;5+H-dUj@SH%Nl)XY) zgRNI>o}nB2z9EiEB)lE2BQEf=`z3#KR6_|4`W#fl-%S^Gw!V6gE~HpOb~E%GtsI6a z{##_3RdiUN&LE`Y;PhHMg@Uxqr16A3ts$HkE`}6{URLj6_)Kbbt0lIG84?V%582tz z7O&;FJg@|r;|Yg@WpEOUFoq_Zbkdu6sp&u`OWOAc?_J}_IWt?kdmWLvF_lA)J(-cPq!HaE^2hk6F-YS}zNgdBsJ1WQ&Oeorzy0 zNRxpB9Fws~)|0=KC)7|xIup9SVcES|Suc*^|4Vnog6i%b8jp{Y( zh12T* zS)1*nkr~Mo!0TB7yy)Qs`GbKL3WG5K%v2CSXHtgOZ88u@YtRQFhn&2 zE?0w|IHR;7C`6+Lya;@Aa)z5HtQps;?4=2WC^5t&ENA_ zouP(|9Ts)gvX$gb>PlKi@5ge50Ok)n-|jNqbYl+{KkU!(h`; zblBKX`a$EWE<%t!%91IHS6JndwZUkewPf1-^8GpQ&|26}|H7l$-!x_UX-;}HOUW+M zZ`zTk)(2z_BDM4e2L?1pX(@Z90&vo)`%rg+R?F=QAIo1Y&2z0z!ZF=CuPZ6&q&VKC zG3XDMXWI*Er)Eip$lv@rL_O1%>emaKu#U~3S;c0LFz~3h!Uz3a8{2JM_&uoHnRK8%Nd-jlG=w!br6DGclye1=$ z;7VxpU{jl~$~Qc>;)4Z=Y9&q|v#2NLJOdyzEt$mW(dfgOWhv(LeC#z#STiC1inXDc z388W`3P5HJf;Dr5q=#(c-fn93+auwGEYVgFR+i>N?VAX}TsadK~qTrzG@0B;IRk$!J4J^%0JlYPBVx02x zrt`DGoP@Uhci4rMNAE+1j4zwL@hKJhhJC<29@0vuc!q{ts{$4ru;NKua;vdOz-`SK=E zBk7cu8^7so_EnhVk%|1rUCY`x*OiJ%UM#YWZE9=|lNy8%AQ6|FFJs;d=2l z&hX*-H1vfp42T_t&%3Pi;wA4RPviY58y* zh0`;&T@rf$Z}~z$$KBH2=M@z#(aom z*m7DVt_8dGcTW=N2!Yd3^0}B*R8=Do7tRL%x1_{sUukT4AM(wE>}5KUV04W; zAmNNL8x1vGSbikC>swYnd2JiaE@*PUDMTXK^5$4{uz+@#`-kA5571e#JRaZ~np;2( znD6`n*_>qT-d#2GNPu_>_kRUh|YKkiN|k9}&sxGcB_?O{$yGWv`-?8wV zqdWy#tw8+-`1DpvUyEKp;)I4jxiw;iWORwcq`pitDWXwPhz{ONwX%40`9(OAL~BMZ zii~x?A6uB&sF|@RTCIm$7fz!YtcWWI9f>9j^WANJTCZwzJ_S1R6%n+x9?fvt7y(=1 zET=eSRe(9>bSz3?=!CCMmP=Z|5o%4aVdHm<*>cJIo}(|VBDY3Hm?N4&*;>X6e<07$ zriTPxAGh|ew~0NoAz19Pz>5xdUqK1uFCsj>OLW){X?ZihNq`hoqNH`7Y4uFqeig3l zHFMO=h6my#P#67CnM}MqUMWKOQ!y~90WKym+gGJQd891zq$Hvj5c6D^Y!n7Od3M&y z#^yH7qQb(QCO0#anC51p^@AcjNeazc>9$Zm&~mh3Aw-UBB=Sf}2*NF#)Cj6CssmCt z5^uDr|LVA>050HH??tscE8tkt3(n9nM_xF8C%>4bp} zNp7C@+f)x+3TW>nyd?W6?IUIc1UVW2p2>0Akj!lz`~j2KIavmaE^WG{J9r-zCE}x& z1YWZJ_HIv@Ym+7ga8YvxpQS?x+zIR$tQkL8U1U9zA!$p+N zSR{x#9%(uU(Ne2c%=Mz_k6_2c4^Dr*QkXZ?-v?&iws*(GOM+ut?B88xoX&&-ajsU} zVwGg+tFsS)o%osNELo`bX)7PBO&{Rlwfl0QndW5S_V!Ibwq#are91fjiYX^efW)|D z$V|SPaC__Kh!4E^^Ki{gH0$9DiLM?aLmGF17DGDgX?qAfo@$%$;_dcK2w_NbKMMT| zuc5mq2aPKQNkHxLSd|QjC#-eKEf~EiOQ0=qy_1UIXiep}o(F#31sU&}P*;S{8bP|b6M5d7(*K*%B6Dsvn>6s=UL17L!;Y=wUn#x$r{@Q`|=>~DWfUoqzj_L zva_C6b@Lq3Mje&2a<0h|ArhHrz?D5pAOQPJ3bfx3_l^+@g#dC8z ze`s(8`IJ`Fo4rzO@vVY+UTyrS2@M96AO*ozCZEYBF&enG*W8cbPyu=nfHftig~RG+ zS*QX%2thd&>mb+QXGJI#rXiGSx?4nesh>6)7baSwTCAFe3=|)%t1)iNY0L?_!>SQX zlVw{d>29onLl0V%T-bVd5pBtQYpx$zmdyd;Y06gjPGcWmc0Wr}9}O+cTVmO8MZ5ou zi{+vs-|6z`PZ87&qNy7Rud-3l1;5^t5}td{v1^d1jg-MQ+`x|)He4Sr^@CD+Cz)+- ziHw@7Ao>YYXB)Wi&7{*)Sim=4o0<~nI^TJF`+L1NRUif6U}&+){mcUwVnQ}l%FazA(S-x?NWA{ zshcpBMI$YZ#kt5CR(tNYv%WX&^-81ED~baVdaEXjhsrq%-UQ8|usV)3>QBm?%)6%t zoK~z1#ssstQ2MDiOiPOrI^q&b+oE$B$0~0bG~|TLu6i}btV%Uax#2#q2g89Wg`O(4 z^)}sbjv;k&SA9-4q6qj|v$(ClZ4TPPbdYQD{^VkKS1#^HF0hXJmKo(`(c<%1^y1_) zTPszi7p_)v>A3vvl>S_YRRZ_n)4a)olf-` zE}}SZX`>xuSaQ%ZH&J`Ya`bt4o!~uKE$i~Wy8{36a*5KnTOeh+qH8Czdzcc3=hV=a zD@317nKH*D@J zJ;Z@-%}pgH0i0E>B^({xVP&c`QWh)-ZPf8}x$v-xKH2tQgsP!T92ZX9scG)Di}{Nb zF__@?oe_s{Sa{y)S6)B(bpIwSCnuH~Ggu||X#PZ*M|Z^8ov>1t zgkf&%1^g&-qm^BNx|>xtzWyMmD9qA8H8Z`L>V9$ga0hj*Ve{4n$(}3?2UbX5U09N| z1*yN{aWZnxPp~PNL^aJHiGSiscp;#I*2)!&uURO@;H4BE-k$la+|dDo7mEN#y?*u> zG46B?W7O4B2I-B(3Wii}hzfk`pn67uCc1 zp|CjFLs)UY0C4sqOlMKALvkRtD3E~UjFF(}>jt6Re~x_ye`91GmnBlobJ4#z1C zQPy2tjA{RP06qNo<`-mLP9&v0OM7_o<{vj5?Q~*%Wn62xzl6j!|`lP%^ zxL}l$)3dH7FjZo0G;9#>Co4)Sjvb}3`H3bAm%>;_6cvS}@vrf&iMBv`{z%zajU>6u zvz0}+YyP#5-VS!2%}kP&<~-uKIj3ft+GyQjq^rF@rpeOPvj;L_dpDAn3{g@Ga*9wh zRW4#O7+{Wt$r+_ip-_DTFWQ2}OLd;E$&q80&&V!*Zd_=-3-Km2!Rt8NbAlY3OeExDCu83<(Fgy0TZUgvhy$c+Sw!N}3q*u;spc`8MRSDdbG zxqt4&j3q4D7KF*UncMGlP=F}9|8gAz|wQpB@2S22X8+ygto)cJT*9;Gww5c z9*({0@niD|gYemFb3_;UU|Q%lC)D@ES(gI7*L9Dx#`S?wd0Qv-CJSb^1-V^QWL&b% z@5l{tUBBL->i3byc89%uW$eGYe*D%(dR^$~A>nauFp8`Dg$m`IG#AE2?t(GJ|2tCW zi8xv?y6#Qv_TJy~7*%r79vza5^(7P11K<)XVV!(2eaI8uchjoJyb1NwjJ*m>Cu0@m>yplcWPJsG0p!G(6!^2`nl^d1L zo6lec!5DWZLw@QR`iOo73HiN=%|ZH8{Fmy25Gh3a)K5n$-J^lmTClrt9#;d71ZWOw zJKHVdN-YAv=>r#trLrJ4Gjdn_q6gJa{<{0z?jtvjMcaRP%XKAk7)r;j*g&l@5q*0m zl!Ugl=03A7E*Z}0%n_gBY+UvuYy8I0+6P-3D4!_xO& z42Wom$hsv-<&@fir&>*GpxPf^bxrf$6hlV(u&VBg=&3V0-H{3^i$#ak!kOaKUkLQG zjjr3$=|542^7*!Bu<@A3429SlI7)w34?=((my!D&1HOuwieKCkyu5di#ezqA=EsJ0sc- zk~z)xG!iB+8}N*IUc-4s$>+o988Np{3^)Yo_NAYFtz@PVaD}$3`*wx+0(ti?xXtr| zrgFx*_VeQp;v09vuHO#D%jc%05zgN0tIsnNXW@7qqeK`fo7u&K@ zzU;VTs#q_M8}5Et4aFATjWVk`cQ7>rrfO1JbdxDEq0P+P2SKa;{UsU{XpE!UTen6-#)I4kv)$EoU2t4PT?c66jo-OPA6S7n{FyTp?ot0(;X;{=(K&23zDX5WU2A;H=5WqB*JoU3rfHrL zBc$xReq27_wQ^nUC-Ff2inb?$%ac?cxxI~(Df0*gI)J?(bZeC&*vpFECOAu|fo#Jv zBmohCFT!$Q9f&tUM6uqF0U)Dh#`>1*oD1jVKxpcPd7%VvkZNo6_04)C zJ3S(q(8VCbqxaH;c4zk`%KL*sS40O__f=nOKI~|21gep^jRbbJkI`$d^1GsRe?Z_K ze#&9U7}vB3!VQrXEH$#K0GX(kI6Mm=bJ!)?TBOe!reMf?KnU1oyXZR0~LJU>C4AdU2wAq+nUeG*P<%J5E1dAxH9=eyV1p@U9ArykVefb3tUP5V$;|ooR@Fu#wO5b2MePcJ_B%kD>@Q zK1!X8!rAgnMcV4m;&0-8e?KHp3VCUE0luTvcI=1^a!%JQc)Nw9JTpJssc(`bC@WRi zUxc<(qC^rHaYYL z54BTz$;`CEWmal9R}^xk_91rXoOA+;G*J$2Ki2GlZLlJOFZBniS^HqiipcEG;lGh2 zf+p@?rLybkR=;ha@K0&Z@*?fa+a=D`lq*CMg_2gH~@_sFyJO zw5PF3#Z`<|74D-8K7u?sk{OJe(rnhA1R4i$-8!PjuLssOmXqqW209>3_>elns&)vG z)ln-l>s@CZ&F^MfA4I&fx-$PTF$Lk3WrTKA~gx_{odaa!-+iMi*4G_Bl(LHy8WPQ)F8u1Irw1 ze9VZd^H;p3zKZiCUsmLV;uOO4T5xgnp0d}7yRR{X*$^_iM45YtK1dXP-xh(cO!kPTrZ)H_&ao8;#>@HktBU5Af{EGXA{Fz(I zxM(^#U*i%}ia2e(5Ik%hBK1Wc*hF&6SS<-e(i(M zzB-{jJ5^G_I`KWTBvD`G^>=7t?|avpB;v1gZNgu|jRxsSegtB*=;k8+)>dtW(e{2u zhPI70MI+lJ-Xjx$FI)+0+ZLpQ!Yt{t5)E9l2?f$WIkuam&je8 zIo}7Puh3UCam~^jAM)-_d%LXlJ2=a4!5jP^!6J`Q@BZzfdJCW9`NK#?m2NKmLC;s8 zc_Fgp{`AqEoReo5B|Bt|D@$|*grDiQ4{hYhzd-1j67HhB0Fsvv=QcX~tj?_3CpvrR zUKlriZmOg|L)g`%ySG&mXq*_gt2ANyRmyBLy4XC@7NEgS@CFEeeb`k<%p!pl{8#Kl zI^+2nBiQ7n1tuJL|HH-F#n$Mb`ow?p42f!!8vj_m^n96|)0DO7&|)k}SBS}Esee)n zSwo7EP%D177u}bo_=c4-7Qu>2H)w?EspEF2tUDJ;yB0`rZO_MWGM$L~fqyMOpolip zn;Oq)chUCHCfNC6`%g;&|EIUdljDRRm+coJVER zD?U@UfDkHMGY}V5ISVQrY(Vtr>yJ}mmd$+FO&Tg<^YX{&5!x$Ta%!ZyX4RHm$}9jB zYsW!yRTRMet=?tJH10<`L4;67opjW|pv!MoK#ZSV5K(Na7e3$DJKo; zH}7Bf;knmG@o%D^NdS?jCxtY)r7biHhl?!-u*F7_1W|zl>kkk^cQ3aTL?MgdYCLUIfg{`=|>8%5^ zEn3+7C54W_BagdP!hN3s$R$?Ps34R2=R+I7=gdjFWjS;o##4b@N)=OLv~O2m&p=i6yHBBqzSeH)Fzc9+56*%NwE$ToSTd z<_!KVn~4YmqT-Kqz>L(3R5wvh^Q0n{vhqFJ8x{y@hQ!t&CFiCX-K9WjK6?vzu3sNZ zbWwinSz4krC^h4N7@ZbZx7tj)V`FUYiqzLt1b9$z#IGwFwF0>LXzWf}G(ysjX6#qm zr1}a`iW>{u=q#&zeVN=^+DAo_-TeNUypFpKxba)a>nkV?R2H_K9^ zQ>bNHvS8@Ai%Qfkt)`w~S_8TRyCW|YKjS5q13);VrGfmS0676&dM48c^YxMT2{+f8 zS5sWZ2-K8Vp)CGljIBYkX+VsOgBTg;S4kMgCq`0(=@Bszm>c*4B=sTnnjSQlr}CN( zh`VRct%$W>MRmRqR*oBOlccJM-M^2*&mTEj7xKgA9Cf#PffaA_A*2V9nd>v`;*&Rp zm$M{Fo^P$Qm}c!bJ}?I67_Y<>AV!~1xxfx{wA3sYOZoOluoH?d#Iu|OnE#} zJQ?bnTz9pyYhjP_w80yv3%v@7kV7p zA`!64jmFRp^5r{{dTI*+k|PUK&bU@$=y$n14)R(}?{VjNN(|u z(687dUOOgYCj(lVJcO4o0+TNuuZx0R9}rs@>R7&On|?ZPdYATI8jrd@dQD!fC9D3J zJPZmM-Bs>F8Zmq*m0LAL`yA1<_l?zVyPcS)H~bd^y>p<7ut885>sGUohMiNob>0cm z=4l%P?7b)&DlKd&YaOTAf$1F~+)u!X5h9@+#Ep*z&R$k4)J2~ z0k$ix6k9cixfQ(Q{1$$0xD?LW_5@C=MU3X6XUA7Q;|L5T5VBwu$*KDb(Oomci}agk z<@~@INl{k{7-p(f(qIBHxuD1uI0ZM8Zv!1k>`bpY-?+9rjjy)RUE&NfM1>{F@SWU9#!m&zH6YXXKg*lv1_8M_>1`yQq_kvG_cAXA2(#*4LO-b zr4UIh%lYL%C88FRwSN!l^=)=*P5yerG3?<+aCZkaqG^0wM7E$gHrMeAS0F3tYdkzz zb8YI5eB0fZ{`=pK`$#v`7nOqjfnVrR4=~XRKl&aWTWpfX9m&Of`15kkN6}SAsvJbFO}Ba1%p+5SHa zl=`nfT27Sxze5W-l~r{#{%^RVkti@^u zh0s}$rRJZrg}Y9h_zBO*@y?-1pvcNW> zCXG*(yTqU-h3p9g-%Kjn6H;4Ml+?i13`ug;I!lYz9m~Sl$~1I&*Yr~z2QF?6bjpfK z$GcdSGM><}+FV|~#A@{!wSH+Uhyfdyt0b_bpZ~|Ce&sO__Cm`!5)JlOu!Y0yDiV#$MSYyC`#^o zLXM4`riQUDv-)1@UmOix2suE>TS(frqnD;q%Pwf7rO6=;I}OM#;&jO*nt$Pe%v|3` z^xc@tg1QkTfv!QFmH@gE9Z|`$u|#hvUu?EYyC}`5@SCP!PyDw3&9X!`e?-%B>{((9 z(dEN$FGRCKnO)EzWP2tj2&$f0hu_cv;v8^UZtpgLL+m%@CEsU}5t;*e$r7@cu4Y|u z(lm*b*os+4GC^|jGRX|H$LMR}fP5LmjR{s3xu+P=*6z~SjxRg?`OGjdwO_YhTbCX{ zOoE*2+f9U@NDe`W5>^-98u(*eS*O#epQ!M^F?xN&o9%p71EplE31L9 zU#rfIGlogOAn5`9F+EHogSLAelr&AR@FLxr{82llHUjD+JehrifC>zVR;c8I3iJ3! zQDYwyp8#Z_|L=Qir$H8km4}Ilv5p#;=0SV$kq@syk!^v?K_;LB@InNt8lFoiVzzmV zIvPZ5m*44A&sS)e(&x-2cjpd_bLLtsREidi>J%H>@fY-P%AtYxR}@7PLHCwcH(P8) zl0P;h8&zzt@EG5kZLmyT70dPmqC#A%grS!UbxbFUQ{9?PeYb1fJ$mAHf9%odLZ}A090UYfv}T zhsqEzcuCrl`SpK~CY)I+(67JG*kK& z)|N5|+FJj`Se)#@22OiKHatxDE}LhP&QKrnOLe_kE;sb+DQ!K5B!X=BI?zT^0NXd@ zdwlS(2H1LNwrq;qx-Xu{O1H?bFq)Jh9hxM1K_Tcnb3(YCxsR7H+g>A&5Si}cnu5ep z`u0(ZBs~UV@Bdn2P!zXpuE5|S8a!$w|6}kVYv(2l4zIH{@=!5xcDArJbNcUNXHx+@ zcHV7KjWE`d8lAuMK9inm8KD5m^U!`YLM_CBorxT1%&_Yz@K|`fwfIzN10cQo>cKaN z^m>6i14G6_E%Lb{^_7?R%o?LMf9V8>FlV33r|V3oPOpja&5!p6_$`J`gGUD|E6=SL z=Tuy)UOm}wg^>l$6gFImr4|mG&S%#BnrLKhLFCPpk}bU*{aU5Grwil{)$rQ z>Q1P;vs;N{Jw*C@tr2Ov{kiB;t)oLJhhHQGuQbjN_s$P@g?{E=j3mdo*cXw$$;vS8 zQFnG)f(?oq6;O*;rJf;%$Koaq5v$=z_IJU(j6Aqv7x1e~8OWV>E2A4joqFPNIUb2s zPU}1OwE~)Y=s?Cie_|)B^?ILe1_u#$1DK9026<8uP_;$6ZxnHkt8W=mP$8Nz72vRR z?XHjN;i+6i0H82W^3)R5Qk-0oc7;EvKYeqzUi^a-fmxNWw4DXH{Lms5t_nnW^6EE= zT%??1o&!PxjT=FZnwvH|^=`2+uy|L~y$+wi9OtdT!)e)b2gy9f2obNNxp|P&WfPaU zP8_1w=kU+z8^lNnwrQfn355CZU;(4smzvSmH?N}FHL({}nvrKV>a!OjDv0nweq(>K z5*V6Q=~FKD9?M0JVcVLcPl_I4R04mlT${J_634);L0b zsQLWAvPe}41-SL20uSPlCM_T(<#B88@yQFC8%Qx*$q4_x^ofF;lOijM>)!Ln9REmh z`!T%T0`-!BZYNK6(XTnC2j-OCPsKt`5@K#a8ZOo&TOFK&Z|bzWPG6*l+%`-qcPc@`0My+oJFo}bk1BQZl-8+D~t@+ zabtEQqkvH{>wNNuF|R8BeCsT`9=v`v5TgWlIdKuD*IrIZIuZ@F`}Z}nLTE8=W$Wkp zPe#ZTSIFt}&V#eO7RhLQk`|OCy;LOwuv&;v+ss$;IH`$ARWQ$#f~BXQI5LkfL&&s# zc;zRS%p%p?!eEkWX~VQceySo3C8$j&$~_F(^T=KP^*Nqv?K^AZ&^u+oV=AAo5Unp| z)uH(yVY4t*C>5yB?|%)HaI%6HLjVI94De}0{6C&5ss@f`CeGp}2F~D}M9#qef0!x% z^w+#sLSQTwhp3s;tE-fy$5b2IAbcqyLxT+@jGJSdL3FD7ClIG?eO-|?lP7cHR`4kO z+uQXHZReLF*9?K>)OV!C(V>m7${H{gllG_mgY{_X5kSYRFJ^S1b6dn?gt2W=E{qdq^~mtqS8D;o&NYiT^m!zxwR#5+95CC0m}ynR?elZy0A{G%&*-jY8*NAY8 z#-yt?a4+5)ny9%IYp_-gGSl1$OSAQj40F*%Em`v&P7Kv!mm4kD2QZ@hybMREmBesv z67}0ZeIG>O0fUm6mOy#nZr?>jCb19cgEiLWRz^e}*CZ0fI-Q$)ze0A7Sm;C%=xCs= z^PT@|=xtCMeXqM<^|3*7hn?ncRn^5j<<^%3^tUaIP1Ecw+~iXKUWGEU@c9KAcJoi#!sF#2aV_`w!@Oo=-~ul z4Ijtv1pGwPC_mhK^)i<1`$JopCX;-o*RGz4MI8lIvb7xB{V0%Cn#m%Tq4dSwwt~qf z(a3YRg|TtO&jg^kU5c7Q5l=*TF!rd zP1gv^S6c;Nl2DB}m^!=X_$S6qD$I+t~nTuP&(;rfJAu~=PEa{ORm!>iNB8ii@ z7piB0u6%f+W(xU3XBAluT9a)w_vNlp1!eCQoPznK-!OTj@gzlrQ_P;THqxh%D|b`r z({1dHq45gGzYVe$8i7lG^4re#337k%>GQo%K5#3nN%bT&P8lPsl<_esPMeqh(oP5r z7ASigpeCO-D@$0D-UB#2-%xc$$Xcou2a8$`C6fw`LgfH+*UK_G5gjqUB5ouUZ_5JM zVL|!e$gwdPhr*>7l=TijWK-&z?*xY@kGVf2N}9J{sO2aO9Xwsz(e?SKhwf;#B&J%$ zu!BMZSWyy@2Aht20a78HP}*39b7VRNnW6=hLQUCLPODqSpED6qcwz7Pa_*)=1$yy` zkI5WZC2j?XEV*N8kp?*XbP(_#Azyl`< zoEP~0|8n3+*_zt@d(;$wv$xh%!SDqWCVzECUAq*$p0;uHov5Hbs5Yea=jaMO_#!LT z-?rR_lqSa_g%KX*Gd1yekY^XQ(Dg|lW599{x@h7k+%MMMb|y%xHQ~hgfP(ul>+<#a zqQwuqoBDjhtnR()KVO~wo!uX%(?wmbY)w^|Y*dnBtAPjF>om|l4%0;egBR+5z{^-i zeJ9;*x?aOhKX7F2R+Q#|u7Gw;3KwF)#K->EY5gL8`RYG4gaK;XU~V#?XQR`p%#({!ZtX9GG1>`eb~j6)t&&xq6V@>U(WcgJNIE(FE(? z*~iOXhsCb^LqHNr^9dmnI7Y3#2+OY#yZr z-#QB2Cxtn};@yQ#^o$}{V{fd`Mm>V?i24(Mi6 zAf~ApJA(rD$wS}y)qZX$DIk1g1imKOw&2A4A6K}UTIZG+^|Ua(3?r^1C5z*wM4P5w zd+sb7*}#r&R;3JyuD*66rFUF$tYva^YJj5gYG6uDZZjT-YY1_tel86b;!Rl|Q$F?E z8!CSoa(m8>OZ%|>PvSD7(W#ErG;_O!^MRma$ zpjcT8s=aE5pDqy9mV#?u$s23ti8RiWcP3h-^*W}}#SaiP0BzY;(%68%$*S~SLh6}} zQEvOnW)e3krC2?z7aSPv!AX$&c$>c1g8KSfOI!m*Odj(Y!gCg1>=fnAWd=OGxNH1H z1ZSW@EEV+rKLmoO32aTW^{*tBrJH?9=|U7 zeD)byQAQ>!g1kxMBB;`jHbe~{eNT0%U<>^A2$X~7cKB~GcrX=g{!{_Oak0vYRY2OO z=|kk?)`KvxJeXF^dMT0{AY=dTINX#{1BQmsZvJR=+Fb@DT?-xOmTk1E5cuqv#Y%$J5b z;(PQJo4E15!TCfWDa8B*^b|-r!d9?-TP?Pt87Pj@D6Zs*+QNw1ky&{|C-#DuT zI_mz$6{J73Za4Qwa9S)RmS|+?UzvglmU`U};1h2G(toVulr%B0b~gW?a$^eA!MQPu z=)Usqn(cJVKMi+(vj1?!H-I&6laGXQU|#w`1~&j)Qj(NS+W!n+mYA!HTqKn-=OdF& zVKdWggVGd}k8jHIwl$GYq9VupHf3S=h&%G&Xk~y zis{ej8gY0kwWpv)wGCwcCiPTTpjL#f`5+YY7caj4)3_B$JO)*h!^zvUHSUQ9B^P)x zaw`#Zo?jPwE1P|@1OQYC1+x1nm3hqDK^?R^wNpr4!{oKB) z)o!h>K8S&O6A@-g_JrnWxYMdaLx!;H zYn!E_#7K__1k!M{ER(CSap&YhFe2Tr=@Pwh&!)w3uH?gssP9*jIBIzD%-U90-2d>x ze{7yVNd*W(7+)+VFF%jaes;PrW1_8*>lJ9RdO*oY4!|HBg;}k?WZBJ7_2mw3{n;5WLd~m1|F*%L3sO z>pOBP5?9==`7KUf0x4-LQeM_|`bAzL(QO`yi92=I{*FAxhJD&lM@~SeOdmVJC2DEO zb?F43T=`P1?+-N@+m$h+AfL?qdn|pN35?`FUJl=%G%A9M-wd?05FE?qjjx{Z;(hJC0l#IQ7E9T+{fR%zam=PlGu36l7U zAgmj9Z0wa#(9!Q~e@7M2>tmqErV}>$dz?!dH64ncCG%Yqz%tn1zR*joeu0R2I5n zv(I-xu~qA6L);AqCbXmI`Rk$azj8-m{adz$zJrtn<2pwt#i}chw1Ku z{Q>ayzYH`1bkMP^al{U$!!mBb`?fcXKFT~+En&a2em>jOBd|k9lB9q$mqDC`+c?qb z;oUYS!-K^{x@~`VAQ0@x7@YhIj?KB8+1HLxn#4jV->ea$0aEze*3%lAw}Xe+hZj}XmpT`2Wz<$W-{nM*{? zt_+2+)M4I8=%q)F`y=bZlO9dP2Dfrg_Tg4XSE z6UJlT3-+4_J<(XdXJFUB6S8}v$0hRs%KcU}USF4eNE%X}&r!iHmsru061D^(f8^{f z-&gZ2La=Wn#@0T*HI(b^>!hQj$@BnLO%@^1H%C_UJ#gg|JgLme$ZLn}YBR#<6RGTK znVY>JqWddN6}H;HL&ifT&sKuLFDf2b==dKl4gd9`{(nc$|F$%!pSz)&V0`ei8T7Id zHNqqW0K28rC=eKP$*F0mr6G}H(3nRpeRw=pWK+kC%_xE@;c41B+fGj_7u3L}(A#wA zu6%xV?q{)R-?fikzwT()OV;>KN$ryLcqd1*i;l_5jhD4epRA|rWJbGB&CrWjm3l3X zg)hfPM2ieCb!c)D4LRl{rJ9MQw)PrLW5)e7ursT@NNdQ(bWW5di9xPCC2ASwo*}qV zlA>jxVYn&^mv6f<3qFL4LyH$#x`L{#0Obg{Rbo|TXSeg!)doNPTSu4(A^IQe+Nj@7 zfj=cxUgts>0Q~HRfTc7QIVm*K0ySx$H9G8G`8!zK=KTPB-F3W+%vo9(CTqOyJU$b9 zCoUIDdr|YsfCfNle{t(EoL7idZ|qdbns5dZ2y*nmK#gWExphdlqMa&neK61~ZM8l3 zyGgT~3lUr|AV)KQ{!lq(bf2S_c5K^3Bh;-?Yp2rudm|GYqaxF7IZA`S8??yPNBKj9 zeQDA$43u`s#&XmAq6~gYuyv6qCKcAg{ZZk?#^e;*sXJW+uR}5%6fzJ&&6anE%FUxo zj0uoz=n-b9?McmUJ{M@EY0I6M>BB=K?jmRWca)r4GB0^#X48VZ*tT%DiQnrjZ7%=- zn$Z5LUY%|*3HO_}Io)8r+Fn7;YxrV53!W5+i0*|{v@*Ofn7OPAN4lLJ2iV^J3b8-I z^u-YWu+AXAT4UvbnacQ*uxus`@;%K9YawHjrujibMHkCSN67oQP_)_RhIza+in-6| zDV7WA6ovT-r6jisr0Y;AKxYm415!(f?I6~ zoy7?_TOL5V;b9%V?^0SBZb|z^b1D--A2Rwk@Lqw_wtNzQSRAI#mv2Z)kXuPVF>-Tx zj+*RA@1#mGBLRK5l|q~0OKa9z?}L_FnrDkQ2#e0Ww@+~BeH%}c<`70foTQz^Pm4V( zUK?HdBbt>B$w`(f#o+eEhIbT6n_2`tgA~n-Ac$CsyDDSb0PR`=J$jc9bYbGTe3gB^ zh3dP(J?qd?f*fpAQ}CHVPrB#pRYDl0(5)J5u7QcWGdX0|i;s&1)v#j1W|GN88xl|? zgyn2zT*>yRKyvveoU79)u(Ba!9jgyX9LtqXq-^)ezn#6j`{z%z%c))^nr03I6ZPEK zH70|S;y)+ZC{W35?3932v#;ZWJZ5^@H@uwE=o=A<702RI9H((%%pQdonz<$zEZI4!`>WcHKP}D=F-_=9WWzF&W73!H02S<~>>q!5TkcTRY$wt2y&3mK+ zPvtA`eq+0BSbW3CpX!&VKd)3e3JKE;e7$9n5B3vmLF-obgUE<5VGMdZ7(Ppt#8RBh zZy&)Mt}(`BzptgvUIPfQ1pa(9WNE$UF73BfJ^{Z6>?ullM-#PW73bZ!db?I!uc1F; z<@_}L-1D76sodyemkk0r^aqHPs(e1Gae@Yyirfvj2pfK4_lcH7#|v^ba5wU ze95l~)O;+Vv$H?+WdYV!@UppzgGMf|$2@HUK|S)R&SpT>)vqU5G+B=XxLPCho})q3 zuc;-f&g2d68pP z3)jyrr`J3i?-=8|=BWesh62arZxdhA3RJS%clsxc@h{yxH}nPt@;?ZtSVVj*a>d_; za`HZpZ)2axqNe*~_ozR4C``g#KsJv3WSwW++@?02s-5zMuVeX*aC1N2iLZOm@V0qRZP-nqMMy_4buB$pvAk6>$^&|%ez8O+v>2oGc zt8CfEcis((57^w(L(z?@nr|QEm)Z76f_b=ITS)LEX!Nk#(4!Y*o^hv?X&7F-}eoH|-tze?7(H ze!6Tl2a|h+$p3KwmFz!v`2Ulnzd}RT9_#{qzZfw+*5VjI>ZV}$6C;{LkG4~fg%?MJ z8bGp)G}^Bw2~T^xlB9WF+C~d4ER2GKA{n2MPYfF)oMze^)5v<8qfB9&>dG?fI#YCC z!02=AT=*?j;I8D{`6R2YO*pr)8m8g!0^D=Vzxf1~_P0Hs31;g+*%NM&OiDI!QmbRf@xPfD&vfC`caedy{iIX&^B%~d)JJ`JfN636U{!ul zL(r;$a1YZ0tvRO0=Gh+qc+ZFp(?##{8|~WK9+A z(f1LROT~Ly^Bz>d^}yZQBgQqGkBSg2BGZ{Uo*Mgk5UHeCZ3ls@(9xbV{{qBS+7EFd z^=9mfOH&caEH_lRnH1wCF2aZvpt{t_x(;m!FV7){hHR5{ES0KqPf)30CzVKjP6`y#!C?A4uMFlfRq z9OI1r4{ENnp0Rs1LBz2|X}se6&kR+2=`Z#m@BG}%yo{ysZ{M(=BZdktr=a2l44tgT zB;~OS>BG2j&ZVBOY4lXC;5ucRXoCuJO_mto(&Kv%7O#O*xBRU}#SndQm4s%ZHtk~R zYp0f)Btt#5TNQ82x?!C$;<72^`HxuJU>OAokgb+kU@w}>;OEW*)V=^G&Z zR)K)W(}J3$fv-4S1;mQkg|QFrMr<6qy_>zAJ^CQRPEQEOrA0xm@QXRRg~Ha6CFKE* z&+B@}1Qy9WB$ZKEL?*q{;?@zT+IRX$n0GiqWF2rFUoGv46+x*w_1{i9gl zP(8dc@Tph+x~ml@c55qdvvevA^w4n2?UfVVuoTklRYvDLgo!Qsql`6QH5Q%F)|uZ< zzX+O-dGe_|j#UQw23^#d!@i-cU&}PhHRE7*QVbQ*ckJ0v-SyE~FZvt8DtOQgTKE3@(dfspL*p^mH4cG6C_(kJA3l=kJ?Z@7leCgAR-6GuPZwF0u%!j_tbkGo99pG z9SOYKh40Z0t%00Uaw}@_u8;{BmbKKIlgZDLv#ZW2IjVN%Sw4u(D!7M7NSlML+@+rg z_g^wu8aQ~S&z<`6_KFH*yWE+BIUcd_F7VW+^&Wi2yQal)52}#`QU#FP5k@UdG+_NH z4g$Q)wMDnblycaI=Xxv~bc&o?w%itxE_6hH25q@*1pcCX1TDfo@^?9u(DS%BM@%^Rg$~o{<*wE$oWXjIz#k zGbqEq#N57Nx#ft?WD^BW7NftV3LJfeVx0~;Swm-;z1U~q=bw^>W2OL6#|qPTsoVSH zcgWg8RL)rROa*fe-dWpwef>3-i`*mMvOJ%%?bF`StLi4NzrOIgT=;Fv!E%u{Y||ej zwv*oNlsgknNGW9`4_sH~@4TQ4LQzMDD z0hr@r1C#3ir`B1c|G)i;QP$Du-%Dzu`Xsnj2JeHhxxLQzcCA~D1jQWL`*o;pVh zR@qSHdv8K0|JLZ=&+zH%nd=Di4re{scSqS%8$7e&cPMzN4t&S5b{l+Nw+H>#s;?Ie zNTz?FOb(*wR)9Z?1EI4Jx>v z;gXeYw8RS~mkU?y3kt|1owqV&hd{r62)OOk@*V6os46zequ?9;yD&H0QAJ%-Vnw3u zuE}CTQ^X@R+ph1;nC^Kuk)c)*2d2+Qr@YE{VRir-@<)6D@<7(I-t;=Bda%hZ`3grb zdgpU17D;{MV-P)=b8sss_Fnt|ZjTsn$$MOv)^qI|gFks>F-iuY>)1JEu08GK?8J_% z{#HTddBp)*ek%?u3^YD^!=GtG;Qvi>sGuYWd%43;_yGsHOOB&wQ>5)1HW@8EqD%kb z29A^P`BFml?4ur$wU*^5_$ekz_!{CF5mFI1vg4Oopux+SDoA-xZgICzoIY+pk43;* zdKuA(ER0yEz)2jbtqhQz5!m%Ki+;}|?xSG@fE?7)JP5G28NJ1JBn@-u!a;%Jn#9+; zo5U6g&uA5-Hu%i>);OCZi$8kw^?-gP`A2OxVc^e-zi(36I`Knd*TjXwBP#msX|x7B z`3p8Ptq3*(WFv#b+xOMj(toejEcV>eK=e7k+BzpSr3LvSYXWS;mbDt_GQ{-mtA?D= zvKt+eSN#Dakrz~985egHp0fpFH+)jbN8?B9D_ucOU_PlK^Putjx!@r(d=rNYm<_Mb z;eF%PTCQ`(w@awKULx&7xqc+gkm}X8_)>;$F_zlesGTicy)mX@_cxEg zU&vI%&pAt9eMKI+tG@hDP8v2YjN+AX8KZ}imj;K=vGKoDCLvxdv8zQfsUfBy5*Xm1 zx%nSl5}hl;rk5PxBkurQr-DoyDc^$k;Mt}NLg9Ij@@-(|YVc|1dvr_iOTFRg?_)@W zUnw(eyPyzi9uiN5Xa&hPeJ>eNp&jQYy!HwLxCj)TI(x*t6;wTiHO9YTiQ>~VG6x(s zhY22i+fv}E@-sm5GXi`N{q~DBsYv;WV#~r~8@Pf;w*LAr%BgA5idY@YsK=uJ$4+2* zagqOOw*4PmP6ZlP|Ft$$=Cg;(MhKC81^>X`lWh8Ce*tW1a1Egh2wX)}SJE2V8%>NW zYPE3jP$a44MD%P{^1sD>qWA(Q1q&N$Z1^Yt+f3nQJ!__gpG%tYGh@8qaee#%n0FG! zNb17nHWkVBFMIH3Azp+{sF@ zkm=QD%Up{47Uzpg$yBw@)KS>CZQ0vNrx(+UuUu%R1GRLKFH4WrcG!_ojnv%t;mBoc zpGU^tCpyg&u-;0uh*S;Bb(-C$d&$FT2^c;Z#c0d+D@;6semGY476zb)^ zQSRtPq1*wzc+(PoNT|+tjGy9g45+Qw*KEUS2Snx+OB`#oE0HhkuP<%n0TEykfhRS8 zVpDQXGNpgW*@OLwZ1NDl{d8FCH}v9e26#XktISpXiq3f^L>L?SN77Z`BAMea_GDbx zg?jOZoqy?5%?8YM5>92ohl7?!n#NgS)#2 zcXtoAaCdiicL*%pT^AmLI|&YFy?a-ks{QWsSAGB8yqZ_D#_S&5{ftl32l6QG+H9kp zzo+Fi%+Vbg#;B`3gmJ~{utWEpra3V);aCPh%tWtYSnm31b#=F>s<1WVb6SDa6 zCi1@FIzxZFk>q;NPL-%LZa=5}4P`e|SRLb5JcpflZt@5S)J0OD^Rsm=}0 zq`zSW2GOURxRGPAoZyOi9QY|z|CGT+(@Eyi~Cyv zEXCb42>7jAv`!3H<<@^~Yg5)Wd0I9?>3@ssma>v+Td%i^e}aPr{#qHr0hnf7Vn!dZ zv#9T&YkSOj_;it~9LL1^W#a`659hbu3O<|-E_sj*VR)5!$R`DGFeMVk_jEZr{Cz}I zDcQ-0KUhLiKTT@R*+`WgM3XwJgrol4Zq#Pj@BIBJD&K4!m@cdX-gpW8FtQyo#mZ?6 ziQHw3H)!j4^=-g3+>5$r0q6F(=mG@LPH*nT3keCH{BcQge^wCpIG%tOV1>9nc0d-4 zzRbRpng&1Yk{v0C%Ep2Vh6%gzf*V?u*lv(lLZk2l1`%(Uu!c8AM1g3OBNQR=}JTrk&qAX=~RQtqe*A5-p6dDnXM z?ZG0}zx%ps?H51W6^P=MV@AAM%0Ms0(K7tv0y!5csrK?^+d~n+yhS;3EUNyP6Ze=po|9yVX-Z;mhQ6= zgW%5{T>ZFZM?LIO5bLWz2#D2S5Y?K%nW}!ufkuedgwlZ3PcH1h40pj%Z`hP5%gbc5 zn2kPD`dboS%&p08vD^2#9y96&=9b8f9HwBCHkH2y{Z*_AyHvk6QrKo9R;tl20fc6Q z@|Q-dzGU}eJHN*d5wj0qx}_7wvM&G#x4g{1jlXJV{%yyXF7`x4Ql^&Y%J$6aQVKD` zmGv}_@>EK@&DSu%=JqKtDEy%0Vyo<~!xg(}XLe!n&;jArBhXndUP~AbL`-NbZc*5i zPQ11(5npQirS{~C?rUDBFk3Z5zf6HE6<)CV_IU#oUx(3UBvqNwRI{GFH`IGl@-%

(9HaTnv3aRpgB#b{l2P={LE1ykQ8 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

J&x9JFStrqx1O??0!4oUcp)SmI-?sM=-f`7`HQS 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�rn)lR2&@)qSyrIUwJ+}5gAaP&Kh}*A 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%0ASw7l%iD0y^d5znv6ODG+_kQI2r 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

@Itp)7o64Pm0C>}n9|5Ylaks!*L^ZV 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

gWmsX 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 SFXax(ed{@*lld_=bpHo$V*XzM literal 0 HcmV?d00001 diff --git a/apps/client/local_plugins/device_smartcar/android/src/main/AndroidManifest.xml b/apps/client/local_plugins/device_smartcar/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000..93acb3b5 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/android/src/main/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/DeviceSmartcarPlugin.kt b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/DeviceSmartcarPlugin.kt new file mode 100644 index 00000000..1a145ec0 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/DeviceSmartcarPlugin.kt @@ -0,0 +1,280 @@ +package com.yimai.device_smartcar + +import android.bluetooth.BluetoothDevice +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.bluetooth.BluetoothAdapter +import android.os.Handler +import android.os.Looper +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.plugin.common.EventChannel +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel + +/** + * Smartcar 车载香薰的 Flutter 插件(Android)。 + * + * 方法/事件通道与 iOS **逐字对齐**(`DeviceSmartcarPlugin.swift`),Dart 侧一份代码两端通用: + * + * 方法 `com.yimai.device_smartcar`: + * adapterState() -> String on / off / unauthorized / unsupported + * startScan({timeoutSec}) -> Bool 起不来抛 SCAN_FAILED(带原因) + * stopScan() + * connect({id, timeoutSec}) -> Bool **认证通过才 resolve**;失败抛 CONNECT_FAILED + * disconnect() / isConnected() -> Bool + * writeCustom({data: Uint8List}) -> Bool + * jlPostAuth() -> Map 认证后的 RCSP 收尾状态 + * otaStart({filePath}) / otaCancel() / otaIsRunning() -> Bool + * + * 事件 `com.yimai.device_smartcar/events`: + * {type:"adapter", state} / {type:"scan", id,name,rssi,mfg,services} / {type:"scanStopped"} + * {type:"state", id, state, reason?} / {type:"custom", id, data} + * {type:"ota", state, percent, code?, message?} + * + * ⚠️ `id` 在 Android 上是**蓝牙 MAC**、在 iOS 上是 peripheral UUID。Dart 只把它当不透明串 + * 传回来连接,不要在业务层解释它(真正的设备身份是广播里的 MAC,见 `SmartcarProtocol`)。 + */ +class DeviceSmartcarPlugin : + FlutterPlugin, + MethodChannel.MethodCallHandler, + EventChannel.StreamHandler, + SmartcarGattListener { + + private lateinit var methodChannel: MethodChannel + private lateinit var eventChannel: EventChannel + private var sink: EventChannel.EventSink? = null + private var context: Context? = null + private val handler = Handler(Looper.getMainLooper()) + + private var pendingConnect: MethodChannel.Result? = null + private var connectTimeoutTask: Runnable? = null + + private val central get() = SmartcarBleCentral.shared + + override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { + context = binding.applicationContext + central.attach(binding.applicationContext) + SmartcarOta.shared.attach(binding.applicationContext) + central.connectListener = this + central.onScanHit = { hit -> + val m = HashMap() + m["type"] = "scan" + m["id"] = hit.id + m["name"] = hit.name + m["rssi"] = hit.rssi + m["services"] = hit.serviceUuids + if (hit.manufacturerData != null) m["mfg"] = hit.manufacturerData + emit(m) + } + central.onScanStopped = { emit(mapOf("type" to "scanStopped")) } + SmartcarOta.shared.onEvent = { emit(it) } + SmartcarAudio.onPcm = { pcm -> emit(mapOf("type" to "audio", "data" to pcm)) } + + methodChannel = MethodChannel(binding.binaryMessenger, "com.yimai.device_smartcar") + methodChannel.setMethodCallHandler(this) + eventChannel = EventChannel(binding.binaryMessenger, "com.yimai.device_smartcar/events") + eventChannel.setStreamHandler(this) + + binding.applicationContext.registerReceiver( + adapterReceiver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) + ) + } + + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { + try { + binding.applicationContext.unregisterReceiver(adapterReceiver) + } catch (e: Throwable) { + // 没注册上就算了 + } + methodChannel.setMethodCallHandler(null) + eventChannel.setStreamHandler(null) + central.onScanHit = null + central.onScanStopped = null + if (central.connectListener === this) central.connectListener = null + SmartcarOta.shared.onEvent = null + SmartcarAudio.onPcm = null + SmartcarAudio.stop() + sink = null + context = null + } + + private val adapterReceiver = object : BroadcastReceiver() { + override fun onReceive(ctx: Context?, intent: Intent?) { + if (intent?.action != BluetoothAdapter.ACTION_STATE_CHANGED) return + emit(mapOf("type" to "adapter", "state" to central.stateString)) + } + } + + // ───────────── 事件 ───────────── + + override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { + sink = events + } + + override fun onCancel(arguments: Any?) { + sink = null + } + + private fun emit(m: Map) { + handler.post { sink?.success(m) } + } + + // ───────────── 方法 ───────────── + + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + when (call.method) { + "adapterState" -> result.success(central.stateString) + + "startScan" -> { + val timeout = call.argument("timeoutSec") ?: 15 + val err = central.startScan(timeout) + if (err == null) result.success(true) + else result.error("SCAN_FAILED", err, null) + } + + "stopScan" -> { + central.stopScan() + result.success(null) + } + + "connect" -> { + val id = call.argument("id") + if (id.isNullOrEmpty()) { + result.error("BAD_ARGS", "缺少 id", null) + return + } + if (pendingConnect != null) { + result.error("BUSY", "上一次连接还在进行中", null) + return + } + val session = central.connect(id, this) + if (session == null) { + result.error("NOT_FOUND", "这个 id 不是合法的蓝牙地址,或蓝牙不可用", null) + return + } + if (session.isReady) { + result.success(true) + return + } + pendingConnect = result + val timeoutSec = call.argument("timeoutSec") ?: 45 + val task = Runnable { + if (pendingConnect == null) return@Runnable + central.disconnect() + finishConnect("连接总超时(${timeoutSec}s),停在 ${central.active?.state?.raw ?: "?"}") + } + connectTimeoutTask = task + handler.postDelayed(task, timeoutSec * 1000L) + } + + "disconnect" -> { + central.disconnect() + result.success(null) + } + + "isConnected" -> result.success(central.active?.isReady == true) + + "writeCustom" -> { + val data = call.argument("data") + if (data == null) { + result.error("BAD_ARGS", "data 必须是 Uint8List", null) + return + } + val s = central.active + result.success(s != null && s.isGattConnected && s.writeCustom(data)) + } + + "jlPostAuth" -> { + if (!SmartcarRcsp.shared.isAuthPass) { + result.error("NOT_READY", "链路未就绪(认证未过)", null) + return + } + var done = false + // SDK 不回调就永远不回,给 8s 兜底(与 iOS 同) + handler.postDelayed({ + if (!done) { done = true; result.success(mapOf("timeout" to true)) } + }, 8_000) + SmartcarRcsp.shared.runPostAuth { report -> + handler.post { + if (!done) { done = true; result.success(report) } + } + } + } + + // 设备在唤醒后自己开麦,这里只决定要不要往 Dart 抛 + "audioStart" -> result.success(SmartcarAudio.start()) + "audioStop" -> { + SmartcarAudio.stop() + result.success(null) + } + "audioStats" -> result.success(SmartcarAudio.stats()) + + "otaStart" -> { + val path = call.argument("filePath") + if (path.isNullOrEmpty()) { + result.error("BAD_ARGS", "缺少 filePath", null) + return + } + val err = SmartcarOta.shared.start(path) + if (err == null) result.success(true) else result.error("OTA_FAILED", err, null) + } + + "otaCancel" -> { + SmartcarOta.shared.cancel() + result.success(null) + } + + "otaIsRunning" -> result.success(SmartcarOta.shared.isRunning) + + else -> result.notImplemented() + } + } + + private fun finishConnect(error: String?) { + connectTimeoutTask?.let { handler.removeCallbacks(it) } + connectTimeoutTask = null + val r = pendingConnect ?: return + pendingConnect = null + if (error != null) r.error("CONNECT_FAILED", error, null) else r.success(true) + } + + // ───────────── SmartcarGattListener ───────────── + + override fun onLinkState(session: SmartcarGatt, state: SmartcarLinkState, reason: String?) { + val m = HashMap() + m["type"] = "state" + m["id"] = session.id + m["state"] = state.raw + if (reason != null) m["reason"] = reason + emit(m) + + SmartcarOta.shared.onLinkState(session, state) + + when (state) { + SmartcarLinkState.READY -> finishConnect(null) + SmartcarLinkState.FAILED -> finishConnect(reason ?: "连接失败") + SmartcarLinkState.DISCONNECTED -> + if (pendingConnect != null) { + finishConnect("连接过程中链路断开" + (reason?.let { ":$it" } ?: "")) + } + else -> {} + } + } + + override fun onCustomData(session: SmartcarGatt, data: ByteArray) { + emit(mapOf("type" to "custom", "id" to session.id, "data" to data)) + } + + override fun onJlData(session: SmartcarGatt, data: ByteArray) { + // 音频帧与 RCSP 命令共用 AE02,先让音频挑走(只认那个 7 字节头) + SmartcarAudio.feedJl(data) + // 认证前/后都先过 RCSP;OTA 在跑且认证已过时,数据归 OTA SDK(对齐 lumi 的分流) + if (SmartcarOta.shared.isRunning && SmartcarRcsp.shared.isAuthPass) { + SmartcarOta.shared.onDeviceData(session.device, data) + } else { + SmartcarRcsp.shared.onJlData(data) + } + } +} diff --git a/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/OggOpusExtractor.kt b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/OggOpusExtractor.kt new file mode 100644 index 00000000..8ccf50ef --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/OggOpusExtractor.kt @@ -0,0 +1,137 @@ +package com.yimai.device_smartcar + +/** + * 从 **Ogg 封装的 Opus 流**里拆出一个个 opus 包。与 iOS `OggOpusExtractor.swift` 一字对应。 + * + * ## 为什么需要它(2026-09-11 iOS 真机踩出来的) + * 设备经 AE02 送上来的不是裸 opus 帧,而是 **Ogg 流**:`OggS` 页头 + 段表 + 页体。 + * 直接把整段 payload 喂给解码器,解出来是噪声——真机上表现为"上行有包、百炼一句不回, + * 5 秒无声自动结束会话"。 + * + * 逻辑照 lumi `MusicDetector.swift` 内嵌的同名类搬: + * - BLE 通知会把一页切成好几包,所以要**跨包累积**再找 `OggS`; + * - 段长 255 表示"还没完,接着拼",< 255 才是一个完整 opus 包的结尾; + * - 每页校验 CRC32(Ogg 用 `0x04C11DB7` 无反射变体),校验不过就从下一字节重找同步字, + * 不能整段丢——BLE 丢包时后面还有好页; + * - `OpusHead` / `OpusTags` 两个头包要跳过,喂给解码器会出错。 + */ +class OggOpusExtractor { + + companion object { + private const val MAX_BUFFER = 64 * 1024 + + private val CRC_TABLE = IntArray(256).also { t -> + for (i in 0 until 256) { + var r = i shl 24 + repeat(8) { + r = if (r and 0x8000_0000.toInt() != 0) (r shl 1) xor 0x04C1_1DB7 else (r shl 1) + } + t[i] = r + } + } + } + + private var buffer = ByteArray(0) + + fun reset() { + buffer = ByteArray(0) + } + + /** 喂一段 payload,返回这次能凑出的完整 opus 包(可能 0 个,也可能好几个) */ + fun feed(payload: ByteArray): List { + if (payload.isEmpty()) return emptyList() + buffer += payload + val out = ArrayList() + var searchFrom = 0 + while (true) { + val sync = indexOfOggS(buffer, searchFrom) + if (sync < 0) { + // 没找到同步字:只留最后 3 字节,`OggS` 可能被切在两包之间 + val keepFrom = maxOf(buffer.size - 3, searchFrom) + if (keepFrom in 1 until buffer.size) { + buffer = buffer.copyOfRange(keepFrom, buffer.size) + } + break + } + if (sync + 27 > buffer.size) break + val pageSegments = buffer[sync + 26].toInt() and 0xFF + val headerLen = 27 + pageSegments + if (sync + headerLen > buffer.size) break + var bodyLen = 0 + for (i in 0 until pageSegments) bodyLen += buffer[sync + 27 + i].toInt() and 0xFF + val totalPageLen = headerLen + bodyLen + if (sync + totalPageLen > buffer.size) break + if (!verifyCrc(buffer, sync, totalPageLen)) { + searchFrom = sync + 1 + continue + } + if (sync > 0) buffer = buffer.copyOfRange(sync, buffer.size) + extractPackets(headerLen, pageSegments, out) + buffer = buffer.copyOfRange(totalPageLen, buffer.size) + searchFrom = 0 + } + // 防炸:只可能是一直没对上同步字,保留末尾一段继续找 + if (buffer.size > MAX_BUFFER) { + val cutFrom = buffer.size - MAX_BUFFER + val cut = indexOfOggS(buffer, cutFrom) + buffer = buffer.copyOfRange(if (cut >= 0) cut else cutFrom, buffer.size) + } + return out + } + + /** 调用时 buffer 已经以 `OggS` 开头(sync == 0) */ + private fun extractPackets(headerLen: Int, pageSegments: Int, out: MutableList) { + var current = ByteArray(0) + var bodyOffset = headerLen + for (i in 0 until pageSegments) { + val segLen = buffer[27 + i].toInt() and 0xFF + if (bodyOffset + segLen > buffer.size) break + if (segLen > 0) { + current += buffer.copyOfRange(bodyOffset, bodyOffset + segLen) + bodyOffset += segLen + } + // 段长 255 = 还有后续段属于同一个包;< 255 才收尾 + if (segLen < 255) { + if (current.isNotEmpty() && !isOpusHeader(current)) out.add(current) + current = ByteArray(0) + } + } + } + + private fun indexOfOggS(data: ByteArray, start: Int): Int { + var i = maxOf(start, 0) + val end = data.size - 4 + while (i <= end) { + if (data[i] == 0x4F.toByte() && data[i + 1] == 0x67.toByte() && + data[i + 2] == 0x67.toByte() && data[i + 3] == 0x53.toByte() + ) return i + i++ + } + return -1 + } + + /** `OpusHead` / `OpusTags` 不是音频包,喂给解码器会出错 */ + private fun isOpusHeader(p: ByteArray): Boolean { + if (p.size < 8) return false + return p[0] == 0x4F.toByte() && p[1] == 0x70.toByte() && p[2] == 0x75.toByte() && + p[3] == 0x73.toByte() && (p[4] == 0x48.toByte() || p[4] == 0x54.toByte()) + } + + /** Ogg 页 CRC:算的时候把 CRC 字段本身(22..25)当 0 */ + private fun verifyCrc(data: ByteArray, offset: Int, pageLen: Int): Boolean { + if (offset + pageLen > data.size) return false + val stored = (data[offset + 22].toInt() and 0xFF) or + ((data[offset + 23].toInt() and 0xFF) shl 8) or + ((data[offset + 24].toInt() and 0xFF) shl 16) or + ((data[offset + 25].toInt() and 0xFF) shl 24) + var crc = 0 + val crcStart = offset + 22 + val crcEnd = offset + 25 + for (i in offset until offset + pageLen) { + val b = if (i in crcStart..crcEnd) 0 else data[i].toInt() and 0xFF + val idx = ((crc ushr 24) and 0xFF) xor b + crc = (crc shl 8) xor CRC_TABLE[idx] + } + return crc == stored + } +} diff --git a/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarAudio.kt b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarAudio.kt new file mode 100644 index 00000000..44f42bee --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarAudio.kt @@ -0,0 +1,148 @@ +package com.yimai.device_smartcar + +import android.util.Log +import com.jieli.jl_audio_decode.callback.OnDecodeStreamCallback +import com.jieli.jl_audio_decode.opus.OpusManager +import com.jieli.jl_audio_decode.opus.model.OpusOption + +/** + * 设备麦克风上行(Android):从杰理通道(AE02)里挑出 opus 音频帧,解成 16k/16bit/mono PCM。 + * + * 帧格式与 iOS `SmartcarAudio.swift` 完全一致(照 lumi 搬): + * ``` + * FE DC BA 80 01 00 8E | seq(1) | 04 | opus payload … | 尾字节(1,丢弃) + * ``` + * 音频与 RCSP 命令**共用 AE02**,靠这个 7 字节头区分;`seq` 0~255 循环,用来去重。 + * + * ⚠️ 解码器用杰理的 `com.jieli.audio:jl_audio_decode`(`ble_service` / `recorder_holder` + * 已经在依赖同一个坐标,不要再 vendor 第二份),不是 iOS 那边的 libopus—— + * 两端解码库不同但输出口径一致:16k / 单声道 / 16bit 小端 PCM。 + */ +object SmartcarAudio { + private const val TAG = "SmartcarAudio" + + /** 解好的 PCM。由插件转成 `{type:"audio", data}` 事件 */ + var onPcm: ((ByteArray) -> Unit)? = null + + private var opus: OpusManager? = null + private var lastSeq = -1 + + /** ⚠️ 设备送的是 **Ogg 封装的 opus**,不是裸帧,必须先拆页取包。见 [OggOpusExtractor] */ + private val ogg = OggOpusExtractor() + + @Volatile + var isRunning = false + private set + + // 排查用计数:真机上"没声音"时先看这三个数 + private var framesIn = 0 + private var framesDup = 0 + private var pcmBytesOut = 0 + + /** 从 Ogg 里真正拆出来的 opus 包数。一直是 0 = 根本没解析出 Ogg 页 */ + private var opusPackets = 0 + + @Synchronized + fun start(): Boolean { + framesIn = 0; framesDup = 0; pcmBytesOut = 0; opusPackets = 0 + lastSeq = -1 + ogg.reset() + if (opus != null) { + isRunning = true + return true + } + return try { + val m = OpusManager() + // hasHead=false:设备送的是裸 opus 帧,不是 ogg 封装 + val opt = OpusOption() + .setHasHead(false) + .setChannel(1) + .setSampleRate(16_000) + m.startDecodeStream(opt, object : OnDecodeStreamCallback { + override fun onDecodeStream(data: ByteArray?) { + if (data == null || data.isEmpty()) return + pcmBytesOut += data.size + onPcm?.invoke(data) + } + + // ⚠️ 别写成表达式体:Log.i 返回 Int,接口要的是 Unit,编不过。 + override fun onStart() { + Log.i(TAG, "opus 解码流已启动") + } + + override fun onComplete(path: String?) { + Log.i(TAG, "opus 解码流结束") + } + override fun onError(code: Int, msg: String?) { + Log.e(TAG, "opus 解码错误 code=$code msg=$msg") + } + }) + opus = m + isRunning = true + true + } catch (e: Throwable) { + Log.e(TAG, "OpusManager 初始化失败: ${e.message}", e) + false + } + } + + @Synchronized + fun stop() { + isRunning = false + try { + opus?.stopDecodeStream() + opus?.release() + } catch (e: Throwable) { + Log.w(TAG, "opus 释放失败: ${e.message}") + } + opus = null + lastSeq = -1 + } + + fun stats(): Map = mapOf( + "running" to isRunning, + "framesIn" to framesIn, + "opusPackets" to opusPackets, + "framesDup" to framesDup, + "pcmBytesOut" to pcmBytesOut, + ) + + /** 喂一包 AE02 原始数据。不是音频帧就忽略(RCSP 命令走 SmartcarRcsp 那条路) */ + @Synchronized + fun feedJl(packet: ByteArray) { + if (!isRunning || !isAudioPacket(packet)) return + val seq = packet[7].toInt() and 0xFF + if (lastSeq >= 0) { + // seq 1 字节循环;> 200 跳到 < 50 视为回绕,不当重复 + val wrapped = lastSeq > 200 && seq < 50 + if (!wrapped && seq <= lastSeq) { + framesDup++ + return + } + } + lastSeq = seq + framesIn++ + if (packet.size <= 10) return + // 先从 Ogg 流里拆出完整的 opus 包(跨 BLE 包累积),再逐包喂解码器。 + // 直接喂整段 payload 解出来是噪声——iOS 那边真机踩过。 + val payload = packet.copyOfRange(9, packet.size - 1) + val packets = ogg.feed(payload) + if (packets.isEmpty()) return + opusPackets += packets.size + for (pkt in packets) { + try { + opus?.writeAudioStream(pkt) + } catch (e: Throwable) { + Log.w(TAG, "writeAudioStream 失败: ${e.message}") + } + } + } + + /** 头 7 字节 + `[8] == 0x04` 一起判,单看头会把 RCSP 帧误收 */ + fun isAudioPacket(p: ByteArray): Boolean { + if (p.size < 9) return false + return p[0] == 0xFE.toByte() && p[1] == 0xDC.toByte() && p[2] == 0xBA.toByte() && + p[3] == 0x80.toByte() && p[4] == 0x01.toByte() && p[5] == 0x00.toByte() && + p[6] == 0x8E.toByte() && p[8] == 0x04.toByte() + } +} diff --git a/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarBleCentral.kt b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarBleCentral.kt new file mode 100644 index 00000000..1040feef --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarBleCentral.kt @@ -0,0 +1,185 @@ +package com.yimai.device_smartcar + +import android.Manifest +import android.annotation.SuppressLint +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothManager +import android.bluetooth.le.ScanCallback +import android.bluetooth.le.ScanResult +import android.bluetooth.le.ScanSettings +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import android.os.Handler +import android.os.Looper +import android.util.Log +import androidx.core.content.ContextCompat + +/** 一条扫描结果。厂商数据原样上抛,字段解释在 Dart(`SmartcarProtocol`) */ +data class SmartcarScanHit( + val id: String, + val name: String, + val rssi: Int, + /** `[公司ID低, 公司ID高] + payload` —— 拼成和 iOS `CBAdvertisementDataManufacturerDataKey` 一样的形状 */ + val manufacturerData: ByteArray?, + val serviceUuids: List, +) + +/** + * Smartcar 的 BLE 扫描 / 连接持有者(进程内单例),对齐 iOS `SmartcarBleCentral`。 + * + * 扫描**不加 ScanFilter**:C2 的身份在厂商自定义数据里,用 service 过滤一台都扫不到 + * (iOS 上踩过同样的坑)。判定在 Dart 侧按厂商 ID + 名字做。 + */ +@SuppressLint("MissingPermission") +class SmartcarBleCentral private constructor() { + + companion object { + private const val TAG = "SmartcarBleCentral" + val shared = SmartcarBleCentral() + } + + private val handler = Handler(Looper.getMainLooper()) + private var context: Context? = null + private var adapter: BluetoothAdapter? = null + + var onScanHit: ((SmartcarScanHit) -> Unit)? = null + var onScanStopped: (() -> Unit)? = null + + /** OTA stage2 回连用:先于 [onScanHit] 看每条结果,返回 true 表示已处理 */ + var scanInterceptor: ((SmartcarScanHit) -> Boolean)? = null + + /** 原生侧自己发起连接(OTA 回连)时用的监听者 */ + var connectListener: SmartcarGattListener? = null + + var active: SmartcarGatt? = null + private set + + var isScanning = false + private set + + fun attach(ctx: Context) { + if (context != null) return + context = ctx.applicationContext + adapter = (ctx.getSystemService(Context.BLUETOOTH_SERVICE) as? BluetoothManager)?.adapter + } + + // ───────────── 状态与权限 ───────────── + + val stateString: String + get() { + val a = adapter ?: return "unsupported" + if (!hasPermission(scan = true)) return "unauthorized" + return if (a.isEnabled) "on" else "off" + } + + /** + * Android 12+ 把蓝牙权限拆成了运行时的 BLUETOOTH_SCAN / BLUETOOTH_CONNECT。 + * 没授权时直接抛 SecurityException,所以先查一遍给出说得清楚的错误。 + */ + private fun hasPermission(scan: Boolean): Boolean { + val ctx = context ?: return false + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return true + val perm = if (scan) Manifest.permission.BLUETOOTH_SCAN else Manifest.permission.BLUETOOTH_CONNECT + return ContextCompat.checkSelfPermission(ctx, perm) == PackageManager.PERMISSION_GRANTED + } + + // ───────────── 扫描 ───────────── + + private val scanTimeout = Runnable { stopScan() } + + /** 返回 null = 已启动,否则是失败原因 */ + fun startScan(timeoutSec: Int): String? { + val a = adapter ?: return "这台设备不支持蓝牙" + if (!a.isEnabled) return "蓝牙没打开" + if (!hasPermission(scan = true)) return "缺少「附近的设备」权限(BLUETOOTH_SCAN),去系统设置里打开" + if (isScanning) return null + val scanner = a.bluetoothLeScanner ?: return "拿不到 BluetoothLeScanner(蓝牙可能刚被关掉)" + val settings = ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .build() + return try { + scanner.startScan(null, settings, scanCallback) + isScanning = true + handler.removeCallbacks(scanTimeout) + handler.postDelayed(scanTimeout, timeoutSec.coerceAtLeast(1) * 1000L) + null + } catch (e: Exception) { + "启动扫描失败: ${e.message}" + } + } + + fun stopScan() { + handler.removeCallbacks(scanTimeout) + if (!isScanning) return + isScanning = false + try { + adapter?.bluetoothLeScanner?.stopScan(scanCallback) + } catch (e: Exception) { + Log.w(TAG, "stopScan 失败: ${e.message}") + } + onScanStopped?.invoke() + } + + private val scanCallback = object : ScanCallback() { + override fun onScanResult(callbackType: Int, result: ScanResult) { + val record = result.scanRecord + var mfg: ByteArray? = null + val msd = record?.manufacturerSpecificData + if (msd != null && msd.size() > 0) { + val cid = msd.keyAt(0) + val payload = msd.valueAt(0) ?: ByteArray(0) + // Android 把公司 ID 提到了 key 上,这里补回去(小端), + // 让 Dart 侧拿到和 iOS 完全一样的字节,一份解析代码两端通用 + mfg = byteArrayOf((cid and 0xFF).toByte(), ((cid shr 8) and 0xFF).toByte()) + payload + } + val hit = SmartcarScanHit( + id = result.device.address, + name = record?.deviceName ?: (try { result.device.name } catch (e: SecurityException) { null }) ?: "", + rssi = result.rssi, + manufacturerData = mfg, + serviceUuids = record?.serviceUuids?.map { it.uuid.toString() } ?: emptyList(), + ) + handler.post { + if (scanInterceptor?.invoke(hit) == true) return@post + onScanHit?.invoke(hit) + } + } + + override fun onScanFailed(errorCode: Int) { + Log.e(TAG, "扫描失败 errorCode=$errorCode") + isScanning = false + handler.post { onScanStopped?.invoke() } + } + } + + // ───────────── 连接 ───────────── + + /** 返回 null = 拿不到这个 MAC 对应的设备 */ + fun connect(id: String, listener: SmartcarGattListener): SmartcarGatt? { + val ctx = context ?: return null + val a = adapter ?: return null + if (!BluetoothAdapter.checkBluetoothAddress(id)) return null + stopScan() + val cur = active + if (cur != null && cur.id.equals(id, ignoreCase = true) && + cur.state != SmartcarLinkState.DISCONNECTED && cur.state != SmartcarLinkState.FAILED + ) { + return cur // 正在连/已连的同一台,复用 + } + if (cur != null && !cur.id.equals(id, ignoreCase = true)) cur.disconnect() + val device = try { + a.getRemoteDevice(id) + } catch (e: IllegalArgumentException) { + return null + } + val session = SmartcarGatt(ctx, device, listener) + active = session + session.connect() + return session + } + + fun disconnect() { + active?.disconnect() + } +} diff --git a/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarGatt.kt b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarGatt.kt new file mode 100644 index 00000000..4e27c3ee --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarGatt.kt @@ -0,0 +1,463 @@ +package com.yimai.device_smartcar + +import android.annotation.SuppressLint +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothGatt +import android.bluetooth.BluetoothGattCallback +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattDescriptor +import android.bluetooth.BluetoothProfile +import android.content.Context +import android.os.Build +import android.os.Handler +import android.os.Looper +import android.util.Log +import java.util.ArrayDeque +import java.util.UUID + +/** 链路状态。与 iOS `SmartcarLinkState` 一字不差,Dart 侧按字符串判定 */ +enum class SmartcarLinkState(val raw: String) { + DISCONNECTED("disconnected"), + CONNECTING("connecting"), + LINK_CONNECTED("linkConnected"), + AUTHENTICATING("authenticating"), + READY("ready"), + FAILED("failed"), +} + +interface SmartcarGattListener { + fun onLinkState(session: SmartcarGatt, state: SmartcarLinkState, reason: String?) + fun onCustomData(session: SmartcarGatt, data: ByteArray) + /** OTA 期间 SDK 要拿 AE02 的原始数据 */ + fun onJlData(session: SmartcarGatt, data: ByteArray) +} + +/** + * 一台 Smartcar 的 GATT 会话(Android)。 + * + * 从 lumi `jl/core/BlePeripheral.kt`(1656 行)精简出与固件行为相关的部分: + * - 自持 `BluetoothGatt`,在**同一条连接**上复用杰理服务 AE00 与 C2 私有服务 ABC0 + * (SDK 自己持连接就没法再订阅 ABC0,这正是不能直接用官方 SDK 连接的原因); + * - 服务发现 → 开 AE02 / ABC2 通知 → 协商 MTU → **跑杰理认证**,认证过才算 [SmartcarLinkState.READY]; + * - AE02 数据交给 [SmartcarRcsp],ABC2 数据原样上抛(组帧/CRC 在 Dart)。 + * + * ⚠️ **Android 的 GATT 一次只能有一个在途操作**(写/读/写描述符/协商 MTU 互斥), + * 所以所有操作都要过 [enqueue],在对应回调里 [completedCommand]。没有队列的写法 + * 在真机上表现为"偶尔丢一条命令",而且和手机型号强相关。 + */ +@SuppressLint("MissingPermission") +class SmartcarGatt( + private val context: Context, + val device: BluetoothDevice, + private val listener: SmartcarGattListener, +) { + companion object { + private const val TAG = "SmartcarGatt" + + /** 杰理 RCSP(认证 + OTA) */ + val JL_SERVICE: UUID = UUID.fromString("0000ae00-0000-1000-8000-00805f9b34fb") + val JL_TX: UUID = UUID.fromString("0000ae01-0000-1000-8000-00805f9b34fb") + val JL_RX: UUID = UUID.fromString("0000ae02-0000-1000-8000-00805f9b34fb") + + /** C2 私有通道 */ + val CUSTOM_SERVICE: UUID = UUID.fromString("0000abc0-0000-1111-2222-123456789abc") + val CUSTOM_TX: UUID = UUID.fromString("0000abc1-0000-1111-2222-123456789abc") + val CUSTOM_RX: UUID = UUID.fromString("0000abc2-0000-1111-2222-123456789abc") + + val CCC_DESCRIPTOR: UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") + + private const val CONNECT_TIMEOUT_MS = 35_000L + private const val AUTH_TIMEOUT_MS = 15_000L + /** 单条 GATT 操作的兜底超时:回调不来时不能让队列永久卡住 */ + private const val OP_TIMEOUT_MS = 6_000L + private const val MAX_MTU = 247 + } + + private val handler = Handler(Looper.getMainLooper()) + private var gatt: BluetoothGatt? = null + + var state: SmartcarLinkState = SmartcarLinkState.DISCONNECTED + private set + + val id: String get() = device.address + val name: String get() = try { device.name ?: "" } catch (e: SecurityException) { "" } + val isGattConnected: Boolean get() = gatt != null && state != SmartcarLinkState.DISCONNECTED + val isReady: Boolean get() = state == SmartcarLinkState.READY + + /** OTA 进行中:私有通道写入一律拒绝——业务包会和 SDK 的 OTA 数据抢 AE01 */ + @Volatile + var otaInProgress = false + + var currentMtu = 23 + private set + + private var txJl: BluetoothGattCharacteristic? = null + private var rxJl: BluetoothGattCharacteristic? = null + private var txCustom: BluetoothGattCharacteristic? = null + private var rxCustom: BluetoothGattCharacteristic? = null + + private var authStarted = false + + // ───────────── 操作队列 ───────────── + + private val queue = ArrayDeque<() -> Unit>() + private var queueBusy = false + private val opTimeout = Runnable { + Log.w(TAG, "GATT 操作超时,强制推进队列") + completedCommand() + } + + private fun enqueue(op: () -> Unit): Boolean { + if (gatt == null) return false + queue.add(op) + handler.post { nextCommand() } + return true + } + + private fun nextCommand() { + if (queueBusy) return + val op = queue.poll() ?: return + if (gatt == null) { + queue.clear() + return + } + queueBusy = true + handler.postDelayed(opTimeout, OP_TIMEOUT_MS) + try { + op() + } catch (e: Throwable) { + Log.e(TAG, "GATT 操作抛异常: ${e.message}") + completedCommand() + } + } + + private fun completedCommand() { + handler.removeCallbacks(opTimeout) + queueBusy = false + handler.post { nextCommand() } + } + + // ───────────── 连接 ───────────── + + fun connect() { + if (state != SmartcarLinkState.DISCONNECTED && state != SmartcarLinkState.FAILED) return + reset() + set(SmartcarLinkState.CONNECTING) + gatt = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + device.connectGatt(context, false, callback, BluetoothDevice.TRANSPORT_LE) + } else { + device.connectGatt(context, false, callback) + } + if (gatt == null) { + fail("connectGatt 返回 null(蓝牙没开或权限被拒)") + return + } + handler.postDelayed(connectTimeout, CONNECT_TIMEOUT_MS) + } + + private val connectTimeout = Runnable { + if (state == SmartcarLinkState.CONNECTING || state == SmartcarLinkState.LINK_CONNECTED) { + fail("GATT 连接超时(${CONNECT_TIMEOUT_MS / 1000}s),设备可能已被别的手机连着") + closeGatt() + } + } + + private val authTimeout = Runnable { + if (state == SmartcarLinkState.AUTHENTICATING) { + fail("杰理 RCSP 认证超时(${AUTH_TIMEOUT_MS / 1000}s):SDK 没有回调结果。" + + "多半是固件不接受这套认证密钥,或 AE02 通知没真正打开") + closeGatt() + } + } + + fun disconnect() { + handler.removeCallbacks(connectTimeout) + handler.removeCallbacks(authTimeout) + val g = gatt + if (g == null) { + if (state != SmartcarLinkState.DISCONNECTED) set(SmartcarLinkState.DISCONNECTED) + return + } + try { + g.disconnect() + } catch (e: SecurityException) { + Log.w(TAG, "disconnect 权限异常: ${e.message}") + } + // 部分机型 disconnect 后不回调,2s 兜底收状态 + handler.postDelayed({ + if (state != SmartcarLinkState.DISCONNECTED) { + closeGatt() + set(SmartcarLinkState.DISCONNECTED) + } + }, 2_000L) + } + + private fun closeGatt() { + try { + gatt?.close() + } catch (e: Throwable) { + Log.w(TAG, "gatt.close 失败: ${e.message}") + } + gatt = null + queue.clear() + queueBusy = false + handler.removeCallbacks(opTimeout) + } + + private fun reset() { + txJl = null; rxJl = null; txCustom = null; rxCustom = null + authStarted = false + currentMtu = 23 + queue.clear() + queueBusy = false + } + + private fun set(s: SmartcarLinkState, reason: String? = null) { + state = s + listener.onLinkState(this, s, reason) + } + + private fun fail(reason: String) { + handler.removeCallbacks(connectTimeout) + handler.removeCallbacks(authTimeout) + set(SmartcarLinkState.FAILED, reason) + } + + // ───────────── 收发 ───────────── + + /** 往 C2 私有写特征发一帧(组帧/CRC 由 Dart 完成)。没有 ABC1 时退回 AE01,与 lumi 一致 */ + fun writeCustom(data: ByteArray): Boolean { + if (otaInProgress) return false + val ch = txCustom ?: txJl ?: return false + return write(ch, data) + } + + /** 杰理通道(认证帧 / OTA 数据)写 AE01 */ + fun writeJl(data: ByteArray): Boolean { + val ch = txJl ?: return false + return write(ch, data) + } + + private fun write(ch: BluetoothGattCharacteristic, value: ByteArray): Boolean { + if (value.isEmpty() || gatt == null) return false + val type = if (ch.properties and BluetoothGattCharacteristic.PROPERTY_WRITE != 0) { + BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT + } else { + BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE + } + return enqueue { + val g = gatt + val ok = if (g == null) { + false + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + g.writeCharacteristic(ch, value, type) == BluetoothGatt.GATT_SUCCESS + } else { + @Suppress("DEPRECATION") + run { + ch.writeType = type + ch.value = value + g.writeCharacteristic(ch) + } + } + if (!ok) { + Log.e(TAG, "writeCharacteristic 失败 ${ch.uuid}") + completedCommand() + } + } + } + + private fun setNotify(ch: BluetoothGattCharacteristic): Boolean { + val descriptor = ch.getDescriptor(CCC_DESCRIPTOR) ?: run { + Log.e(TAG, "${ch.uuid} 没有 CCCD 描述符") + return false + } + val value = if (ch.properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0) { + BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE + } else { + BluetoothGattDescriptor.ENABLE_INDICATION_VALUE + } + return enqueue { + val g = gatt + if (g == null || !g.setCharacteristicNotification(ch, true)) { + Log.e(TAG, "setCharacteristicNotification 失败 ${ch.uuid}") + completedCommand() + return@enqueue + } + val ok = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + g.writeDescriptor(descriptor, value) == BluetoothGatt.GATT_SUCCESS + } else { + @Suppress("DEPRECATION") + run { + descriptor.value = value + g.writeDescriptor(descriptor) + } + } + if (!ok) { + Log.e(TAG, "writeDescriptor 失败 ${ch.uuid}") + completedCommand() + } + } + } + + /** + * 认证必须在 AE02 通知打开之后才开始,否则设备的应答收不到。 + * 对齐 lumi:MTU 协商完(或超时)再起认证,让 SDK 拿到真实包长。 + */ + private fun startAuthOnce() { + if (authStarted) return + val rx = rxJl + if (rx == null) { + fail("BLE 已连上,但设备没有杰理服务 AE00 的通知特征,认证走不了") + closeGatt() + return + } + authStarted = true + handler.removeCallbacks(connectTimeout) + set(SmartcarLinkState.AUTHENTICATING) + handler.postDelayed(authTimeout, AUTH_TIMEOUT_MS) + SmartcarRcsp.shared.attach(this) + SmartcarRcsp.shared.onAuthResult = { ok, reason -> + handler.post { + handler.removeCallbacks(authTimeout) + if (ok) { + if (state != SmartcarLinkState.READY) set(SmartcarLinkState.READY) + } else { + fail(reason ?: "杰理认证失败") + closeGatt() + } + } + } + SmartcarRcsp.shared.startAuth() + } + + // ───────────── GATT 回调 ───────────── + + private val callback = object : BluetoothGattCallback() { + + override fun onConnectionStateChange(g: BluetoothGatt, status: Int, newState: Int) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + handler.removeCallbacks(connectTimeout) + handler.postDelayed(connectTimeout, CONNECT_TIMEOUT_MS) + set(SmartcarLinkState.LINK_CONNECTED) + // 连上后等 200ms 再发现服务:太早会碰到 DLE 协商未完成(lumi 同款延时) + handler.postDelayed({ + try { + if (g.discoverServices() != true) fail("discoverServices 起不来") + } catch (e: SecurityException) { + fail("没有蓝牙连接权限: ${e.message}") + } + }, 200L) + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + handler.removeCallbacks(connectTimeout) + handler.removeCallbacks(authTimeout) + SmartcarRcsp.shared.detach(this@SmartcarGatt) + val wasConnecting = state == SmartcarLinkState.CONNECTING || + state == SmartcarLinkState.LINK_CONNECTED || + state == SmartcarLinkState.AUTHENTICATING + closeGatt() + reset() + if (wasConnecting && status != BluetoothGatt.GATT_SUCCESS) { + set(SmartcarLinkState.FAILED, "连接过程中断开 (status=$status)") + } else { + set(SmartcarLinkState.DISCONNECTED, if (status == 0) null else "status=$status") + } + } + } + + override fun onServicesDiscovered(g: BluetoothGatt, status: Int) { + if (status != BluetoothGatt.GATT_SUCCESS) { + fail("服务发现失败 status=$status") + closeGatt() + return + } + val list = g.services.joinToString(", ") { it.uuid.toString() } + val jl = g.services.find { it.uuid == JL_SERVICE } + if (jl == null) { + // ⚠️ 没有 AE00 就没法认证,固件不会认我们。把实际服务列出来,别只说"没找到" + fail("BLE 已连上,但设备没有杰理服务 AE00,认证走不了。实际服务: [$list]") + closeGatt() + return + } + txJl = jl.getCharacteristic(JL_TX) + rxJl = jl.getCharacteristic(JL_RX) + if (txJl == null || rxJl == null) { + fail("杰理服务 AE00 里缺少 AE01/AE02 特征") + closeGatt() + return + } + g.services.find { it.uuid == CUSTOM_SERVICE }?.let { svc -> + txCustom = svc.getCharacteristic(CUSTOM_TX) + rxCustom = svc.getCharacteristic(CUSTOM_RX) + } + + setNotify(rxJl!!) + rxCustom?.let { setNotify(it) } + // MTU 协商放在通知之后;无论成败都会走到 startAuthOnce + enqueue { + val ok = try { + gatt?.requestMtu(MAX_MTU) == true + } catch (e: SecurityException) { + false + } + if (!ok) { + completedCommand() + handler.post { startAuthOnce() } + } + } + // 兜底:个别机型 onMtuChanged 不回调,认证就永远起不来, + // 只会在 35s 后报「连接超时」——那个提示指向的方向是错的。 + // startAuthOnce 是幂等的,早到的那次生效即可。 + handler.postDelayed({ startAuthOnce() }, 6_000L) + } + + override fun onDescriptorWrite(g: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) { + if (status != BluetoothGatt.GATT_SUCCESS) { + Log.w(TAG, "CCCD 写失败 ${descriptor.characteristic?.uuid} status=$status") + } + completedCommand() + } + + override fun onMtuChanged(g: BluetoothGatt, mtu: Int, status: Int) { + if (status == BluetoothGatt.GATT_SUCCESS) currentMtu = mtu + Log.i(TAG, "MTU = $currentMtu (status=$status)") + completedCommand() + handler.post { startAuthOnce() } + } + + override fun onCharacteristicWrite(g: BluetoothGatt, ch: BluetoothGattCharacteristic, status: Int) { + if (status != BluetoothGatt.GATT_SUCCESS) { + Log.w(TAG, "写失败 ${ch.uuid} status=$status") + } + completedCommand() + } + + // API 33+ + override fun onCharacteristicChanged( + g: BluetoothGatt, + ch: BluetoothGattCharacteristic, + value: ByteArray, + ) { + dispatch(ch, value) + } + + @Deprecated("Deprecated in Java") + @Suppress("DEPRECATION") + override fun onCharacteristicChanged(g: BluetoothGatt, ch: BluetoothGattCharacteristic) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + dispatch(ch, ch.value ?: ByteArray(0)) + } + } + + private fun dispatch(ch: BluetoothGattCharacteristic, value: ByteArray) { + if (value.isEmpty()) return + when (ch.uuid) { + CUSTOM_RX -> handler.post { listener.onCustomData(this@SmartcarGatt, value) } + JL_RX -> handler.post { listener.onJlData(this@SmartcarGatt, value) } + else -> Log.d(TAG, "未知特征通知 ${ch.uuid}") + } + } + } + + /** 供 OTA SDK 拿原始 gatt(`BluetoothOTAManager.getConnectedBluetoothGatt`) */ + val rawGatt: BluetoothGatt? get() = gatt +} diff --git a/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarOta.kt b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarOta.kt new file mode 100644 index 00000000..7390e378 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarOta.kt @@ -0,0 +1,325 @@ +package com.yimai.device_smartcar + +import android.annotation.SuppressLint +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothGatt +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.util.Log +import com.jieli.jl_bt_ota.constant.BluetoothConstant +import com.jieli.jl_bt_ota.impl.BluetoothOTAManager +import com.jieli.jl_bt_ota.interfaces.IUpgradeCallback +import com.jieli.jl_bt_ota.model.BluetoothOTAConfigure +import com.jieli.jl_bt_ota.model.base.BaseError +// ⚠️ 用 jl_bt_ota 自己的 StateCode(值与 jl_rcsp 的相同,但这里调的是 OTA SDK 的方法) +import com.jieli.jl_bt_ota.constant.StateCode + +/** + * Smartcar 固件升级(Android)——从 lumi `jl/ota/OtaManager.kt` 搬。 + * + * ⚠️ **lumi 那份是死代码**:`PbManager` 里 `otaManager = OtaManager(context)` 整段被注释掉 + * (原注释「暂时禁用 OTA 以避免初次扫描冲突(当前不使用 OTA 功能)」),也就是说这条 Android + * 路径在 lumi 上**从未真机跑过**。所以这里的实现只能算"照着他们的写法接上去", + * 首次真机升级务必盯日志。iOS 那侧同样未经样机验证。 + * + * 与 iOS 的差别:Android SDK 用 [IUpgradeCallback],stage2 是显式的 + * [IUpgradeCallback.onNeedReconnect](iOS 是 `cmdOTAData` 回调里的 0xfc),语义一致: + * 设备烧完 stage1 会断开重启、换一个地址广播,App 要重新扫到它、连上、过认证, + * 再 [changeToPreparedState] 让 SDK 接着烧。 + * + * 事件形状与 iOS 完全一致:`{type:"ota", state, percent, code?, message?}`。 + */ +@SuppressLint("MissingPermission") +class SmartcarOta private constructor() { + + companion object { + private const val TAG = "SmartcarOta" + val shared = SmartcarOta() + + /** stage2 扫不到设备的总放弃时间。3 轮 60s + 轮间等待,与 iOS 对齐 */ + private const val STAGE2_TIMEOUT_MS = 190_000L + private const val STAGE2_ROUND_SEC = 60 + } + + private val handler = Handler(Looper.getMainLooper()) + + /** 事件出口(插件接到 EventChannel) */ + var onEvent: ((Map) -> Unit)? = null + + private var manager: Manager? = null + private var context: Context? = null + + @Volatile + var isRunning = false + private set + + private var terminal = false + private var lastPercent = -1 + private var stage2Target = "" + private var originalName = "" + private var stage2Deadline = 0L + + fun attach(ctx: Context) { + if (context == null) context = ctx.applicationContext + } + + // ───────────── 对外 ───────────── + + /** 返回 null = 已启动,否则是拒绝原因 */ + fun start(filePath: String): String? { + if (isRunning) return "OTA 已在进行中" + val ctx = context ?: return "插件未初始化" + val session = SmartcarBleCentral.shared.active + if (session == null || !session.isReady) return "链路未就绪(认证未过)" + val f = java.io.File(filePath) + if (!f.isFile || f.length() <= 0) return "固件文件读不到或为空: $filePath" + + originalName = session.name + terminal = false + lastPercent = -1 + isRunning = true + session.otaInProgress = true + + val m = manager ?: Manager(ctx).also { manager = it } + m.session = session + m.isOtaProcess = true + + // ⚠️ 这些开关只有 setter 没有 getter,Kotlin 属性赋值写法编不过,必须调 setXxx() + val option = BluetoothOTAConfigure() + .setPriority(BluetoothOTAConfigure.PREFER_BLE) + // 走 SDK 自己的重连逻辑(lumi 试过自定义重连,会让状态机卡住) + .setUseReconnect(false) + // 设备走的是标准 RCSP 握手(已经在 SmartcarRcsp 里做完),不是 SDK 内置那套; + // 打开会让 SDK 发设备不认的挑战包,超时失败 + .setUseAuthDevice(false) + .setMtu(BluetoothConstant.BLE_MTU_MIN) + .setNeedChangeMtu(false) + .setUseJLServer(false) + .setPriorityCallbackOtaFinish(true) + // 默认 500ms/包是 stage1 最大瓶颈;MTU 已协商到 ~247,贴着写回调发下一包 + .setBleIntervalMs(0) + .setFirmwareFilePath(filePath) + m.configure(option) + m.onBtDeviceConnection(session.device, StateCode.CONNECTION_OK) + session.rawGatt?.let { m.onMtuChanged(it, session.currentMtu, BluetoothGatt.GATT_SUCCESS) } + + emit("preparing", 0) + Log.i(TAG, "start: ${f.length()} bytes, device=$originalName") + m.startOTA(upgradeCallback) + return null + } + + fun cancel() { + if (!isRunning) return + Log.i(TAG, "cancel") + try { + manager?.cancelOTA() + } catch (e: Throwable) { + Log.w(TAG, "cancelOTA 失败: ${e.message}") + } + emit("cancelled", -1) + finish() + } + + /** AE02 数据:认证通过且 OTA 在跑时归 SDK */ + fun onDeviceData(device: BluetoothDevice, data: ByteArray) { + manager?.onReceiveDeviceData(device, data) + } + + /** 链路状态变化(插件转发) */ + fun onLinkState(session: SmartcarGatt, state: SmartcarLinkState) { + if (!isRunning) return + when (state) { + SmartcarLinkState.DISCONNECTED, SmartcarLinkState.FAILED -> { + // stage2 期间设备本来就会断开重启,这不是失败;交给 SDK 的状态机 + manager?.notifyConnectionState(session.device, StateCode.CONNECTION_DISCONNECT) + } + SmartcarLinkState.READY -> { + if (stage2Target.isEmpty()) return + Log.i(TAG, "stage2 已连上并认证,通知 SDK 续跑") + manager?.session = session + session.otaInProgress = true + stage2Target = "" + SmartcarBleCentral.shared.scanInterceptor = null + manager?.changeToPreparedState() + } + else -> {} + } + } + + // ───────────── SDK 回调 ───────────── + + private val upgradeCallback = object : IUpgradeCallback { + override fun onStartOTA() { + Log.i(TAG, "onStartOTA") + emit("transferring", 0) + } + + override fun onNeedReconnect(addr: String?, isBle: Boolean) { + // stage1 完成:设备断开重启,换地址广播,要我们重新连上去 + Log.i(TAG, "onNeedReconnect addr=$addr isBle=$isBle") + stage2Target = (addr ?: "").uppercase() + emit("stage2", if (lastPercent < 15) 15 else lastPercent, message = "$stage2Target|$originalName") + startStage2Scan() + } + + override fun onProgress(type: Int, progress: Float) { + val p = progress.toInt().coerceIn(0, 100) + if (p <= lastPercent) return + lastPercent = p + emit("transferring", p) + } + + override fun onStopOTA() { + Log.i(TAG, "onStopOTA(成功)") + emit("done", 100) + finish() + } + + override fun onCancelOTA() { + Log.i(TAG, "onCancelOTA") + emit("cancelled", -1) + finish() + } + + override fun onError(error: BaseError?) { + val msg = error?.message ?: "unknown" + val code = error?.subCode ?: -1 + Log.e(TAG, "onError code=$code msg=$msg") + emit("failed", -1, code = code, message = msg) + finish() + } + } + + // ───────────── stage2 扫描回连 ───────────── + + private fun startStage2Scan() { + val central = SmartcarBleCentral.shared + stage2Deadline = System.currentTimeMillis() + STAGE2_TIMEOUT_MS + central.scanInterceptor = { hit -> + if (!matchesStage2(hit)) { + false + } else { + Log.i(TAG, "stage2 命中 ${hit.name} (${hit.id})") + central.stopScan() + central.scanInterceptor = null + val l = central.connectListener + if (l == null || central.connect(hit.id, l) == null) { + emit("failed", -1, message = "stage2 设备无法发起连接") + finish() + } + true + } + } + scanRound() + } + + private fun scanRound() { + if (!isRunning || stage2Target.isEmpty()) return + if (System.currentTimeMillis() > stage2Deadline) { + emit("failed", -1, message = "3 轮扫描(约 3 分钟)都没等到设备重启后的广播") + finish() + return + } + val err = SmartcarBleCentral.shared.startScan(STAGE2_ROUND_SEC) + if (err != null) { + emit("failed", -1, message = "stage2 扫描起不来: $err") + finish() + return + } + // 一轮到点没命中就再起一轮;同时喂上层 90s 看门狗(stage2 窗口没有进度事件) + handler.postDelayed({ + if (isRunning && stage2Target.isNotEmpty()) { + emit("stage2", if (lastPercent < 15) 15 else lastPercent) + scanRound() + } + }, (STAGE2_ROUND_SEC + 3) * 1000L) + handler.postDelayed(stage2Heartbeat, 15_000L) + } + + private val stage2Heartbeat = object : Runnable { + override fun run() { + if (!isRunning || stage2Target.isEmpty()) return + emit("stage2", if (lastPercent < 15) 15 else lastPercent) + handler.postDelayed(this, 15_000L) + } + } + + private fun matchesStage2(hit: SmartcarScanHit): Boolean { + if (stage2Target.isNotEmpty() && hit.id.equals(stage2Target, ignoreCase = true)) return true + // ⚠️ SDK 给的回连地址经常和实际 ADV 对不上(lumi 明确记过这个坑),名字兜底不能删。 + // TODO(smartcar-ota): stage2 的广播名待样机确认(lumi 是固定的 Lumi-Music) + val n = hit.name.trim().lowercase() + if (n.isEmpty()) return false + if (n.contains("smartcar")) return true + val base = originalName.lowercase().substringBefore('-') + return base.length >= 4 && n.contains(base) + } + + // ───────────── 收尾 ───────────── + + private fun finish() { + if (terminal) return + terminal = true + isRunning = false + stage2Target = "" + lastPercent = -1 + handler.removeCallbacks(stage2Heartbeat) + SmartcarBleCentral.shared.scanInterceptor = null + manager?.isOtaProcess = false + manager?.session?.otaInProgress = false + manager?.session = null + } + + private fun emit(state: String, percent: Int, code: Int? = null, message: String? = null) { + val m = HashMap() + m["type"] = "ota" + m["state"] = state + m["percent"] = percent + if (code != null) m["code"] = code + if (message != null) m["message"] = message + handler.post { onEvent?.invoke(m) } + } + + /** + * 杰理 OTA SDK 的适配层:把 SDK 需要的「连接/收发」接到我们自持的 GATT 上。 + */ + private class Manager(ctx: Context) : BluetoothOTAManager(ctx) { + var session: SmartcarGatt? = null + var isOtaProcess = false + + fun changeToPreparedState() { + session?.let { onBtDeviceConnection(it.device, StateCode.CONNECTION_OK) } + } + + fun notifyConnectionState(device: BluetoothDevice, state: Int) { + onBtDeviceConnection(device, state) + } + + override fun getConnectedDevice(): BluetoothDevice? = session?.device + + override fun getConnectedBluetoothGatt(): BluetoothGatt? = session?.rawGatt + + override fun connectBluetoothDevice(device: BluetoothDevice?) { + // 回连由我们自己的 stage2 扫描做(SDK 那套扫描会和我们抢 Android 的扫描配额) + val ok = session?.let { it.connect(); true } ?: false + if (!ok) onBtDeviceConnection(device, StateCode.CONNECTION_FAILED) + } + + override fun disconnectBluetoothDevice(device: BluetoothDevice?) { + session?.disconnect() + } + + override fun sendDataToDevice(device: BluetoothDevice?, data: ByteArray?): Boolean { + if (data == null) return false + return session?.writeJl(data) == true + } + + // 注:lumi 那份还 override 了 `startBLEScan` 来拦 SDK 内部的重连扫描 + // (Android 30s 内只允许 5 次扫描,SDK 会拿一个可能错的 MAC 反复扫、白占配额)。 + // 我们用的 jl_bt_ota **1.11.0 已经不自带扫描**(`BluetoothOTAManager` 不再继承 + // BluetoothDiscovery,接口里没有 startBLEScan),回连一律由上面的 stage2 扫描做, + // 所以这个 override 没有了也不需要。 + } +} diff --git a/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarRcsp.kt b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarRcsp.kt new file mode 100644 index 00000000..dc62f933 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/android/src/main/kotlin/com/yimai/device_smartcar/SmartcarRcsp.kt @@ -0,0 +1,182 @@ +package com.yimai.device_smartcar + +import android.bluetooth.BluetoothDevice +import android.util.Log +import com.jieli.jl_rcsp.constant.StateCode +import com.jieli.jl_rcsp.impl.RcspAuth +import com.jieli.jl_rcsp.impl.RcspOpImpl +import com.jieli.jl_rcsp.interfaces.rcsp.RcspCommandCallback +import com.jieli.jl_rcsp.model.base.BaseError +import com.jieli.jl_rcsp.model.base.CommandBase +import com.jieli.jl_rcsp.util.CommandBuilder +import java.util.Calendar + +/** + * 杰理 RCSP 认证 + 命令层(Android)。 + * + * 从 lumi `jl/jieLi/JLWatchManager.kt` 搬,**去掉 WatchOpImpl**:那是手表专用基类 + * (表盘/通知推送),Smartcar 用不上,直接继承 `RcspOpImpl` 就够,也省掉 JL_Watch 这个 jar。 + * + * 固件行为:设备连上后要在杰理服务 AE00 上跑挑战应答,**认证通过前不把手机当成已连接** + * (屏幕显示 BLE 未连接、私有通道 ABC0 的命令也不应答)。算法在 `libjl_auth.so` 里, + * 只能调 SDK。见 docs/Smartcar车载香薰-接入设计与落地文档.md 5.5。 + * + * 数据分流(对齐 lumi `PbManager.onReceiveJLResponse`): + * - 认证通过前:AE02 收到的一律喂 [RcspAuth.handleAuthData] + * - 认证通过后:喂 [notifyReceiveDeviceData],让 RCSP 命令层自己处理 + */ +class SmartcarRcsp : RcspOpImpl() { + + companion object { + private const val TAG = "SmartcarRcsp" + val shared = SmartcarRcsp() + } + + /** 当前 GATT 会话,由 [attach] 设置 */ + private var gatt: SmartcarGatt? = null + + @Volatile + var isAuthPass = false + private set + + /** 认证结果回调,由 [SmartcarGatt] 设置 */ + var onAuthResult: ((Boolean, String?) -> Unit)? = null + + private val auth = RcspAuth( + RcspAuth.IRcspAuthOp { device, data -> sendDataToDevice(device, data) }, + object : RcspAuth.OnRcspAuthListener { + override fun onInitResult(ok: Boolean) { + Log.i(TAG, "RcspAuth 初始化: $ok") + isAuthPass = false + if (!ok) onAuthResult?.invoke(false, "杰理认证库初始化失败(libjl_auth.so 没加载起来)") + } + + override fun onAuthSuccess(device: BluetoothDevice?) { + Log.i(TAG, "杰理认证通过 ${device?.address}") + isAuthPass = true + // 告诉 RCSP 命令层设备已就绪:SDK 会自己去取设备信息/对齐状态, + // 相当于 iOS 那边 JL_BLEKit 认证后自动跑的那串(见 iOS JLAssistBridge.runPostAuth) + try { + notifyBtDeviceConnection(device, StateCode.CONNECTION_OK) + } catch (e: Throwable) { + Log.w(TAG, "notifyBtDeviceConnection 失败(不致命): ${e.message}") + } + onAuthResult?.invoke(true, null) + } + + override fun onAuthFailed(device: BluetoothDevice?, code: Int, msg: String?) { + Log.w(TAG, "杰理认证失败 code=$code msg=$msg") + isAuthPass = false + onAuthResult?.invoke(false, "杰理 RCSP 认证失败: code=$code ${msg ?: ""}") + } + } + ) + + fun attach(session: SmartcarGatt) { + gatt = session + isAuthPass = false + } + + fun detach(session: SmartcarGatt) { + if (gatt !== session) return + val device = session.device + isAuthPass = false + try { + auth.stopAuth(device, false) + notifyBtDeviceConnection(device, StateCode.CONNECTION_DISCONNECT) + } catch (e: Throwable) { + Log.w(TAG, "detach 清理失败: ${e.message}") + } + gatt = null + } + + /** 开始认证。必须在 AE02 通知已打开之后调,否则设备的应答收不到 */ + fun startAuth() { + val d = gatt?.device ?: return + isAuthPass = false + auth.stopAuth(d, false) + auth.startAuth(d) + } + + /** AE02 的通知数据 */ + fun onJlData(data: ByteArray) { + val d = gatt?.device ?: return + if (!isAuthPass) { + auth.handleAuthData(d, data) + } else { + notifyReceiveDeviceData(d, data) + } + } + + /** + * 认证通过后的 RCSP 收尾:同步时间 → 取设备信息 → 取系统信息(通用 / BT)。 + * + * ⚠️ **与 iOS 逐条对齐**(`JLAssistBridge.runPostAuth`)。iOS 真机上验过: + * GATT 连上、认证通过、`0x10` 和 `0x15` 都成功,设备屏幕**仍显示 BLE 未连接**, + * 把这一串 RCSP 加上(外加 `0x17`)之后才亮。到底是哪一步点亮的没有二分出来, + * 所以两端都整串发,别只发一半。 + * + * `notifyBtDeviceConnection(CONNECTION_OK)` 在认证成功时已经调过,SDK 自己 + * 可能也会取一遍设备信息;这里显式再发一遍是为了和 iOS 完全同构——重复查询是幂等的。 + * + * 每条失败都只记进 report 不中断:这几条是锦上添花,链路本身已经能用。 + */ + fun runPostAuth(done: (Map) -> Unit) { + val device = gatt?.device + if (device == null) { + done(mapOf("error" to "no device")) + return + } + val report = HashMap() + send(device, CommandBuilder.buildSyncTimeCmd(Calendar.getInstance()), "setTime", report) { + send(device, CommandBuilder.buildGetDeviceInfoCmdForAll(), "targetFeature", report) { + send(device, CommandBuilder.buildGetPublicSysInfoCmd(), "sysInfoCommon", report) { + send(device, CommandBuilder.buildGetBtSysInfoCmd(), "sysInfoBT", report) { + done(report) + } + } + } + } + } + + /** 发一条 RCSP 命令,成败都记进 [report] 后走 [next],不中断整串 */ + private fun send( + device: BluetoothDevice, + cmd: CommandBase<*, *>, + key: String, + report: HashMap, + next: () -> Unit, + ) { + var fired = false + fun once(v: Any) { + if (fired) return + fired = true + report[key] = v + next() + } + try { + sendRcspCommand(device, cmd, object : RcspCommandCallback> { + override fun onCommandResponse(d: BluetoothDevice?, c: CommandBase<*, *>?) = once(0) + override fun onErrCode(d: BluetoothDevice?, e: BaseError?) { + Log.w(TAG, "$key 失败: ${e?.message}") + once(e?.code ?: -1) + } + }) + } catch (e: Throwable) { + Log.w(TAG, "$key 抛异常: ${e.message}") + once(-1) + } + } + + // ---- IBluetoothProxy 三个抽象方法 ---- + + override fun getConnectedDevice(): BluetoothDevice? = gatt?.device + + override fun isDeviceConnected(device: BluetoothDevice?): Boolean = + device != null && gatt?.device?.address == device.address && gatt?.isGattConnected == true + + override fun sendDataToDevice(device: BluetoothDevice?, data: ByteArray?): Boolean { + if (data == null || data.isEmpty()) return false + return gatt?.writeJl(data) == true + } +} diff --git a/apps/client/local_plugins/device_smartcar/android/third_party/aar/jl_rcsp_V0.8.0_705-release.aar b/apps/client/local_plugins/device_smartcar/android/third_party/aar/jl_rcsp_V0.8.0_705-release.aar new file mode 100644 index 0000000000000000000000000000000000000000..1bb9afe50bb6a10f09678a9d4d1dfee861cb6b4c GIT binary patch literal 664211 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 z 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ʸ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ÌsUt%YsPlyLg?^!XfVS9wS3l@XwyhEmQ7y!vp8vw0 zzsH_G#-3kCvmiR_w*uxZ75f5~t%jfH!fe{&E($@Ka%_j29}i*Qy3e!#Yiy1QldEK4 zehPwkt*zs}un61BDdajtEBtD{ZLOlMn$H5HfBj9-i>&%NsQRxxIpja$@JKjX$(T4f z8JL;;Unb|b5{ek=w>90~KGLBT5?W=kr4TZEktX7xq&y4SAhckh&6(rcZXan|TSsnm z0pH`ddC9^VY!8DHr&7KWu8+0ZJKNfPixeX8h=o(a<#opk?@hzagUiDTUymI~s~_@! z>rD0*t{bx6?s7fF(Lta?1)|(YmE&9!F5c>qqFh}jhVe@faV!1l(U0pFb%da%OSNzx zui9Q*y~2ZQL%FyPp632mW4K4B2(K>xtXIJyhtXOh?i~3shFQ-qZM&Vf*98hdAfrmP zTQZ;lw{KSFZHiQjy}9jh(lhxc9eIfH!EmTKDD5ekJm}^@B#(G^6@S7@IgR0ldpZ8!N=rXrQCVa2VNTnASnxb$jgubKQF)>@XX>j?8&IaK=8CphoA zUZ*~g8dfvkGdMY{?IZ0v4FF#-#t%B>xNOcZW(5m=ju3Yh2rx8{Z6KzKlt*|YS{<9u zNWH-Op83ErEY(95c!sO6&)2#yf7$t&4rTb%!%s~2;uRh_I!Yr{L1i*VmytH&KdKB3 zws#h))E$E7iWyxFdt;9kzQ-~Rc!e~xXc1Pq;y@7s*_ux`X8#qdPFjoW^jPf1qDfaZ zDs4eE58^MI(on>I9j`t#3$wtFFwMwvU0m&OQ2;52%5kQosVqUc3qptW3Ys%)4?9xC z|06y$pG|zf-DD@Z3wPkiX2c+#g<`@*|5TCEG6VaL`^&8!xiv|j>K2s#ywy@4v`V=? zBpa84w7woi)Ip}ZwYtDR&j!NC?sQ5sFX`h1yuP(b$?<+lR@c`UN)35|QD7bXhz->+ zRXAm^N9Zw-3AlW#nbgv-^mwN^zFh2ig9&Y8Y{F6oyOn&b<;tZmA!`~x+A#UNS0}|5 zBshCe;52Z}a+Jgu-U<1WSE$7L>V?CH7Plu4w^;5vlUeeM7PIi#dl3P3V77b1+Abl~ z066(Fq*I#p{Yx1v&5|*=BQ>5m;}NT9fj^7IHf8Wi(m}v&!AoG96HWUxT+S}ni0!o25mLb;YCd?(a@U-;RmvYY?$FL$ZzI9%BQLt9&8L(f zh$k(9WBG;MYP?Np?`q^q-525-s-Md*V}13eGs+XW#B#bPmR0&-YY{(H+D6nzaEoeK zk^a`fwi6m_Cd5~mg}XC6^k?RJ^I`RD;kQ|RWs&1pwXqpmim9H6QwxPweR$p)RduC> zm1Jx_5vs+iAhsYU5oeY|XK_#Bin*zl^3S)p!)d|oA;l0x&9Gz4{3WU63E^9+q<6A> zfZDjvb1}tELX5H{#Tznl+nw<_2b1zM)o`hJTNoeGQmC7bhf^!F2+4>Kzmeo}P57Nk zkeLOBUL}e$GR9e(j!_2xt6kO zdb~Wk>fhPy<&L9A!QenZwFv)6%uw3G%-mVX&eqw{&idc)8}3dEqNu**39AmEsrEq) zpf3a=frLkpP_ygNIM}FMtB$?DmnrHEspAkxIAR?W=aaV~x^6z+3w#@yX^q$6@pE@_ z^@)pu9UNdYZ;gMY{8lDL#K_*s#NCbx3I5}C8pnhYIOzOdTFV2*(6F2a7 z$_9JRG|n+6Kn9bkkv6nUhV==wKP%s?@r?ZethG5)5p&!k=t<)-N48uJS(!US2-%8o z@WEt~KGHIq*p!&GSjPg=krR%CGy8z_5tCBq*}bCE{$HmqA>J6YtQNXcza;BgJ|-Oz z2|Jb40(aU3nUOimgb_V&ytIf6$av~55hh_cDy((!WSzKW=E)=z8<(Q#k&T$2<8F35 z({-W5rB1EWV3(;rOco-WY)7*KUBhUj6ZH|vk@j8O`P(f}WjarqYz&GS`HzjWHEj}d z5(&*UZRi;S|5wb@JOa}@=rmznacN{%j2}AhB15s`8bU0!Mw}}1$O)??u#HlzO~r)$ zt)RFEZ zTEujs%hUY=Fiyx(?KX|b=&F|e{e&<{&5CHJjtc6EjOg%MtJWyXRAgiH9oll}qBMsV z)IFDyd0dDo<^=npzu6!ODxAD-2X>yI#j7)aCL}{(e zC7Xi&EUnDcY(^)eU92B8ieQIpCbH5e{>hD{-9FolnpiC3Iu3N#_E)btnCR=3-#G_V z46G9ltC#X8370X}2I53~0MjE9*b-o$ceze8w);oGKBbr7Hi2!X$twi;v8de`G&QNh0QTDK$jHuhe(eA=@EgkwdM9!jYnfhm5d)&5B=XXFlS2&v1cV>c_H=>)I&*i&&ExQ8a= z*pqoKc%XI5V7J>_qEL;{l%WikN>`_+j>r3n(1Wo(^tE`H&kDBj=>6J@aMKq8$SWLU z!fT76ogjxyQy63XGs)z&{n%`Z@k^-MZBI&Cm?R>>@|X55P}j%u2UoH)Bk36KJ*(G2 zNX@QRC2zGR+h92(ZFwQwx}j-FuOQ$o?bFb>H0Qvb&f*RIm zsjC8K#5;Bmr(Q@0@pF$e(HCr(HEZBmv{8%2ksjJ`#pZ)BjUMGVmHPUL(z?p zH(wFL0Us|xu~#o1!ukQBC%1JB@w3|?p4gScBn}%PdAG{z#}7*`2jkI{*`zK@J;<`|o9MVJ)^;!1bdzh^&2l`LYQ2ZH?QBEu48Xo=q`tvq+xCLlX148=YroHS zI`A$ByWwElF41wH>9`B0b^Gf(-FlC{<#vSLDZ-}fHEVr40ZH2V#3wMec#Os5+;EN*es3kK3ctl6@5h7NQP5OHPo2pG_7op_%~du*A7*N z;MruIU(VfzshI+K9|s}eY*DXyZ5O9Wj@rtM2cDm+v+mpz)M!G->mTmm*KF z%vu#(t17}KZB04EZ1DlrR!8^XaiR>4nqdqdF7dGb-b&O=pgIF+-s0^xZJUmm>)Hi_ z)YYm~%#GYEGy~p~wScit7_W(6uobPT-RJG+8d0{)uf%gUnBD+LfqsI4QI+}fYJ*`m z2~UaeAVNXq!)v9fCBS>S4&Ii;_$v-EA?yJRX4a{t5TXI*mO09LYh-r%O><-hD{cQQ zReOd+gy@gBC3DT-04N2cc!Nh@{i5uL70Qi#?^p(r0VW!?rUX&Ox8WnSd zgN(!lEiPL;!LpV_clhr=;z|L2r*=abz;g*?#>N#*20`L7tjC0&UlDOZ(Ao{k9mA8g zBM}B8V2MEo=61^!wr%Ig657-fZaDq%1fL#hK*ozU{(&9L&h8{#36JvRv8Y!i01vDo z-YS6$fY%X#4kK%xF#V938^Hh!w7tWDtgHJ|^Tgy1mb8);WP5P&$B0i6nlv4ul$2)i zn}UO2K4<#0No7RWs6n91dJ{cXTwNFkux|u_oT=1%VrzM_T%SQiPWrOL;7+?qc{iHs zTq$3Tts;ph!-Y>A2BOgbsOr(g4eE|e&{(g-c*3|vuf8V1`yhVHpRP{7&^7Go-dJv{ zTO*|_JMmN+|NX2(M%AAx;^T(8OTdI6cQBFAMDQ(ihEsH!!6Tp!W%C^HvdEQnDJB<| zP3RI#FURn~oMrqP-W_O8==EsFul~MQ;s9o!;gzuM{lci$W0y)ojH%44fB9$V4t<8! z=fQ23MiC=jwQHgB+;CyhykRj!M#(Irh}W{PUcgf6a|oBR$B;7To9qEe?sIM1E%>X&<*FF3&yMgGo9Q29pr$w|0I_tVZYU;R=f#p?4v017v2xS%ILGJ~GqE zVxXL${3?6NA3|a!w$CSSHynz_+yH-<`;kKQklzk0!pXfsM((%iRCxxPlOjmSvLWoBUfX4VBGVy&nbI5JVW6 z3?d3633uAR6wIVsrhIM%cl&k@0?8CnWIlnvC=RxYLRW*OnV3Cq+D?SFe! zH5yaIcW=onQg`I>wf0+W5Jogt+{;5*^gwZwHoGe&XK7CGXA*AhhHNfxmTlNk!%=$u z5P}V!^*@nH@lV3shgV@RZlaNIqXAaIg8CUp%309};$qCA}D_6lP=VgCG_7jkd#GM_>*bQ zl5%4rNf>5D_=qReZ|WKfHk@gFi7@PW}} z$3vIdO7Rz-8gnSoVgSq0kH*pIQ&HVH3;AdthO3w}t8`h>6a77G(eBybdr((G3aKKq z&KQ=&qA&o;%PSR5xe7Si zKO}-jj2QpP1|G^(?TAvfPbwHnLspy^GB>9)??MvX3&R&f&oUQpz7KILggLVi?KzOa zTXOO_bF-6q@_5su=L-~Rl(aW7H}|pW-&tho+1W`eH?|&~ncO5r8b_XXp*6{ zeF&~bD?6mKG;ZFZz0qJvDwVyi02fhmWJ#!`Sb@1^B5m0Qr9xbl#&xz+h6zsk+-8B4 zgxt0_7q?fZ@Wuc#jHpwwC>>RE3T_4<`?gj%3C^a)%8{NbHw7CSwSDl`Iapg^m0DT0 zUaHoRbT2^`4bAH+y{^y@qQ$7UYYEqG7%(?BU#xNseoym1!c1>Ux45tGs!kaVqJ))k z8B&G2;nA$2d+QG3#YO5yp$)R7iOD768XW2 zsae+OyiJ`bAC!;X5|kezKs59o))LgJc4}hIVO4|>H+!RU-KrO#f+(Pb(lueM*lH{Y zA|i-7C3x${4UNG~QWHxO(=QT(UK4K`x|+ngu{Z%194+klWL>E1lAibBXj@l|y|D>v zL=vvRn0GDJ;c}{h=T7S^J3cX7JYnrDr{kfc-L3{8@|O zU5CkM-NX0uAf$-4%!;oSQ~!%ilr4r49osb)#mR*MH{)ra5aOXugkCnxZ7qTswFRHk z?VA71r4OuHYIdt=*Y|(I2d|KPRLrj$$ZFSKJjYU>GrJ#X$>2JwcF{`knNgZZfm23#$InVHD%Rdj(CeVahjn* zkAK?_CfG!3-mNA$AahMPE@o)ia@<}TZrF7BU7h4O#!XL3n{yDI);=Y3|4T9CZmr%1 zrIr{cMIA~!DpD7_jkmlD-k-6QdZ^wgoMQqVRw!|2wLZuOQ|sAj#91oXxGoB=&M2*4 zeLQ_$K>$U_IO4{B;P`juowK)8YIXoRI4Qk$%1Nk|+upZvgsp9WA+*K=?+d$-KJC;j zlLZ=$UAjO_cB~;Su9gX;s8NMM&|IFN0D0CV+V;Ky>s^AQL^Pdqh52w9*2uiUuPKEz zipYi2q+@2|=|9Ot=uue=VgSO%X5^tatRaQqVsmR++~Dw^7G0x=_uDg}hB_Pjk}08H9C?i;$sW2r+F6Z6=k?islPKCH7zS z;#lE6$rV%LBsd#+)pIz|jBqT=E;X7N57@m{R2ar*sXw;VwE-#iLPNhcjZb5yzqk%) z)9#vK=MJyog+erFW=(FB-zGE{YO>AEp~(hPd%@6@Qon@$PTV(ZB5wh{VtP z1M!eh_=?TvsSs)bt{#2F^}qujfwJzTk5P!ipgkU;r>{{4Z$r0nyMO2i6PZ7_p3JHt z;N>RGt>b+AeRUPYqT?qc=p?safb}5P524`C^?Zle^}gT|^`Kk+zK z#C$ad1q2j`@{hP5f8kNa$?U)2s0!njpoZ!5-Dok-!VlNt(tFCOzQIydz(jGB-`FcI zF|eF01xo9i&|@Q+ZY&{L25ICp&A2wyHf2+4jtSCV8yL5YRy52j+Ucqo>!_QmgTFGvDvuUoPk? zl~*x~e-;WZWJv^oO8F%Wf_215TUh20HU5)T_t(Jv^%> zdLm%rPtt@kpN&z{z=sy65FxaSRUNwmWvO=K>#zt~1k8&@9z`vyFsG4^jW!f$SO}B~G-K2h>$(H1$-2IPwog&zs3F!ri_nr0 zEov!lWN1V_pY3s^r=Qv( zV9=&|?zQLB`V<5%JNiO#w~phdYtX7_>I(fRWpfl0k^&lcuf2(pC`ANns|wI5{Ip68 zEvw$Y1{@9Ci1}`)^i3B<@)l310k6WsEouw}Zrso<^nEghTnVv7Vw2&L)YU2sb^*0Z z9_idj$#}#S3^@~U)2x_bqc>EQ%?6~~eU3@*_6&-;Q#8u1&5fb0)e5m|Xi5dp_a?(| zk!}H4l}&kAG@?%hgJ*&fkP5n#NG*0EGZxu3~-5pQQK(m0DtkwCCl3ea(8}JXAqf16FG~7 z3kd95->VK?V~P-y3q0SEbkevCdakdOcwz{r+xq%RXgNpgDzWWbtv(*D3dXKgVMB}8 ztzajplUSsg)Nl8la5DsD3s>Rsuc&xsWTS4280#zPo` z*Xb2EKC+iz@gQ8TB_I^dy!76fUD2l#BEusp1oYa~-BfD#>qqAzrX%z<{lZ=AP01;c zZ+bpIMVy$JGB{D@WL>6BMf5^1Rb((Be+f&gl*zfUYA96%C)Nif>OEJ43wAP6UAigpP2_02g^h}PUAalMdSUvSpuRGN zkuTaCMqr(zdaDaX>(}!1)gE76nlBqh1w>g;Xtc^kjkCIubf@~^xcH&1X@6%?qgZR7 z6joh*8cj@aWN1ZOn{d>d9F2Y@9#k%}a}~`c+5vZew5!n+%n>u2_F@-VGtvbolIufFpN zDMMC+@S>5L=_Qr5N7t#1yJ9H+%5f_O^%^A zXc1sb;b2vgWCdpsB?1eGLe{v%a!OmhinD0p)rc_qkZ6eC!u8ij1uK&zGASH0yUer+ zdQ1oC#SYYaF17V8Oi93kO^m-8L%H0cb*76d;JL@gIVRK342m+1Y#t5hvW@oX^ML3Z zF7-&itkippwL(|UX0Z!vTjVG0Qg(ansmK!NDN_u^FuU9!pAIZ9FuA=vv~4K&yJDHL z+1br_R$mlT1r zvrMLT1yHOJ2e8bXKa9N3jienoz2Dc$!<{}5OTcn=m(F;yAEJ}qnT)78_thcw!L;uN zt-i5(`$$gqRL{(u;*V~LY281RjwqP`-%}1aXm1pq|#o;bz8-s0H;89TE zn4E<@Hll0uL9$7XJyDB0*_vE8wQPwyQNb(E;<(za*!$THc#gY4xGiQM%|eKKz~A%S zb-4dh=!T!ZS7G39JkfYdQJ<%e`#{rxBQyT|Tcab|GMx_!1PDm>$3L32mA5uSF3m{NtPhNd1maowgp<) zi1CF-Ph$=W=Ih5N$=yL#)g+I8Jjweo?aAx%pG`W>WK3Q>+^#Zwbs4(nqJ{dOG;__W zG<(n7Mee2ACCg4)@vZbthyH~FJa~(P*{B}^Js9fPHq}4c4BfLdV?0^WJh_pdLbPL- zYhrF%J~UAP;(P>ZAWut89~B78l>;<@z`BEHZ^9gETFhk1o-Gwc>W+$?52D-4QIQQ= z4tc@#8rJXI0R91s4$MLTv<~lX^ReuR&(ftNl4-2zs0T6b4=aX3d}^`Za+r!oq9!SX z8r7HS4Ek83yU0Rxv3sj)!gw4%P$&>@GVfni2ZYfR5}Y|@Bm`Z_ACndgQt8y1k9Ldo3nR8;kj{%V9YRyyf zyZmvg&^)w=vUAOqcf1FV_7T;hjefBj-eET3)hM-cwm0y{DP)%V^i7taxN{EACGgeh z;jEQZ4ArD^@D|7nYFZi;>cl|Fzx%sW9ltAEgk~s&6WU_Hhp1!af4)WjFbp9X0*(JW zS4S5&hSmA6JvSr}5ZnJASBfSsCXR+C|LG6#KOD%nlu*=gcv8HO1Mtn!z)%+~g&;*| zL7-Qm&1K*WN&gRPXBkyjx20)<1~|C8ySqzp4el1)-911!xVyWbeb>Xy`3t z6THv+P%`JWo$UOCF~U4MQuA=~I`QPYK9=+G`i|Q}F$d}A@&0=LIIB9sOe9m1*%r^L zp|YHKq;8#T3z>WZP+PCt>!Px?e2fpV1`3&gq;K*Js-Mf~Du8EWHs$I#<+zO`vd+4k z!^40CO?#hVzec;&wWZi>1$Dc~9HK4Zkg!x}2` z6S8r!^3wGI0Vst=JGt?j?R3ov`q?dn0&f!6$$k3vlheXyKtS#7=&kU!zc&YogITqb zK+WmeFZm~rAy*5OenT&1FI1`S!~HB_Vu?l{KjNGL6nyzyc%si@R1Cv#Ag6f!{beK6 z;pr@4NGeE?qy09j0BkQP(k_5%==N_h9$g z*n!sl?O|;*o-jo6)z*pFs=AD*1D95`v*TC(5nAt`i0nuqI1*c&DtKR!D&^pBk5;to z?9#(p_C1FZp1c$*tijbb6i~6%Y8!RFD!O2l9=*Gu?zU9My95UaT~~f*O&C2;lH=GW zqirVRr|=1WRJcm(GeF~RBWu&KmN3-16d!aE2+&$X=B^7GpEU5dVYR{J0cP;Qw4H=o zXTSWUUSg+E zGP$jF49NTbzTvW7H&z}M4!fp8bG)${s-QNhFnEQ5WgmYUF(6{-Q0GJ!RC#%>O2w)j)QK5p&Ka z>+5CuQ@}PPpS)1N?3k@yDo=sBDwJ^}Tr!#cV#TkFjZYch7hyl|Lhe``tn8N~z`kFh z9`a=9#lYMy^r7u|zicYakww7ogcIFk9-m6X|$V6Ol|=8^4|jRC|_Gf?lxk3+>s170!P z-(O%{Hy2+pf`po2-o=uJOr3p)$|P*1emdC368c8@0Tq$k6vcRtndRdn@M3r^0!uw9 z8EuqW@7JrYLXl1Wt*Sgk!J#CZ#lZ^7+B}ZmsfM+}{M1Qhe?hJ1+q~GC!>tIM{pu`Y zpm+0K@9|a3f+lpq8TSMQI4xQ^3-&$bnImW-@UN|5P`ad&tjFek{0(GAE@k6sfBqn4 zp#EF6u__Lxrp6Zkc@x0)uOo-UAMX4%k=Mkzq09toj{Q;K`H@rwj3kUC>CB?HNv$W0 zI+BZ=w#{6S`j4JId12B2=hPv-lxXs8cJ@to_w0+1d-uodBh)v9NgTnf>~pN>dAP-x zA8Kk`YHy0;Wo_#&fP@#I?e7dXHN_2#;;rmlqbzUFPR3iZ>iOHbaZx)j(h}ZAp9DTn zvTrtr!LFc$1%}KEA)7Qxij}^*P?@m4nbGT+<8ZHdFk`9Yv*d~hy?%6n)^Rllzz|ov z|Ml=VyFfa;Oig@sDp=j^$J7bM$y9Vfj$uddsxDir+U$lpuE@hKwn^xsrw;xlEdJ_6pwuJOk-2)0-q9U&(#f37>Yow6} zBGiat3ZhW1hhN7J`xM{B8Y_TG+Nu6zI&=FV^PB&<+8A?1U(~K4D*SazfBw28s?uNG1)^Y;-ffjj&hQ=&y?BD?dLFRHuSRo<_|Q6%n!U*o7O- z+O3O9}XRqES=O<0`)_4G~s?nKGr<|Fk#x@b;bmRQ`=MFv}$*&#DTqrlE zRx(WZ4bPd{&`*7pG&0YxanG-1Q(9Vb4dPaayC??Phj ziOA7>bO1`CEhApf93UoBsrP&64_O=XlkJ)tX6Adm76wHjHg)M92jh^!GVumh;|8WlR-xlltQ`A(E?r1nmt#Tj%|A?B(uCMR*^M8Te`b3G-b$Z@K>wj&f zYcp1J&fsA*n{g+G-jKK-7T%|fJWnwnH5We|kJ#*?i>jk+GkivTkIC5@{kw9}DiM5x zwoG+5j#_9hu%`GmrF(fH9gc5ipin0GdhNBd_2p*cz>gXD>NUqH0-|NWDIVFhr!7m` zoV$n$)#*~3_R~A3CV7hr-9gK~4D*EX1zeQNclG;@_X9uj7ZOR!R6RAh;>ur?PP_LC zD?R1M!Z64@QPT#GwFqcsF@SxJo-m00OJ$gdPJqGs6>jcf<~6mcUQg%)sU(v2QjsKj zmRrmcPF-{dmKZ<4j4T{{Tm>Z@;s_unf@)YXjo14EK&FSGycx%@t7~?M^gG1V_)!wr zy0bF3`jOE51C3~MP)&D?Ea(J~uhtpT{d(GrfheY%rF;h2giV6FTS>)q~Y5yKG z<${5;*2tV_CVs=6+(6)g3r8?WYlAO><8)Gva$RUk{>Fxr&Y`#9GI)AP6FqAe$yz^u z1flyZ0}mZz#L2K4qW`~RrY3wtUd;BvH12t~az)KvJ|vg>*b0QU&Iwe`Y3R{h62UON zg6e|JN+cgx7Q!0yo2vjk=)w(o=o``*%fnT(7KidTeKNjn-(;yGP1^J z$eD)^O0|}1b{>bonbNW3Avb`29nptU!qzGT3vCjK zN%dJOl-|%J(6}uFM3RwRaA0j!TIFa3bW*dWCchRAQAptkVc?;gM^OsJeHGeql6g~% z;^(>|o*Wc}4Vhh5wPR1{>^C%nkzj>_CGa+RTl}H;b)8_sY}UAbx78*Ze97!4_|}AX z*f>KD3Ck$~bs~}=Ra&{PGl&6tSg_G$gha%e7FA8NN>LV%o2HkGO{B9aQCZwPAzVIu z=&4Ri*#=HUPZbb!M2PIS?7J81L~91nc^vuK^5Y#DwS|7SA;>e>tKfQI`Dgh!P+mo=NQ`tk4FzY> zAqx-b=Oey(%ay#0yW+g~9!bNcgHXRTC{IiqGgY8XB?7Y|`6S9DKSy63Zgr4!bfx&2 zl#T2IzA#DnnnTZ`@&0`ApobteA6H*|gsbXp3^_tWvL) zcRHsllA;mB+94|6r+k|qF#1J)(lBuGL2$f&YTkvoCxIe?A8u{$)4E;CO;Z^TJZiK= zzH$3YPn>d>-is-jnmiLLZ^tYN{}2?cq}%9?led*U$2P2dfpXcD)m~J&B*=XqoXXTE zL@WADwU1_FCkSxRk|#qDIAeEe_IEs0y7b z$9<&?67))cqnh)*GwXAzmqbk5Ao@5Jl-ROnlhKk&xc=|{ltoOyASm6(o|`gch&{-( zqKL-~^HC%}G#+cC)g z4L~6Yp94YPMZvc#-)FR!TbIkQk1v-chmtR1Qw_8O{>@`Kt{?q7-9hJhdXkG81M9*N zN=kVL{qG9gw1|~8tvbsM8p-OeWLsxfU|)x;I#<4zU{+vPl(0?90H;vH@AVcM+u2N z?E*u7hM9e?NNan1NNY-kCyw5n4|sen%>uho9)sQoWLFX$4i{cKLmdumM7>d-+kU%Y zcn^J@4=8IbSm#TKb{P>TH_nQ7JkgaE?J>xY5%MnX0ItU#dArMijFl}2Nf$X?OMEJK z$-;yQr_gR8CGsptr*H{DIo7ahJS@NEtlBjg{$iYrqenOR@ZG#6mW!#8&0Ms3LvEWN z6|{&1yA4NEdmT&fR`Bx-{F~!k7^wqh6gsz&o5cp!|Oj{ zuE|>yO7OD{b`(x@j{EUy>3nXDc6_v98>?!yZUc}xF0bsoy-$8-OzvxED%{*Djb)Ed3qJ?{=bz3g%bNOB`Np0KK@Hdw#U8yD9P0yB}w{ANt}>5$hRe|MvSFH zbodz~7-*Vyzao3zWath%4Ow%IeX>tcJH8TAC3OCxtMXK_d1@iw6V1-jimI5F<<0!! zF!8d6G!$zP!z=L5Is)65bLjGb*jzxoKB3)XAefut^^^@nn~*6hA7rJF|cxoXt=={|>@f`>WZYVsU^P3c#31J&` zKwXKEL2S+fj6w>pagYROXNy_doKoMav8uDV;r@D#>SX~-BSp`atitVTDde4;sO>o` zZJV;!bo@Hg_kQDmZ*$o@N8t75B1aZXzZVJhe7%!z+MAEPps>13g3^UQF&n}4$4u)} zM=@PfG8^xKGftA1%Dmd3vSmlPX4X-K)pNR9YO~0&ImWs&pU9KVK}Y<>9Dbzn(MEwx zdY9S7_4{%lNX1c)gCSpedeybGz2ZRe@GAv5Y_AFETk(8CI!Na8&Ff)i@v*kc*Bs7S zbwOIiTMLO!P|^IMYVkm>sb#co69D04|HEARnzDWg*Rj*zAjXHA)x}Hc;nQ3*~vz4SSr|PXW&x}ps*C5{S5QW0;X)T6)sg5{IWcUML8b&M}SXNEhTa`;9 zB{afEE!>JkQAcmWEw5Phwq^TmnFyg_y}6z-ZRBHyzE*G<^8`^4^i-gho7pWNn@nsU zA|b)YOHShrpx_&?{g}S4{KOhM94t!o9NaG)i>_l?qv|~u=3&nLF2p_RK_CiloJxg4 zwp}bc1gkMlT6r~R7jBa2#88sPt4-MkN<0@~wmajEufs;~^qsvr> z`#js0a8Fz=4sth234JB6PSWdAXKojXPOP)0LE&hZ`7vz1NTA?D3lv8m46{w~n5P}D zp>h^Eh{sO8!rZ|8l;svBKzb}7ClHllp~g&BdE_cj<~de3{{;3~xhS>Ri7snw(Hj+C3i5Q>+t)tHB ztwZjUi|W}$Ly==1fmu|G;=22VkXp9?2Ze){yL^6W_JM~U_r|w$UhPh-$$FfK)v5KHHCfxG zrh91FaeV`mZH#U?BuI)bc>vEE@CjfN&v*={hHS7ItQi3jJ7vw)0gbTal=xXnc$>-D zMG5GBO_uH#TBNTfHawZ)t6gtsN8f_lkdfx`n%p4(6(r>sc!Aa4DXDUwL38TxXDOcxBR#5JaBzxA6`E1 z1im<#aIXRDmzlakLMa+)j&fId4cv4kS&b;)uYUjNlV(dutFA4ucN{lgsXcQYkgvl} zF+X-xuB>3qX)Ha?Kuc>mzGnLRMP+fs@t1r=>E2J%eKWQj=NU^TY|)x;?D9$W*1YCY zitje!yKTu;hZpkm<>pZ0ljk?a^1qk$MD5i*yWGA(ZW)KFCK^*z&^0>UyO#CMOMv-7 z`>Q<(i$Eur#2EAaFzm5fH~}s@AP2{ABteR!R$6gX)lO_Bp|t}9oCI^05VoQFzT6V` zZ6&NmXMBNV#ugD0@ojL8$eY}WN^z@02BKhmB8y%eLG3HujZz^5#}WsUtT4JP?j%Hz zjzdz4_n;e&rZ}`W`F!p?L<=j)>KsG=GVGmWs93MtgDz`(&lxGwKWAl1EBy7;1##jE z#0>bjShcZw7UY7Ef{E)T7Hx2TrJBI0zB5YJRylS}CjmCBA)HUl?}L6Y$Ao})_ApC? z_*7liA~Px0W4D8$uaD36l>Z>{l#uIsD{{bTfYaMZJ6#Jo?FsSH@Ompf!R-ZWbh#EQ;6s^2sZHllkUJ z=5B)RwRs-)Sfb%rVQ7-Yxltvis`DT`X}zZ4Tyq&gwp)}ybloY< z%l-rgMh^bpIv1{C=wfW4V(Q{zX=nZ)ACsD*e8iuR$u}#_gwxoK3uF)ih2$K&UbF1z z+S?L}_2qL5oP_!K;gNWjIP)(6hv>@Cn3dWu0sbXSG)3>rhzqV@WK-GE^+vtz@k1 z#s(y)j4kO2#GVQ>es)yQ#e|eU2-EIkcKSa%S^^;8Y3bWpr}+5Wyge?cpIbhWAS2e* zDc-8$p@w?;@z0vL@UvaOncjH(Hrhd9XvlwTbg|+kK5*eZD%qv~&NP)h5*!&NM|Bmk z9hnF}g?x!-c>tczH04pKaz@D3w74mRc6on4sr`8x4&_^YFamoiN1eg*?Fsk<)8t?Xdu9&h%JIYCx=(g-JORFk*Zn%*ggLhp) z=gj)Me5V~x(N*jA7XD>RTZJ-&_DDziI7pL8=9JYl2omK!q7Cx$jAmmS{1;G$16k7ZrCsy9#Lx5 z;}y%5_+EBTl|(ajUFNdkYP(|RJZ~B72yF$iMSGl6Y7$#!{W=$TSlbjJ>UN&kfAII) zfN?;;0~iQ+*5P~aO*-ENP-DH$`nmQK-B%>V=N+xh(EgSxQ${YVhSPIUncAl0B0DZt zBuZ_JKg!wIYNP4%E5N34B+Fms1Xa}1fKZ!o`8v9lW?hwSBFd%JrBU#5T37{nw*A*& zhqgvkt<==k7F>FnW#0>Q(x(~^le_fQ1xM~P5CiA+R>TWa$t06<}3?;;{1?|=A1?kAxkTU8N5`ImX>a)TE2kat7fO|(lYAM zCEiW1nx|9@2x2f_re(^Y7_Zx_Jt`!MEFtIRPJmeU+qOuI+pMCKS8QD1i2-Jei2&>2 z2x90q79g@{iNuj}g$Q~k0)Atv&GCp87iysJ4^4>X1Mb%t!HkuE;oYHH%Uu=)3G-1{YaEsO=n6%l6!L3n9{F*%kJH6#5mF4P; z*^v!-oxKj{g^c>Mw}CFP@eGcmLF||~jLkTKk_??(vtbm+tajM!CxAHNis1#~bi}Ym zQJUXqq*LU!qH3 z{Kbx?_GXxn0T=#c@{d7=zpd;jxv}w8vq_%NfcW>UI}It*Q}3WU>sh8l0jQJ<``b1a zH(@1OJMQ&Vmsy)#u)LHP=~kj*zNSYkSk@}(@|@X;ZitewO+y)KiF7U2BytNN@3*Mb zNfiwCosHZ!mStmkIAu4Eqnul;LTB%m)elF42NQwg$3p)`k{GF{Ss=g6b=k0M|Cw{}4538(Sn~GVCUm+uCO*d8 zYMdw=XVgk8Wq?w=)s)*WZzp*xpC?pPA-*cqIU%p}<848r@Ml%%_DW0faB<7mC7IL9 zcdvPN=~@O_PAv*?8=sx)$GsmPjxg9kOe!FC7spj*DACMU$!35d?lgmQRsO2Fsy0gj zRITkHX?cq5$&f_j4m5UAMv+LzE3>0&MPEPjlaSl~+V6o*H)w_oolJv_&gR6_aT6R( zWs)}PpMw1pstgsnj%KhR=heJ^4B(CYGesVJkdrC44eyw`#|R^CG+E55JvK#u>qsu- zP_iYS6liETnd3Hp5{Bs+XHNK9XdQ=0wL{{Qc85`fc$aaqXFx9=v9NMKPX{AYmU~r| z#bMxr^vf57byrJGQ3buWpUl^+ZpssGx(@k${)aS4dfB^(=G=NKt>buY(xZ!UCvu@$x!XTN$fk-`zb4|qG9VqS+@jhd7_(R+wM<9(K<^06f7LANHsomJ0Q2?9$Tw~ z(<=2)#@y%JcrYY%4}~eobflHA+%+k5J#z&*Q@LK18)6m)CEA3k2o~1%AY1T2$E3H} z7ehqMnXlDZY~YXvnB|Ncvg@MS%l?!KVaEsxNYa2vp|}+M)Q@GrON1^T&07n#^D`0I zLhV_$V`Z~sX44#3uqQ#T@?`thn{} z`Iq2)9ti%H?}#olf(q@NkB50_PQTBGR(3(OhNYOd3zi2VBB)#NwB2sh*52H2L9gF) zg)iK+R}bSJyPyT7-uI}AsZwtce>^yF>h=e}Fr7wEF)wd-M9tl>GGfo*KXV6O=5 z=f9uW!4g%2@47=XSj#q&UHIbR0bGZ^cL1a7}o7s2{7SL%+8L&5|FjjE9Q_r(tD zNpzgE;;w9}x#>Mab(TzRym5J{MG`0`hQn2dOD7fM!F=vqQW$+>UUwYqmWs8MSAOfT zd$;A5e??RgVVPMYRgn%fD}_)Gd*WB?B|c{;$4d}c$R+-*p71X3|An_Xr2UO(-a%oZ z02uS4aeN(`C{#99K%V2J+pmrA`eMA-N1@?3tNaf2&$KFAd|iKr0Q++f1}5{b(n{6c zS<2MV#M#v4zv7kZrpjN7s&;;8$wU&?)=FVIGNQy{Q|gcn6uA_b3?c)8XWS{{6!doS zS?dT@yN9AVFEB38NVmZ-e6zr4H=k3{kAf~2uk&@VUYn!S)9j1vmv!ff&V$vLMWN~q zu$FLp>@NQ+Bh%xwu8}CJeD#GAS7TYC*(k4hPKNWeJ8h6Q6Z|z_AL<$gd+YdmW-UV` zm0iK{@vP38(_pHdhLf7zfgHwe8;ffc-hgW{;(|Q~eFT1cpCb(|Pw@~HV~oPr!%4Jn zfRTBxewG2-SyTXgqENRn+}N)R%@~6I#v9h~B&Gv1WAlkCf^fAIDNNZ zuFdlpvc5mGio;CwwAPEFOe!S(dmyK+g63jUx>u&waR%`^dRp4Br zH^d?{T!OB~+{t0b@q@lxF;RSvIeP&68US0}bzwIAc{!fTCF)!3vrx8`iO3~3yW)k^E=U&HK2PYTWF3r@}$o9D5~8Ld7YB1lJ}!AS?xt*+N; zkKH%e*pJ=Qtje=UDcr8-#zixe5T_x0#C;ap7)~>=7`P1WVyPqXq7a(jF{klQwXt^- zU}bJnsIoNL+MZ4)uL_-6E!v@U=xRI<42KY_@7~$js6~HI02CGnm97V<3WSzJDTf4> z3Ixn;6ImP6k$G~{>&PMBiC5XxQa;%ip49{=V;@_o`3=YI&Z{>O(@ z{#C;KW9t4-a3L2lbhb49=irPYRUHL9N%VJUgXEU6aT1Ns6gufE(NO_~y(Eyh8OUoQ z7A&z~Rpo{_zv2h=&p^@@)Sib5N3sU7=`vMi+B7k~hxX;^*=g&fjOzON^XELy6Yh-8 z`x$R9n?ip$6J?L>=W%CMcG3b|Gp)mUNySi%rGUdj+zb!uD^h+ z-?(6C%#9f+R=LjDD>^y2_Pj}PPR`aLEEvZMWOzf_xhLSn!XG6L{5!rwvOt1L*wB>jyF0% zPJ>ml&>*sOkp@nFnUj~ABx)z@fCI@V1gz5f^2?NN_a7oj^X_^f(b3M3$FtKo7K<(} zP%9z4Z4hT|(b>W;p(Ohb8kkWW}25$fpA7GWO`Mg>iA941g`3I06sw z#N2%2l7Y`49c^>kAxs1Jnq6)1SN`v6r}jK6jIp{^rAP|qKpnuDU*}G{de!JuhRo!} zwQqK_XH_~<<%7jiiR~cJ)P4kf*NO80je3i*e-I7kk<{e=%}p_!+a1460nj?P3}+qz zggQTJiJ?jJOSgj@H{tkMw)+Y6(-R%%`6zS)M~G~f2$iKSXxLNCS0H}+~InX zL>M6`%_GA;8Oy(q6e@W?%$}%n|J`rz<+_rInB*zh#JI?vtBD>@XZnifTd<#W}clM=lX0CK#mu-B1VWTuO-7?1L zx#B%_S}r!P+cRj|>icP=2|pUoz@UMYv1W>O{0v!b=WvZJ+^T!1Y)LJuFOG(YO-XoB z`80$uiK{Mx@1lqS{SDnS($_-R?1|*50QD(Q@>H+-)OoUE0Y*a!g-a<$BFOjiTUrw~ zNo#zoXXxCD$*JUkf1hq~*y&22LFz;oEWP_P>+;X4#t}J#OEJIUv&|_YH6!BUfp5C7 zqAEs*xfjA&ThP8QD4w!tRCPX+>d-dA(pw2_B1o^I!t zEa$GxkLNp%?`V(d+ZiPa_K1Sf@)axiT(Y&>sp`>1#_4K}uA;84W4~0ZP^nt`5kL#v zH0E>K5*gbox>fpBgTS$JrQM@cy%AM4z5;JSU_-A;xrC;9ji~_$4;psARfVjY9Gl-q_G0&H^6nOnmfCn78iFvMtDxvd~2S$c@&Lg#j@7+;Lqg84$xJlS(<65vU>+) zJz9Ci_}&K%?#~oDEH#ZJWTV4$wS)P}y!52g!&~}AU07SdRTYWL?C-By^BxQpYO>3L zm&{hOq0E^dIk3{PIOIZfZBO*fHQ=J9d$17h&H!6;7ZvwO7RcQ&N995IFh{71JRJ$_ zb}1sJwQ&w{?;jS`E#jt9he|bQ1ZU){CAnyNJ54zvYAxQ@)BD+yaFnwT9&~MroNRD| zXrw+%>RGsk{f^-xhZ6|r*FfzGY3_lVgvz1Ya@$LkMwuVMYdv*5~ z_wkO!dgBRW@Sc@gpBfI-t<+(DS*{r^HK)A2BAZTe27`npB_{s5?Km{W8;{-SBfuB{ z^B$b{s`ehc@J&C_A!C2Yo87664}|MFsRW8`Dfk9%@DqF3#Colx?{)NowSljrd`3NV z$S2GX=iyQ>L4!V7MK0$#@7%fl$?`^pQ0ck6g)Y^#n z=7R8NTWY7Lm1lM~Hfd35hEJh>*8T*8t2TcO->|M1$iB4cqY7Ovfo~)58aGta3o(=n z5*foDT;T5073tLSS0^u~!w(YQySU8h+shJmAUVXI$)%df z<{aFHKOWKLrMHhy^5qv^zJ!DXy2o#u@VCVVx%T~~{Sc5e^T=+BqjJcncwzbGS`Nf)%`+w zXFP!&d$~z4Bk?KID z%#t?6#ZI%>Qa|)aX$a?|5=D>;_Wx1GciX>0G>MWfMKOzzNNod=L_sSc1;G|PtmsHo zzhT*PJpo4Oi7!haV-&@U7mu7Ao1z%&K%iML8hAp=947bvV@FNsw4QFLAfx4?sLfdQ z%`{#&D3axPNB}qGWv@vLfx|*KTS=#TP`@r+i^}~cQTEr~rM)|@*wDJ)dv#p4q?O3Jwup z*1LSxit~e=A(^|6BWwG?s&kk3dFMg)#r}oAzds@v);2u2fuOgWy%Sxd$h@nWs!EEA z6+@D2nOXmg%du5)oPDYq&@baCk{1wEF*j0CA*biw0ZeGqEokd^qN&KXSEQ?c;whdR zfh{Lp%zpLv8J~4^v0+~AtvpQS=W=^r3$C4;bt8t{!I-UA=t+~<(FW{(<@s!Ng!pT1U{4v{H z5sL+x!y8A!U~ZPM!r+#^O3v(*>9hIIa*|?5#m`b`Q|9OCoT7N<`ngnR)HoS zy~$&jCiNMQiZv*vaGb_1RFROnBHmQl&Loyg)3!M#+1zIv77u=v4^MXaGxeZ_qK1*! z&Zg(JE`Ao9NfQUJI&v~o3MgR44xt7Nl0b`U_VYSp5$gOhPkMWRfI{bX`YcTY#S6(> zC0rtGjxO~%Q9V~Sw-Q`BzzNO;-sNimVZa346x|dQ)H7sTsc^TjJuNfw6nQ|YxUHYa z^sN(%iux9-?)FJ0<_Ws_din%C7Dfy7qURw4IK$W=Hacu3|B^{|#ZmB#?fvIf@Fesg z9B@e=222k3xZ`XgjoM!i{P4{?4rq307VhKW))5H`=I52u2-;I+N=%j^w{Vu{5ona`87E};R?0VXQnBVgYs6|hpQ zPz!Q6FKVUJu!m$1HL2Gs6(YSmCWAm}%LvZz2 zhj87n(W;kViwC6`K6Ix2-`u22qWkfCB!?Ka(@IZ>8CJ(Liu1WVaH z_s~sDHE#g~m$q0F!MHsSXs^5het}I4c+0`NLS&?uiT(w@Q6>lgjygW)Ta1|=X=BUw zJq|r*m%}@iwyR)*Dgg;!PCbw#%=`mXR^=@Rszqf8;*|J`=IU9kL}bQ)mg*@Vmqw;1 zD&MeLH79DvDtQ;qvEVdn$PlC`y%f&LvRZW~@{$xFN|mXw(!LvhrakIqkYK*|b#uW2 zG0IE&e{Uk%UOh!z(@cLs>zWY2%C73QVa$k#WRf?B>F@q&ulSDfwei`E{5YfDwrga- zhi&CN!$-se9(J41dVP$-DKY{-MJyV&H+zL}?VjTXuqle{86dEX8bp15PIMUlTSs+}e9w?#19>j&zCF9C-D{Fw(Eejrq6KPx^oMp8|*OaserH2fVR7ju81b0;+QEC-~1d(LGL{ zxcU!56D$feL%0Q5d=PihuB`E&{#GIxaC8Fk`ez=F`T2i_)GD6NE~d7BpNMZNtg55G zGm@~3|C*e^#FQx;ZX=ifJOwID>`Mltz^kdsvkZ_=U`hFQOrCs}tFHD^BV@|t{bhyL z)=;}h@ZQjWw&8runh6g1N?Ggv>6~X%;NWp>^8IDAdjq^BiU`}!>+aa_KDem>Pr=hw zBV#^NfT0MdG2B+W&3vK!NX9lLVRIXEQSWQ7@47tR%bLgW0v(96y+nsm!P1RKZ~Cl( z#(9mSj;-yBF4fD&duN+z+-@u%qbY@?+rNdudM`r_Au}u-NB5@4N3d0@y!{FoVPJFq z_I8L3%0khq{KY85j*!h_H7`)F>uwU1Hr!@@dZ44XJ9q#ZrW?B}CrO6m#Ub>un0VFq zRC;iMLIDON$ra~DN4z} zZ|H`);Uc{hR&BpJqYgMzDg%A&$`q%41Eg3m1O(g4^A{x-Rd1gT+rs^beEX1_T!)M3 zw;$aYl@zaN>_Xvko-kf(U53zBc`#tf#SbY(huyw@N#A~6zA5!CP8zAcG-vlf%?bpF zHYeIn+{(16r8GK0O`o9`7o-j_02!;*Z}Fe*gRTaS1N=(O={vP29yh!J8ed zpv(qr7$xEc_42d$*RTT4FWdv1#9UU3tD{H=gmiXn=5zZ5FdkT#u9>DDL_}$xc+`Bt z3|V6Fv#7JCTVJpS-ziX)tSUQ)O8a3*Cl{VP;YcSn#B4^KwWAZQlD3WD$&e|a7I2Ih z0#s(m`_Wd1l|ACSLwd=vj*cM}xX)K!-+7sa@Zmj2KVG2;%YhhLUD=dkOpg&@Rrq%QV}PV*xezp_R3RMa73tvqzMw{t^qWrgnF9!kL7cpMwl!%;O~VzgHHEZ z%wYC$9|N@~xoY@pNSU+LAPkTypFC8z?0xttFWm(fAQ_)MG95O@pk)yFpQ?D;O6QP| zw5|5N`yfpE=Ts8yg3n_P5l0>n-u~8J7SM#9%KOI)a{ypq;{X4&`8T{&ssGh*0R2Pn zW~2>0(m-6QqHG>n5F8TR=u$*DThSSjTX8Rl{Qzhu~tiQQ(;d{v5%x?F8y*pt8^Y!St91MbShIkOM z1g)vVr%ip68UgZ(%CH#BxY$_^ifDADDvj8cwvEas5rQ1*Wwn%&R?T?qfzb83T=Nr( zG>b_GMU3Ooj`}!<2XIfg5KN2aV{Ko79P`XHv^dah-rjAKx4`q4UhG1XS{v%)mf{LP zN~lml)Awn?zG-8_evN22C(O`^%iDzYaW14(;&A;37Z{q zFl{Ekvaw6lSqp&xbm0QgwQ+9UgZaMBq z$HULzSUv;)OS0aFCDYO=K`oEpEd^_KMBQ7k#E8NfaD)WUiF<31W0i+^>u|LkkX%t zFgo_Dnm@Ja@8Lizq@sTPi9IA<8zu`F=b10}UaSsYebBXq2`zqi%~^%Wwv9&T(m>wBHSLQ}qK&|lD^I^6FcHp$=U#x#c*SY8rWga{%muL2u?-mww{@_ofMvPhqU zJ9gp8QIGP>#@r-`l8)#KD)uM?{uay2#dXZeD7FeLmyiGSYSBxAPuao9NPsq|GelN~g_NG{x-k1Sn->?!>J}iNOP+msi$368 zKC`)(I3RBVj*+R;h*v^aa3`MnUa5sf0m*B`Evyni7COHaKe_<-+^5FEyCCZ zX0a1njxE%BH+MIuK5=k= zkBiuudx3usZb$@v$`j4bArSJ4pDiSvY*bMq1!h$6g;phT)FqiSt?!csd5tUnfT-6s z2W)JZd!ZZpqAkw}q+t*aiczHV_)DiVxG_w^%gjDKBe#ZVKJeQa*^*n_6 zUbpWsi!?1~e2&XE9S)Jp@J^8thm>>6k|wCp6KoKce441|0xch3|J|HxRXEU2LB4z` z{;7oy5fTN#3A7yY~U^oe3+shS>&E*)6&Fgn0BVX&RFmWf!iPq6mwzG4$ zX&xgE%b5s$g!<iyX|-vN`JGme43p; zFnZSli6Z9Sg40!5Pf0N>RrEKJgOS0pStMP$!xJgf6j!U1QNc2ws|I>+1Hf@A0(Cyh zneCou5zCGBpSl{(oJ6r8KFQh6YEr?Q_rjP(3q7XH4Q1eJsjXx_d4f`a3{0Y|V+X&5 zVWbKZ!bs$T$Hx)olST11M4emC!a2MsLJ08G_cs+ysYAecc&)Zdj=_e``U0-zk&V)h zDW_{lK-c1R){j(`DB5-9chDfzj@d+pow*URcE&&aK@7CT4`Mu(tyWF#@s6-&ckYvl zx_hdK=&JY%q+7p7N@Yp_h<7-T{8DX=k0(qmmY#Sx>Fk%H?OYS`92nIR3f0u0Vai`Y zrO=oM98F`-aYx5(pmj-VTK1-Y8dI4+P%h`xR|%%~ndvH>lEQ(e7k#2ipgYMT(|%IM z(C&)DaPKczN61!B%NQPKBsaC-vZ)8Zey=HAO3i*eaY);fZ-HEqNd1z*JFhoOBW>gS zedw%#SB|TIJAST$9z?~&2Z@%@B>%m+Da2~6#_p?n11ZSdvdseWE>mFt1gR>Pwen_9Vylf$Tu+@P} z{pkgycIo(H3cZ1LRl-y-uCBO&*D-NOK-6Dl1>Z@O+T}>Wb=c_vl9=XNiAAU}rC3#z z3^jiw^dPSHTv&W{2+mjB$q80`$`MvW?VUcUEvJ!brLVEMU0Y~50wX2&{cnPjbXRb= z{3EE!KYOzOrJ#gu9UM#*JiRQ;?Ej{z|2<~E-`%RLiijjPx94RcB?VoG%D^8@gzT$S zu;F(|R@>0JUmF|0?V*Evf&}{qo{l3CGc1{{J@0xA_Jfoz>DVE{O%tEF9>@6~v(w)n zZs&-<3-K9xc6EP}byrk5o2V>{*{QNFHdLB(nJqPV8uGYT|3(Af$^HfQ2oAo~n!~yn zQhTB?+Qrc}L~mfq-ke11!f65E7LR&k;tV@G_{=n@(8Tzv(|1cv`}Mi&L&vZAwXqWm zOT>4x%oC8tLf^|I_VNOtrc>GamF)$%JY|V2!W>Mog4%HW&0ep1-3M~-)>~z$$EX>j zlDW1?4eg^3_QNVQKa9!sopDL_mm1P~Onx@8@rw%wsE&ClA*UT{%UEvVY$Tkuby1wY zEK!Uo9!-L%q}=BZoV~F8a7l(oUnNon%IT=vgmn}OEqNjU0AjUSis#2n0u+Y3E;1n8 z9~z%!)(g#R1XLcqXqGkvtU6Z)(1v}g4x?lV$4~iM23B08Ab_%#7$f%~?i5Xoy{Xs> zhtaAAEki3irfk1$j<*zV90oq=yB#kFM_+a~4zab{Hh7-k9~{Hn@E(ayQ>>N*qP6m# z&gFb;Vkvm?R(BcL8090fz$|`a=`KJ5|AT{BV6kO;1d_*ikRCfuTNQ}s+|bU zwppadxf6A$DgKPY+q2?9{74Xezk`iYhsy4bgWUJs)LiPEzo&JRhJo+hhfKa#lBy61 zMa1TO`G5&t%3`zNeS$fpAeKNsx=jWeEhCgA>2r7XNv0IvfkjPM-9Sifzudy=fp)b% zlu_{$M-D%|k|ozy^aa#R-SmQIy`&aC-ayq|4~>SJ^X;1onnpJ&Nr(;*Y(+bvFieu7 z^ca4OILIahZZYcQEoy!C>)qi8&Be$|#R%uQ8ngP~z?w-Fk*yfCjH3VFf^x(*6o2dd zSsz0E7tNIa6qbmCow1eu-wrC(EfrifEdEq-GI$xO6GUlh@IXlvDC$COn1)p_WHcI- zLJ%5;pRjZrzpLAEhY;ojp7H~NSYu-U(fW<&_HrB)5FQYS7<1p=t|MuTu+SCTQ*)TGkb z34Q3^n%~~unyZbOkk%Oa~oTif~JsV|OM4eivNYN{s=cQiTk2#@VVcn`F^S5gN2 zE?6>ccs_Q+KJrUSn7Js3iVBVu7gdtR-`KerHHq{QE44)61ZO>DWsRs{Vk?=&1;_SU zN14Zklfw<6vS+=^v2$BkxYKot3D9DLuhT>Gz*^G?U#t-YASK*c(N4G-8`FXZP$o*-arkT|NM&`Tu z+Y)&Bgaeg?ISxu7411+KinV(}yk7gMDSQg$%btph9h1QInXybn&1QnaK#DKT9(@P> zG=)~Bqz0JCE6DwYP-ETTIl7t5y0jg6sy$F_@TN=XkQg>_QaF(dF*swu>S}1wFe#{( z9%~BH#D|HZL#bGIAJ?1qZb8C{;>NsC&{(474b=!h@7+92#g*5ERT?@Y%bd$!@BVcv zG}h6r1#pI_;2(jyu`4H+FA2xr8_TaxLX_}~-5Cnc{zgeabB>tU1dxX8D|9Y(Ws+UR zpuvYp%tlNu?k_ygo84iuB2mqNPn-qEmi#OhmuBCXdx{GJ~MWzt`TFJt;@-6JRqrG?!)TiG1{llM{@Ve)FlEZaRZc?nbq2%Z=UtG!! zbPg`Xe&UMA$@Fcy^rbwTV9B{d1c|VW)jMW56~#v{pgF;**VBh#Mmr;(%tc}5#e8Hp zaz8_j<&;9pIMw?d+zL?=IFJXe{w`;zedd9-7{fHjtkdt)r^Qa^?z_F`|3mQZ`g;#K zAtKCMd~7I~|M6Z!kBtBUhG+k^yy-37`U?om6I(Mc$Dg|{$A2#o5}A8HF3dY>%`=|0d9_-Ao6<5quU;^EKq7_s2(`kR2_|5EAXeX*IEZdWvCM z@!Lz=A0jYlCTIs79V-vcY77AW5JBlmg?Z5h1o)}VAJES5fAudT^WAEorRjs~{G3g@ z<%|eiqtV9dEB=eJBjM;(itS$J;G}6fdyu5)(dS^D29RQj1Hq7$>$~%suvE#y_Z^o| zxE-mzo3?! zs~^O@11L`_ixoGLwD6lD#tfJ1`FJWG3%p;5BqWYXo;~&+j3tTZ79oollI3^6-FC*j z9EzeP!9?80$<4fsXq!6={9S1clG6UEuGa@FkBblE^bHQMT2>xgU4ZC4I|;oEzt0Va z7wJRFEL2sL%H_<1OfB07oC+No7z|Y>#BJ(W9~WQDypa>fcq!~aXuBOz z+5JP#PD=Mu)x}I%PG;=kX@y;Mw6FxKv8YMoA z%MgAuK4~B(@Y-fv?Qb~OrL?30Hw6kj@@_p(wr+L$zfKX>eAVr<0}y(6bk_*5bF|!Q zdj1^B+_A+r>%Z3d;p#=_S2KIV3BHr(2p$VY{*$kqOKyiRX0>W0ZEe?{Y*c)@w82v` zK72^6gl7zY7qH-QuVc4Fo=e&nrV3puFRvh{pUL4~X9(xL;Sd_rLa*0rs1jhK1EZn6 zc2O`L4kA<5vRHg9DWMs2X$KVNm4#@?2yAznYg570-w$;|9-g%^jWfo2Pn&dJuLXZ( z!7`Nu9(N7*EMmm~k5h&@b(Ij`n5u_K46$_MvZHEPEzO-mi0!J^29xmwMD!(aa!`A9 zy&>UGMz*oyK?ub274%1Uxa6sBFvCZ*5w!5Qh0hpWrhR6t)Fe-2MFtSF!AOXeceH$q zSPDAFk2b9%u6zRvDVQ5r34 z@_>fac}1}#*R(Xlks*J61fVDY)!fPJr$@_ybB)pcv=<=$k-43ILvEo*SzzB))+nPK zF&n6IaMws@KEg%-=DLMNb7=J5Pyc#z%dI^QLPr(8 zT0&k;8;;AZ%2bx`0DQ;MBLWnR&7y8K>fn<2<^}^7y=6bA`3cBu;%Z!ZdcN?xu1ghC zZV8RXi``YvSVuXEZ`n%uBySAQV4|_E|Grg~uf6qiN2c!k?rWv?b9wkm6qAzh!ysRU zC7Ep=3TRwt;LZ{Mb+#y#tI;D@zX7 zo6eSR*VFQtk$THhh_)y|ibhkibHRVtqj-31<`2j(U&c`Wdp%12@~`OL z^8DoaK736HUXv*(xaz;iUq&g9TSon;E~WJ&Qv zy6+-^q2c0m;-YQt6hl71EWIo}GXe*^{qPQ)KW<)y^~cD5X8bSJd73L*3r>}k_^d@# zafZ0G9GE+glN17AX{pL~#GphQrFX$b|IA1!NYPerQBYu3lOG$_83w4uuQiTf2-5iK z@R9oK%?l%|<-FWpdnkmV7ZVe`re+Z#y&vvmG;Rouz-kEzl7iasJjvekA-P#cQ>uBv zb^aMv4!jfqJh-(JG5Wl$(=QnJOgL)G%y67CT^=1>aB#h#1v)ba?6E|c(-nK$1c(X} z{7x~Up+lf44?jA0J(o!#NBCHUK9W@#oyB&V6EqJcXMG0#opyt2|RX8ERpX-lPNp-_|zI~xJdB%zC(tj?D?J| zfT|8M!)Nt9BN1RsmZ0CQXDzED&mv)*N?esHdeA~`g^Z}qROBgmZalSI2^8esP6nzB z<^qWG)*}_5%!0oLl+2Xv&f$oM+$BCG#SN851>S6{GFR`kOnXn$G&pgW0oeUjD6nha zljJhmY&$Ej8zPJ&h?~-Oit2w_R`@=6YG1~D=Sc8vP!;J{V@a(zCYZHHWCov71?nqF z|6GxBtjKs!U+H(}w)k3V*^yW^$ZE8g7jEQNqLA;Re+;7w&D*vT?3GBaoJMV|tqbshGB$wR*Y zA}}zOB_pNj!(Zsb8yLb}8G%{9$P#{$IoA)QYo3%QH*!{XOa&&71#GG7P&rVPz{&5p z!DBkb5gbVUHU8SY5<&3r+r2D+y8)!zg7@_SA#y+SOuO-H zy2MOLvN;!97wz8Cs0v!fR^oH0gW$Rv_C*G)U=Jd=o=NPED~-howT-UAp_jXLA0P2= zx48BG=VvKW+&RjFqI_cOYjO+8sbx3wEBRvb@x9u}^l*UpuA9^{ak{jKRA>BsaYEbE zB|{l!{YQMl3xDM$b=lU~iy!&@>$$`HT3R~Nn7NeR?}QV89t-C$nau-tAnY=Om&GbM zBX>&s2=Fc9Q_%37_=cL!rZa~9x6iP@%yYrKmUQIPOGKAFmnA4$&0bJjN;o^-@@aSf z10ve{);#(y zN&?N{xNW1|c(*8+7?jwmy_Ri@aD{c8$kg}6ItzIAbx6u3y#wh5rw3lAutlOJr!ZcO zqZn$gaFxMp0m~^&NAIovyyUtv^bdicBbpY1F5O-?1$sCZ}5y5X|_a3 zRY!Pr=d3`b-o}!IGd6RY76eu2tPrhUx59)oJb4XA{EGdI0blSX)MVYVd2kJ}qZFQ% zhs&n!T?4x%#(a0|Ps{cQU*BV#Ng7Xl`QeDEwV@|xSKaaUj2gCTM(AL~tu#{w!}>!*RIyX%wf`kblFgJ=)4iw`y5vnQ4p zQ(#!P+&VF>+#CMxd!5k07WpRatMnVr^*f8m?j>@&sZm&WK*wOf`*X}ewC7la$)Ldc z4e6MPrK?{U1v;ZWlPEq-X2hru{O90wXcTFOwnM-v2iEe#^}B-83Qrlg{4Ru!5#D?V zPWdK2~)GHLX0}!_Z_ERA4d?LCvP%ZniyC*i_#+J(20K?-@QVBbQY+w&GAZS!2 zV8zGFC5eHGg%9CeZE@5iT3M&CRk09Qxo7MPFKGP%r17VKv_*Gd|E&AYtA2fUxP|7Z zc;x`wB5`#I>-p`97o3me2@#x+;z{~z4$-EYJ-UX*wZ9i#FG2GA8Vug&-wJT@L{mtV zf3TYY{J*%z|K~BUY~=d)Ya$s1G`W9V6S<2c6Nc@9u4zm$i3B}ieKlaU7C@O7h5GBF zh#JtBoh>gIHgw!qB)B8f)#BPOjEWzHlgjWW#t`LQVG;H6qd4(G=O~-!aj|tFr>pDz z%QjmzE1%cfllwtl?Z~-LpB~E)oX-jswtM}KRA^}3Neb=+xljuuUN5K+5S<|D9NlOO zHecK@ir$41iM+oe6?dI>OmnY8k9*i|_a&L|HI;Oj*ii22YZ;0nHV!rc54$nn=y&Gh zxrveHLAMhqfQ;&vc5+|*V!6vwGw75uO-v)%Vj(?U`w7FC_x>=vHfeL+ppq?Tj%@d?lMUG8Fa#Lvb)-5o_T#mX49! z^bjq;pTC!W+`JZ^8(+$nGLZWj^mHbENS?%N9Z@utFMW{VxB5PR?T9Z1wyVdSw*iJX z?`jQ)GLIhS&N!&Tfat0xQmE>oBd<$xXl4cnEbIbZOpjt&0h}J}0$U6#-iq%&RZ@)F ztHgSVO8lc$rs>GwT*atk3a`?-shcvp+Bc=pa3O%~awdYGbAnN`R+{#K&AM}oPV?$9 zm&n#~-#9Ww9yB`pJf!rTMeG>6g$wcXiRXQsw z3*khtt+&$?-Z|wE)OAJ#G?tYAqnJv9Vy0cZ;%gtaAFJ58pE)S6zVf(ZW4{Xb;H29! zI2jbE^I+@1HiS2%&a%(Z5k^)*cuTIhB!pj<9i$01k(O`B$Nd&f1EHUcwLdM*#v#Hz zbsmmi4O&?;s0->Rak>Fx6H}Zgps+aK#D!B}*Yc#lTasTwz<>^2X0`MIqG;)ONgUNF z&R}WL#G`tq9WmU&R89j&$~ylQ)_a!gI^A%g-@m*B4ydF?lHewVBMV~zv@8~%KRI(A zR=&jt9C0|7Kf1!AyWL<6`7k!@@eT6FYPYNl-w!&Ji26#?+e^J7{JRpf=WnvZ{wVPq z#D6gZ<)2DaaddEY{d+CR0aXI+W9STb5}=zax3*2OvS~X!i6YzE`b~vbQ8-c2C}|NW z(x|1734gY+;LT|rvYjVbpu8|Ftwx|-#)YoRchkdoDkA1%zW7a8w_$dibL;sqv;HX4 z>)~w%^$X@TdOso}!Fu)jToe2)gGa_{hxvu2*o5m^wi)h^1D>L$wf%wD^+WN{M5m?W zq;Wm_&GX>%7>;g}Wqkel4)roSPjZ=;G*;SF_{0YPgTeQ#>89}IBmdA26s7cZenA%_ z_4XVHlacw2Y0hW2u|qf+G=r`B7P}Llhvu%8YuBB@#h<=gEUor!lQ9c0e(AYgWAMDo z3uoD9kZuHEDRa`qlT6nE`szXNG@O}e32-9nB?R8Pr*`&j{)s>ASTg;Ai|fC)a{4nQ`9bNm|iN2{|$8e)UE-zm?st}s~ zbW&Fbu908kOx^=X(NNb*Vm+%rK{t`Umid|Kq8-avYez$*irX(ZKY1^29)94P=yW9Y zdVgc|n7G=~z4UOZk6hS_QG=}GiICO$d#|omh}yOa$d@mRVE@snYwF-; zY-?ulNAmV&Ca#Pk|NCiXD(w2#xT}8+-L3lPMe_d`x;tv2#Y~|dfn`fXTt&OuNZ)!ZYTqynPbE&3G7R{G$^(XLyB}>m!ox;i%!XaT?|i}+Ad1N4{=5#ZnC@f&A!t%76H;q=!8TKxk;#o~KaI-KZ30|T-u(5(h?E^Iz7AW@ z_d~O>j$O6Gj^*hFrMpViO1?Qki=a=FvSaoWw_4a_R zP0&{pPHkc^5>)v?_A1QZ`Q(miA9M9hY7KMsgOSxI$#b*P%zD2L?dGI0Ge=ct+AMjB z63kvsWbGPZO#GYJ&Ml#!ZL`@Aqg`jHCJGhgCvH?lB758mR2}i##$sDnNtAmFVm z(Zi~J8hH1#0hcW}Bp}-Fkv%Sm=-U_XI2=+gC9(MFd|ujy7WN`X{UE6vi&#K@)o=X; zuC-sGD<7rb zm^MAcB`^u1zlk*W#CWnI_4`?1StV-r?+v6qq1BNaXpNp84^BemdkRZXHZ>7PrS(jI z5>^5>cnEqAIez!5fUL=CA=o(Q*`mj^RM#qs*cxW#;-0QOe(|q(1h@^%P!`A?F9Xh5 zR+GM+g=wj7i%$Qrr!L%^U`@%fqT5oB$cS9RzO-T3Dx=sD!Mv)i+woqcnNXjM#pxnO ziZQ@CBW=&NbnwgVV*DyAlpIJ4)q9t{j(> zzyMW#q5lyhF3G+xDO{kqjiybR-*w9)zirAp

4${UDPPGq+3)j%o|FRc3@4@u-Kj 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\!=ejkvAMIxd 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 literal 0 HcmV?d00001 diff --git a/apps/client/local_plugins/device_smartcar/android/tool/unpack_aars.sh b/apps/client/local_plugins/device_smartcar/android/tool/unpack_aars.sh new file mode 100755 index 00000000..1b269f1a --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/android/tool/unpack_aars.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# 把 third_party/aar/ 下的杰理 AAR 解包成 Gradle library 模块能直接消费的形态: +# classes.jar -> libs/.jar +# jni//* -> src/main/jniLibs// +# 理由见 build.gradle 顶部注释。升级 SDK 时替换 aar 后重跑本脚本并提交产物。 +set -euo pipefail +cd "$(dirname "$0")/.." +rm -rf libs src/main/jniLibs +mkdir -p libs src/main/jniLibs +for aar in third_party/aar/*.aar; do + name="$(basename "$aar" .aar)" + tmp="$(mktemp -d)" + unzip -q "$aar" -d "$tmp" + [ -f "$tmp/classes.jar" ] && cp "$tmp/classes.jar" "libs/$name.jar" && echo " jar <- $name" + if [ -d "$tmp/jni" ]; then + for abi_dir in "$tmp"/jni/*/; do + abi="$(basename "$abi_dir")" + mkdir -p "src/main/jniLibs/$abi" + find "$abi_dir" -maxdepth 1 -name '*.so' -exec cp {} "src/main/jniLibs/$abi/" \; + done + echo " so <- $name" + fi + rm -rf "$tmp" +done diff --git a/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Package.swift b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Package.swift new file mode 100644 index 00000000..ab7dfa07 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Package.swift @@ -0,0 +1,38 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "device_smartcar", + // 与 Podfile 的 platform :ios, '16.0' 及其它本地插件对齐 + // (ios/sync_spm_platform.sh 会核对这个值不高于工程 target) + platforms: [.iOS("16.0")], + products: [ + .library(name: "device-smartcar", targets: ["device_smartcar"]) + ], + dependencies: [ + // JL_BLEKit.xcframework 由 device_jieli vendor 并以产品形式暴露(见那边的 Package.swift)。 + // 它是**动态库**,这里绝不能再 vendor 一份——同一进程装两份会在启动时报 + // 「Class JL_xxx is implemented in both …」,认证行为不可预期。 + // 先例:recorder_holder 也是这样复用 device_jieli 的 JLAudioUnitKit。 + .package(path: "../../../device_jieli/ios/device_jieli"), + // libopus:设备麦克风上行是 opus(见 SmartcarAudio.swift)。 + // opus.xcframework 由 ble_service vendor 并以 `opus-binary` 暴露, + // SwiftPM 不允许跨包同名 target,自己再 vendor 一份会报 + // 「Multiple commands produce opus.framework」。先例:recorder_holder。 + .package(path: "../../../ble_service/ios/ble_service") + ], + targets: [ + .target( + name: "device_smartcar", + dependencies: [ + .product(name: "jl-blekit", package: "device_jieli"), + .product(name: "jl-otalib", package: "device_jieli"), + .product(name: "opus-binary", package: "ble_service"), + ], + path: "Sources/device_smartcar", + linkerSettings: [ + .linkedFramework("CoreBluetooth") + ] + ), + ] +) diff --git a/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/DeviceSmartcarPlugin.swift b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/DeviceSmartcarPlugin.swift new file mode 100644 index 00000000..8b865f28 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/DeviceSmartcarPlugin.swift @@ -0,0 +1,259 @@ +import Flutter +import UIKit +import CoreBluetooth + +/// Smartcar 车载香薰的 Flutter 插件(iOS)。 +/// +/// 方法通道 `com.yimai.device_smartcar`: +/// adapterState() -> String +/// startScan({timeoutSec}) -> Bool 扫描起不来抛 SCAN_FAILED(带原因) +/// stopScan() +/// connect({id, timeoutSec}) -> Bool **认证通过才 resolve**;失败抛 CONNECT_FAILED(带原因) +/// disconnect() +/// isConnected() -> Bool = 认证通过且 GATT 在线 +/// jlPostAuth() -> Map 认证后的 RCSP 收尾(设时间/GET_TARGET_INFO/GET_SYS_INFO),回各步状态 +/// otaStart({filePath}) -> Bool 杰理 OTA(含 stage2 扫描回连),进度走事件 {type:"ota"} +/// otaCancel() / otaIsRunning() -> Bool +/// audioStart() -> Bool / audioStop() / audioStats() -> Map 麦克风上行(opus→16k PCM) +/// writeCustom({data: Uint8List}) -> Bool 往 ABC1 写一帧裸字节 +/// +/// 事件通道 `com.yimai.device_smartcar/events`,每条是 Map: +/// {type: "adapter", state} +/// {type: "scan", id, name, rssi, mfg: Uint8List?, services: [String]} +/// {type: "scanStopped"} +/// {type: "state", id, state, reason?} state 见 SmartcarLinkState +/// {type: "custom", data: Uint8List} ABC2 通知的裸字节 +/// {type: "ota", state, percent, code?, message?} state ∈ preparing/transferring/stage2/done/failed/cancelled +/// {type: "audio", data: Uint8List} 设备麦克风 PCM(16k/16bit/mono) +public class DeviceSmartcarPlugin: NSObject, FlutterPlugin, FlutterStreamHandler { + private var sink: FlutterEventSink? + private var pendingConnect: FlutterResult? + private var connectTimer: Timer? + + public static func register(with registrar: FlutterPluginRegistrar) { + let channel = FlutterMethodChannel(name: "com.yimai.device_smartcar", + binaryMessenger: registrar.messenger()) + let instance = DeviceSmartcarPlugin() + registrar.addMethodCallDelegate(instance, channel: channel) + + let events = FlutterEventChannel(name: "com.yimai.device_smartcar/events", + binaryMessenger: registrar.messenger()) + events.setStreamHandler(instance) + } + + override init() { + super.init() + let c = SmartcarBleCentral.shared + c.onAdapterState = { [weak self] s in + self?.emit(["type": "adapter", "state": s]) + } + c.onScanHit = { [weak self] hit in + var m: [String: Any] = [ + "type": "scan", + "id": hit.id, + "name": hit.name, + "rssi": hit.rssi, + "services": hit.serviceUuids, + ] + if let d = hit.manufacturerData { + m["mfg"] = FlutterStandardTypedData(bytes: d) + } + self?.emit(m) + } + c.onScanStopped = { [weak self] in + self?.emit(["type": "scanStopped"]) + } + c.connectDelegate = self + SmartcarOta.shared.onEvent = { [weak self] m in self?.emit(m) } + SmartcarAudio.shared.onPcm = { [weak self] pcm in + self?.emit(["type": "audio", "data": FlutterStandardTypedData(bytes: pcm)]) + } + } + + // MARK: - FlutterStreamHandler + + public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { + sink = events + return nil + } + + public func onCancel(withArguments arguments: Any?) -> FlutterError? { + sink = nil + return nil + } + + private func emit(_ m: [String: Any]) { + if Thread.isMainThread { + sink?(m) + } else { + DispatchQueue.main.async { [weak self] in self?.sink?(m) } + } + } + + // MARK: - 方法 + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + let args = call.arguments as? [String: Any] ?? [:] + let central = SmartcarBleCentral.shared + + switch call.method { + case "adapterState": + central.ensureCentral() + result(central.stateString) + + case "startScan": + let timeout = args["timeoutSec"] as? Int ?? 15 + central.startScan(timeoutSec: timeout) { ok, reason in + if ok { + result(true) + } else { + result(FlutterError(code: "SCAN_FAILED", message: reason, details: nil)) + } + } + + case "stopScan": + central.stopScan() + result(nil) + + case "connect": + guard let id = args["id"] as? String, !id.isEmpty else { + result(FlutterError(code: "BAD_ARGS", message: "缺少 id", details: nil)) + return + } + if pendingConnect != nil { + result(FlutterError(code: "BUSY", message: "上一次连接还在进行中", details: nil)) + return + } + guard let sp = central.connect(id: id, delegate: self) else { + result(FlutterError(code: "NOT_FOUND", + message: "这个 id 不在扫描结果里、系统也没缓存,请重新扫描后再连", + details: nil)) + return + } + if sp.isReady { + result(true) + return + } + pendingConnect = result + let timeout = TimeInterval(args["timeoutSec"] as? Int ?? 45) + connectTimer?.invalidate() + connectTimer = Timer.scheduledTimer(withTimeInterval: timeout, repeats: false) { [weak self] _ in + guard let self = self, self.pendingConnect != nil else { return } + SmartcarBleCentral.shared.disconnect() + self.finishConnect(error: "连接总超时(\(Int(timeout))s),停在 \(SmartcarBleCentral.shared.active?.state.rawValue ?? "?")") + } + + case "disconnect": + central.disconnect() + result(nil) + + case "isConnected": + result(central.active?.isReady ?? false) + + case "audioStart": + // 设备在唤醒后自己开麦,这里只决定要不要往 Dart 抛 + result(SmartcarAudio.shared.start()) + + case "audioStop": + SmartcarAudio.shared.stop() + result(nil) + + case "audioStats": + result(SmartcarAudio.shared.stats) + + case "otaStart": + guard let path = args["filePath"] as? String, !path.isEmpty else { + result(FlutterError(code: "BAD_ARGS", message: "缺少 filePath", details: nil)) + return + } + guard let sp = central.active, sp.isReady else { + result(FlutterError(code: "NOT_READY", message: "链路未就绪(认证未过)", details: nil)) + return + } + if let err = SmartcarOta.shared.start(filePath: path, peripheral: sp) { + result(FlutterError(code: "OTA_FAILED", message: err, details: nil)) + } else { + result(true) + } + + case "otaCancel": + SmartcarOta.shared.cancel() + result(nil) + + case "otaIsRunning": + result(SmartcarOta.shared.isRunning) + + case "jlPostAuth": + guard let sp = central.active, sp.isReady else { + result(FlutterError(code: "NOT_READY", message: "链路未就绪(认证未过)", details: nil)) + return + } + var done = false + // SDK 没回调就永远不回,给 8s 兜底 + DispatchQueue.main.asyncAfter(deadline: .now() + 8) { + if !done { done = true; result(["timeout": true]) } + } + JLAssistBridge.shared.runPostAuth { report in + if !done { done = true; result(report) } + } + + case "writeCustom": + guard let td = args["data"] as? FlutterStandardTypedData else { + result(FlutterError(code: "BAD_ARGS", message: "data 必须是 Uint8List", details: nil)) + return + } + guard let sp = central.active, sp.cb.state == .connected else { + result(false) + return + } + result(sp.writeCustom(td.data)) + + default: + result(FlutterMethodNotImplemented) + } + } + + private func finishConnect(error: String?) { + connectTimer?.invalidate() + connectTimer = nil + guard let r = pendingConnect else { return } + pendingConnect = nil + if let e = error { + r(FlutterError(code: "CONNECT_FAILED", message: e, details: nil)) + } else { + r(true) + } + } +} + +// MARK: - SmartcarPeripheralDelegate + +extension DeviceSmartcarPlugin: SmartcarPeripheralDelegate { + func smartcarPeripheral(_ p: SmartcarPeripheral, didChange state: SmartcarLinkState, reason: String?) { + var m: [String: Any] = ["type": "state", "id": p.id, "state": state.rawValue] + if let r = reason { m["reason"] = r } + emit(m) + SmartcarOta.shared.onLinkState(state, peripheral: p) + + switch state { + case .ready: + finishConnect(error: nil) + case .failed: + finishConnect(error: reason ?? "连接失败") + case .disconnected: + if pendingConnect != nil { + finishConnect(error: "连接过程中链路断开" + (reason.map { ":\($0)" } ?? "")) + } + default: + break + } + } + + func smartcarPeripheral(_ p: SmartcarPeripheral, didReceiveCustom data: Data) { + emit(["type": "custom", "id": p.id, "data": FlutterStandardTypedData(bytes: data)]) + } + + func smartcarPeripheral(_ p: SmartcarPeripheral, didReceiveJl data: Data) { + SmartcarAudio.shared.feedJl(data) + } +} diff --git a/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/JLAssistBridge.swift b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/JLAssistBridge.swift new file mode 100644 index 00000000..8348fa1c --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/JLAssistBridge.swift @@ -0,0 +1,94 @@ +import Foundation +import CoreBluetooth +import JL_BLEKit + +/// 杰理 `JL_Assist` 的薄封装——**只做 RCSP 认证**,不走 JL_BLEMultiple 那套连接管理。 +/// +/// 为什么不用 JL_BLEMultiple 直接连:它会自己持有 CBPeripheral 与连接, +/// 我们就没法在同一条 GATT 连接上再订阅 C2 的私有服务 ABC0。所以照 lumi 的做法, +/// GATT 由 [SmartcarPeripheral] 自己持有,把 `CBPeripheralDelegate` 的回调**转交**给 +/// JL_Assist,让 SDK 只负责认证握手与 RCSP 帧的收发。 +/// +/// `JL_Assist` 必须是进程内唯一实例:lumi 那边的注释写着「每次访问都创建新的 +/// JL_Assist 实例会导致 XPC 连接冲突」。 +final class JLAssistBridge { + static let shared = JLAssistBridge() + + let assist: JL_Assist + + /// SDK 的 `mCmdManager.mEntity` 是 **weak**,我们不自己持有的话认证一过实体就释放了。 + private var boundEntity: JL_EntityM? + + private init() { + assist = JL_Assist() + // 1.13 把 mNeedPaired 改名成了 mAuthEnable;语义就是「连上后要跑设备认证」。 + // Smartcar 固件没过这一步不把手机当成已连接,所以必须开。 + assist.mAuthEnable = true + #if DEBUG + // 排查期打印 AE01/AE02 裸数据,能看见认证握手到底有没有真的来回 + assist.mLogData = true + #else + assist.mLogData = false + #endif + } + + /// 认证通过后、lumi 两端 SDK 都会自动跑的 RCSP 收尾序列 + /// (iOS `JLWatchManager.initDialSystem`,Android 由 `WatchOpImpl` 在 `onAuthSuccess` 后自动发): + /// 设系统时间 → `GET_TARGET_INFO`(cmdTargetFeature) → `GET_SYS_INFO`(COMMON / BT)。 + /// + /// 杰理固件通常在收到 `GET_TARGET_INFO` 之后才把"手机 App 已连接"置位—— + /// 我们只做了认证、一条 RCSP 命令都没发,屏幕就一直显示 BLE 未连接(2026-09-10 真机)。 + /// 表盘文件系统那段(openDialFileSystem)是手表专用,这里不搬。 + func runPostAuth(completion: @escaping ([String: Any]) -> Void) { + let m = assist.mCmdManager + var report: [String: Any] = [:] + + let c = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: Date()) + m.mSystemTime.cmdSetSystemYear(UInt16(c.year ?? 0), month: UInt8(c.month ?? 0), day: UInt8(c.day ?? 0), + hour: UInt8(c.hour ?? 0), minute: UInt8(c.minute ?? 0), second: UInt8(c.second ?? 0)) + report["setTime"] = "sent" + + m.cmdTargetFeatureResult { status, sn, data in + report["targetFeature"] = Int(status.rawValue) + report["targetFeatureLen"] = data?.count ?? 0 + NSLog("[Smartcar] cmdTargetFeatureResult status=%d len=%d", Int(status.rawValue), data?.count ?? 0) + m.cmdGetSystemInfo(.COMMON) { status, sn, data in + report["sysInfoCommon"] = Int(status.rawValue) + NSLog("[Smartcar] cmdGetSystemInfo(COMMON) status=%d", Int(status.rawValue)) + m.cmdGetSystemInfo(.BT) { status, sn, data in + report["sysInfoBT"] = Int(status.rawValue) + NSLog("[Smartcar] cmdGetSystemInfo(BT) status=%d", Int(status.rawValue)) + DispatchQueue.main.async { completion(report) } + } + } + } + } + + /// 转交 `centralManagerDidUpdateState` + func updateCentralState(_ state: CBManagerState) { + assist.assistUpdate(state) + } + + /// 认证通过后把 SDK 的命令实体绑到当前外设。本期不发 RCSP 命令, + /// 但阶段 7 的 OTA 要用;照官方示例在认证成功后才绑。 + func bindEntity(peripheral: CBPeripheral, name: String) { + // 头文件在 NS_ASSUME_NONNULL 里,mCmdManager 导入成非可选;mEntity 是 weak, + // SDK 没绑过时读出来是 nil(运行时行为),所以用 Optional 兜一下。 + let manager = assist.mCmdManager + let existing: JL_EntityM? = manager.mEntity + let entity: JL_EntityM = existing ?? boundEntity ?? JL_EntityM() + entity.setBlePeripheral(peripheral) + entity.setBleItem(name) + entity.mUUID = peripheral.identifier.uuidString + let addr: String? = entity.mBleAddr + if (addr ?? "").isEmpty { + entity.mBleAddr = peripheral.identifier.uuidString + } + manager.mEntity = entity + boundEntity = entity + } + + func unbindEntity() { + boundEntity = nil + } +} diff --git a/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/OggOpusExtractor.swift b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/OggOpusExtractor.swift new file mode 100644 index 00000000..a92c732b --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/OggOpusExtractor.swift @@ -0,0 +1,138 @@ +import Foundation + +/// 从 **Ogg 封装的 Opus 流**里拆出一个个 opus 包。 +/// +/// ## 为什么需要它(2026-09-11 真机踩出来的) +/// 设备经 AE02 送上来的不是裸 opus 帧,而是 **Ogg 流**:`OggS` 页头 + 段表 + 页体。 +/// 第一版直接把整段 payload 喂给 `opus_decode`,结果是:85 帧只解出 21280 字节 PCM +/// (每帧 ~250 字节,而 opus 帧应该是 640/1920 这种整数),百炼收到的是噪声, +/// 自然一句都不回。日志表现是「上行 42 包、下行 0 包,双方 5s 无声自动结束」。 +/// +/// 从 lumi `MusicDetector.swift` 内嵌的同名类搬过来,逻辑一字未改: +/// - BLE 通知会把一页切成好几包,所以要**跨包累积**再找 `OggS`; +/// - 段长 255 表示"还没完,接着拼",< 255 才是一个完整 opus 包的结尾; +/// - 每页校验 CRC32(Ogg 用的是 `0x04C11DB7` 无反射变体),校验不过就从下一字节重找同步字, +/// 不能整段丢——BLE 丢包时后面还有好页; +/// - `OpusHead` / `OpusTags` 这两个头包要跳过,喂给解码器会出错。 +final class OggOpusExtractor { + private var buffer: [UInt8] = [] + private static let maxBuffer = 64 * 1024 + + private static let crcTable: [UInt32] = { + var t = [UInt32](repeating: 0, count: 256) + for i in 0..<256 { + var r = UInt32(i) << 24 + for _ in 0..<8 { + r = (r & 0x8000_0000) != 0 ? (r << 1) ^ 0x04C1_1DB7 : (r << 1) + } + t[i] = r + } + return t + }() + + func reset() { buffer.removeAll(keepingCapacity: true) } + + /// 喂一段 payload,返回这次能凑出的完整 opus 包(可能 0 个,也可能好几个) + func feed(_ payload: Data) -> [Data] { + if payload.isEmpty { return [] } + buffer.append(contentsOf: payload) + var out: [Data] = [] + var searchFrom = 0 + while true { + guard let sync = indexOfOggS(buffer, from: searchFrom) else { + // 没找到同步字:只留最后 3 字节,`OggS` 可能被切在两包之间 + let keepFrom = max(buffer.count - 3, searchFrom) + if keepFrom > 0, keepFrom < buffer.count { + buffer = Array(buffer[keepFrom.. buffer.count { break } + let pageSegments = Int(buffer[sync + 26]) + let headerLen = 27 + pageSegments + if sync + headerLen > buffer.count { break } + var bodyLen = 0 + for i in 0.. buffer.count { break } + if !verifyCrc(buffer, offset: sync, pageLen: totalPageLen) { + searchFrom = sync + 1 + continue + } + if sync > 0 { buffer = Array(buffer[sync.. Self.maxBuffer { + let cutFrom = buffer.count - Self.maxBuffer + if let cut = indexOfOggS(buffer, from: cutFrom) { + buffer = Array(buffer[cut.. buffer.count { break } + if segLen > 0 { + current.append(contentsOf: buffer[bodyOffset.. Int? { + let s = max(start, 0) + let end = data.count - 4 + if s > end { return nil } + for i in s...end { + if data[i] == 0x4F, data[i + 1] == 0x67, data[i + 2] == 0x67, data[i + 3] == 0x53 { + return i + } + } + return nil + } + + /// `OpusHead` / `OpusTags` 不是音频包,喂给解码器会出错 + private func isOpusHeader(_ packet: [UInt8]) -> Bool { + if packet.count < 8 { return false } + return packet[0] == 0x4F && packet[1] == 0x70 && packet[2] == 0x75 && packet[3] == 0x73 && + (packet[4] == 0x48 || packet[4] == 0x54) + } + + /// Ogg 页 CRC:算的时候把 CRC 字段本身(22..25)当 0 + private func verifyCrc(_ data: [UInt8], offset: Int, pageLen: Int) -> Bool { + if offset + pageLen > data.count { return false } + let stored: UInt32 = + UInt32(data[offset + 22]) | + (UInt32(data[offset + 23]) << 8) | + (UInt32(data[offset + 24]) << 16) | + (UInt32(data[offset + 25]) << 24) + var crc: UInt32 = 0 + let crcStart = offset + 22 + let crcEnd = offset + 25 + let end = offset + pageLen + for i in offset..= crcStart && i <= crcEnd) ? 0 : UInt32(data[i]) + let idx = Int((crc >> 24) & 0xFF) ^ Int(b) + crc = (crc << 8) ^ Self.crcTable[idx] + } + return crc == stored + } +} diff --git a/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarAudio.swift b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarAudio.swift new file mode 100644 index 00000000..16468477 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarAudio.swift @@ -0,0 +1,152 @@ +import Foundation +import opus + +/// 设备麦克风上行:从杰理通道(AE02)里挑出 opus 音频帧,解成 16k/16bit/mono PCM。 +/// +/// ## 帧格式(照 lumi `LumiDeviceManager.isLikelyAudioPacket` / `extractAudioPayload` 搬) +/// ``` +/// FE DC BA 80 01 00 8E | seq(1) | 04 | opus payload … | 尾字节(1,丢弃) +/// 0 1 2 3 4 5 6 7 8 9 ..< count-1 +/// ``` +/// 音频和 RCSP 命令**共用 AE02**,靠这个 7 字节头区分;`seq` 按 0~255 循环,用来去重 +/// (BLE 通知偶尔会重复投递,重复帧解出来是杂音)。 +/// +/// ⚠️ 设备是在收到 `0xCC 0x11`(唤醒)之后**自己开麦**开始送数据的,App 不需要下命令开麦 +/// (协议文档原话:「不需要app回复,设备端直接开麦,录音发opus数据给到app」)。 +/// 所以这里只做"要不要往上抛"的开关,不控制设备。 +/// +/// ⚠️ libopus 来自 `ble_service` 暴露的 `opus-binary` 产品——SwiftPM 不允许跨包同名 target, +/// 自己再 vendor 一份 Xcode 会报「Multiple commands produce opus.framework」。 +/// 先例:`recorder_holder` 也是这么复用的。 +final class SmartcarAudio { + static let shared = SmartcarAudio() + + /// 解好的 PCM(16k/16bit/mono,小端) + var onPcm: ((Data) -> Void)? + + private let lock = NSLock() + private var decoder: OpaquePointer? + private var lastSeq: Int = -1 + + /// ⚠️ 设备送的是 **Ogg 封装的 opus**,不是裸帧。必须先拆页取包再解码, + /// 直接把 payload 喂 `opus_decode` 出来的是噪声(2026-09-11 真机踩过, + /// 表现是"上行有包、百炼一句不回")。见 [OggOpusExtractor]。 + private let ogg = OggOpusExtractor() + + /// 16k mono 最大 60ms/包 → 960 samples + private let maxFrameSize: Int32 = 960 + + /// 排查用:从 Ogg 里真正拆出来的 opus 包数。 + /// 它一直是 0 就说明**根本没解析出 Ogg 页**(同步字没对上/CRC 全错), + /// 与"拆出来了但解不出 PCM"是两种完全不同的故障。 + private(set) var opusPackets = 0 + + private(set) var isRunning = false + + // 排查用计数:真机上"没声音"时先看这三个数分别是多少 + private(set) var framesIn = 0 + private(set) var framesDup = 0 + private(set) var pcmBytesOut = 0 + + private init() {} + + @discardableResult + func start() -> Bool { + lock.lock(); defer { lock.unlock() } + framesIn = 0; framesDup = 0; pcmBytesOut = 0; opusPackets = 0 + lastSeq = -1 + ogg.reset() + if decoder != nil { + isRunning = true + return true + } + var err: Int32 = 0 + guard let d = opus_decoder_create(16_000, 1, &err), err == OPUS_OK else { + NSLog("[SmartcarAudio] opus_decoder_create 失败 err=%d", err) + return false + } + decoder = d + isRunning = true + return true + } + + func stop() { + lock.lock(); defer { lock.unlock() } + isRunning = false + if let d = decoder { + opus_decoder_destroy(d) + decoder = nil + } + lastSeq = -1 + } + + var stats: [String: Any] { + lock.lock(); defer { lock.unlock() } + return [ + "running": isRunning, + "framesIn": framesIn, + "opusPackets": opusPackets, + "framesDup": framesDup, + "pcmBytesOut": pcmBytesOut, + ] + } + + /// 喂一包 AE02 的原始数据。不是音频帧就原样忽略(RCSP 命令走 SDK 那条路)。 + func feedJl(_ packet: Data) { + guard isRunning, Self.isAudioPacket(packet) else { return } + let seq = Int(packet[7]) & 0xFF + + lock.lock() + if lastSeq >= 0 { + // seq 是 1 字节循环计数;> 200 跳到 < 50 视为回绕,不当重复 + let wrapped = lastSeq > 200 && seq < 50 + if !wrapped && seq <= lastSeq { + framesDup += 1 + lock.unlock() + return + } + } + lastSeq = seq + framesIn += 1 + guard let d = decoder, packet.count > 10 else { + lock.unlock() + return + } + // ① 先从 Ogg 流里拆出完整的 opus 包(跨 BLE 包累积,可能 0 个也可能好几个) + let payload = packet.subdata(in: 9..<(packet.count - 1)) + let packets = ogg.feed(payload) + guard !packets.isEmpty else { + lock.unlock() + return + } + opusPackets += packets.count + + // ② 逐包解码,攒成一块再抛,省掉几次跨通道往返 + var out = Data() + var pcm = [opus_int16](repeating: 0, count: Int(maxFrameSize)) + for pkt in packets { + guard !pkt.isEmpty, pkt.count <= 1275 else { continue } + let samples: opus_int32 = pkt.withUnsafeBytes { raw -> opus_int32 in + guard let base = raw.baseAddress?.assumingMemoryBound(to: UInt8.self) else { return -1 } + return opus_decode(d, base, opus_int32(pkt.count), &pcm, maxFrameSize, 0) + } + if samples <= 0 { continue } + out.append(pcm.prefix(Int(samples)).withUnsafeBufferPointer { Data(buffer: $0) }) + } + guard !out.isEmpty else { + lock.unlock() + return + } + pcmBytesOut += out.count + lock.unlock() + + onPcm?(out) + } + + /// 是不是音频帧。头 7 字节 + `[8] == 0x04` 一起判,单看头会把 RCSP 帧误收 + static func isAudioPacket(_ p: Data) -> Bool { + guard p.count >= 9 else { return false } + return p[0] == 0xFE && p[1] == 0xDC && p[2] == 0xBA && p[3] == 0x80 && + p[4] == 0x01 && p[5] == 0x00 && p[6] == 0x8E && p[8] == 0x04 + } +} diff --git a/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarBleCentral.swift b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarBleCentral.swift new file mode 100644 index 00000000..f9625ca8 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarBleCentral.swift @@ -0,0 +1,230 @@ +import Foundation +import CoreBluetooth + +/// 一条扫描结果(原样把广播段交给 Dart 解析,这里不做任何字段解释) +struct SmartcarScanHit { + let id: String + let name: String + let rssi: Int + /// `CBAdvertisementDataManufacturerDataKey` 的原始内容:前 2 字节是小端公司 ID + let manufacturerData: Data? + let serviceUuids: [String] +} + +/// Smartcar 的 CBCentralManager 持有者(进程内单例)。 +/// +/// 从 lumi 的 `BleScanner.swift` 精简:保留「懒建 central、等 poweredOn 再扫、 +/// 扫描超时、连接/断开回调路由」,去掉状态恢复、自动重连队列、通知中心广播。 +/// +/// 为什么不用 flutter_blue_plus:它的 CBPeripheralDelegate 在它自己手里, +/// 我们拿不到回调去转交给 JL_Assist,认证就没法跑。 +final class SmartcarBleCentral: NSObject { + static let shared = SmartcarBleCentral() + + private var central: CBCentralManager? + private var discovered: [UUID: CBPeripheral] = [:] + private(set) var active: SmartcarPeripheral? + + var onAdapterState: ((String) -> Void)? + var onScanHit: ((SmartcarScanHit) -> Void)? + var onScanStopped: (() -> Void)? + + /// OTA stage2 回连用:先于 [onScanHit] 看每条扫描结果,返回 true 表示已处理(不再上报 Dart) + var scanInterceptor: ((SmartcarScanHit) -> Bool)? + + /// 插件实例:原生侧自己发起的连接(OTA 回连)也要走它,状态事件才会到 Dart + weak var connectDelegate: SmartcarPeripheralDelegate? + + private var readyWaiters: [(Bool) -> Void] = [] + private var readyTimer: Timer? + private static let readyTimeout: TimeInterval = 8 + + private var scanTimer: Timer? + private(set) var isScanning = false + + private override init() { + super.init() + } + + // MARK: - 状态 + + /// 懒建:冷启动不能弹蓝牙权限框,首次真要扫/连时才创建 + func ensureCentral() { + guard central == nil else { return } + central = CBCentralManager(delegate: self, queue: .main, options: [ + CBCentralManagerOptionShowPowerAlertKey: true, + ]) + } + + var stateString: String { + switch central?.state ?? .unknown { + case .poweredOn: return "on" + case .poweredOff: return "off" + case .unauthorized: return "unauthorized" + case .unsupported: return "unsupported" + case .resetting: return "resetting" + default: return "unknown" + } + } + + /// 等 central 变成 poweredOn。unauthorized/unsupported/poweredOff 是终态,直接失败。 + private func waitReady(_ completion: @escaping (Bool) -> Void) { + ensureCentral() + switch central?.state ?? .unknown { + case .poweredOn: + completion(true) + return + case .unauthorized, .unsupported, .poweredOff: + completion(false) + return + default: + break + } + readyWaiters.append(completion) + if readyTimer == nil { + readyTimer = Timer.scheduledTimer(withTimeInterval: Self.readyTimeout, repeats: false) { [weak self] _ in + self?.drainReady(false) + } + } + } + + private func drainReady(_ ok: Bool) { + let list = readyWaiters + readyWaiters.removeAll() + readyTimer?.invalidate() + readyTimer = nil + list.forEach { $0(ok) } + } + + // MARK: - 扫描 + + /// 全量扫(不传 withServices)。C2 的身份信息在厂商自定义数据里, + /// CoreBluetooth 的 service 过滤只匹配「Service UUIDs」字段,加了就一台都扫不到。 + func startScan(timeoutSec: Int, completion: @escaping (Bool, String?) -> Void) { + waitReady { [weak self] ok in + guard let self = self else { return } + guard ok else { + completion(false, "蓝牙不可用: \(self.stateString)" + + (self.stateString == "unauthorized" ? "(权限被拒,去系统设置里打开)" : "")) + return + } + if self.isScanning { + completion(true, nil) + return + } + self.isScanning = true + self.discovered.removeAll() + self.central?.scanForPeripherals(withServices: nil, options: [ + CBCentralManagerScanOptionAllowDuplicatesKey: false, + ]) + self.scanTimer?.invalidate() + self.scanTimer = Timer.scheduledTimer(withTimeInterval: TimeInterval(max(timeoutSec, 1)), repeats: false) { [weak self] _ in + self?.stopScan() + } + completion(true, nil) + } + } + + func stopScan() { + scanTimer?.invalidate() + scanTimer = nil + guard isScanning else { return } + isScanning = false + central?.stopScan() + onScanStopped?() + } + + // MARK: - 连接 + + private func peripheral(for id: String) -> CBPeripheral? { + guard let uuid = UUID(uuidString: id) else { return nil } + if let p = discovered[uuid] { return p } + // 记住的设备回连:不在本次扫描列表里,从系统缓存捞 + if let p = central?.retrievePeripherals(withIdentifiers: [uuid]).first { + discovered[uuid] = p + return p + } + return nil + } + + /// 返回 nil 表示这个 id 既不在扫描结果里、系统也没缓存 + func connect(id: String, delegate: SmartcarPeripheralDelegate) -> SmartcarPeripheral? { + ensureCentral() + guard let central = central, let p = peripheral(for: id) else { return nil } + stopScan() + if let old = active, old.id != id { + old.disconnect() + } + if let cur = active, cur.id == id, cur.state != .disconnected, cur.state != .failed { + // 正在连/已连的同一台:复用,不重复发起 + cur.delegate = delegate + return cur + } + let sp = SmartcarPeripheral(peripheral: p, central: central, delegate: delegate) + active = sp + sp.connect() + return sp + } + + func disconnect() { + active?.disconnect() + } +} + +// MARK: - CBCentralManagerDelegate + +extension SmartcarBleCentral: CBCentralManagerDelegate { + + func centralManagerDidUpdateState(_ central: CBCentralManager) { + // SDK 要知道适配器状态,否则认证流程不启动(lumi 标注为"关键修复") + JLAssistBridge.shared.updateCentralState(central.state) + onAdapterState?(stateString) + switch central.state { + case .poweredOn: + drainReady(true) + case .poweredOff, .unauthorized, .unsupported: + drainReady(false) + if central.state == .poweredOff { + stopScan() + active?.handleDidDisconnect(nil) + } + default: + break + } + } + + func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, + advertisementData: [String: Any], rssi RSSI: NSNumber) { + discovered[peripheral.identifier] = peripheral + let name = peripheral.name + ?? (advertisementData[CBAdvertisementDataLocalNameKey] as? String) + ?? "" + let mfg = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data + let svcs = (advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID])? + .map { $0.uuidString } ?? [] + let hit = SmartcarScanHit( + id: peripheral.identifier.uuidString, + name: name, + rssi: RSSI.intValue, + manufacturerData: mfg, + serviceUuids: svcs + ) + if let i = scanInterceptor, i(hit) { return } + onScanHit?(hit) + } + + func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { + guard let a = active, a.cb.identifier == peripheral.identifier else { return } + a.handleDidConnect() + } + + func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { + guard let a = active, a.cb.identifier == peripheral.identifier else { return } + a.handleDidFailToConnect(error) + } + + func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { + guard let a = active, a.cb.identifier == peripheral.identifier else { return } + a.handleDidDisconnect(error) + } +} diff --git a/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarOta.swift b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarOta.swift new file mode 100644 index 00000000..0a879f19 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarOta.swift @@ -0,0 +1,286 @@ +import Foundation +import CoreBluetooth +import JL_BLEKit +import JL_OTALib + +/// Smartcar(杰理方案)固件升级——从 lumi `PbMangerImp.startOta / handleOtaResult / +/// scanAndConnectStage2` 搬过来,接口对齐 lumi 的 `cmdOTAData` 流程(不是 SDK 新加的 +/// `cmdUpgrade:Option:` 内置回连——那条路 SDK 要自己持有连接,和我们自持 GATT 的做法冲突)。 +/// +/// 流程(单备份固件两段式): +/// ``` +/// cmdOTAData(固件) → 0x08~0x0f 进度 +/// → 0xfc「需按 MAC 回连」= stage1 完成,设备断开重启进 stage2 广播 +/// ├─ 记下 SDK 给的 MAC(outputDeviceModel().bleAddr) +/// ├─ 扫描 3 轮 × 60s:广播 MAC 相同 或 名字命中 → 连接 → 杰理认证 +/// └─ 认证过:noteEntityConnected → cmdTargetFeature → 再 cmdOTAData(同一份固件) +/// → 0x00 成功 / 0x01~0x07、0xf1~0xfb、0xfd 失败 / 0xe1 取消 +/// ``` +/// +/// ⚠️ lumi 的 stage2 广播名固定叫 `Lumi-Music`;Smartcar 的 stage2 名字**还没在样机上看过** +/// (TODO(smartcar-ota)),所以匹配顺序是:广播 MAC == SDK 给的 MAC → 名字含原设备名前缀。 +/// lumi 自己也踩过「SDK 给的 reconnect MAC 经常错」,所以名字兜底不能删。 +/// +/// OTA 期间私有通道(ABC1)的写入被 [SmartcarPeripheral.otaInProgress] 挡掉: +/// 业务包会和 SDK 的 `cmdOTAData` 抢 AE01,lumi 那边卡死过。 +final class SmartcarOta { + static let shared = SmartcarOta() + + enum Phase { case idle, running, stage2Scanning, stage2Connecting } + + /// 事件出口(由插件接到 EventChannel): + /// `{type:"ota", state, percent, code?, message?}`,state ∈ preparing / transferring / + /// stage2 / done / failed / cancelled + var onEvent: (([String: Any]) -> Void)? + + private(set) var phase: Phase = .idle + var isRunning: Bool { phase != .idle } + + private var firmware: Data? + private var targetMac = "" + private var originalName = "" + private var stage2Round = 0 + private var stage2Timer: Timer? + private var heartbeat: Timer? + private var lastLoggedRaw: UInt16? + private weak var peripheral: SmartcarPeripheral? + + private static let stage2MaxRounds = 3 + private static let stage2RoundSec = 60 + private static let stage2InterRoundDelay: TimeInterval = 3 + + private init() {} + + private var otaManager: JL_OTAManager { + JLAssistBridge.shared.assist.mCmdManager.mOTAManager + } + + // MARK: - 对外 + + /// 返回 nil = 已启动;否则是拒绝原因 + func start(filePath: String, peripheral: SmartcarPeripheral) -> String? { + guard phase == .idle else { return "OTA 已在进行中" } + guard peripheral.isReady else { return "链路未就绪(认证未过)" } + guard let data = try? Data(contentsOf: URL(fileURLWithPath: filePath)), !data.isEmpty else { + return "固件文件读不到或为空: \(filePath)" + } + firmware = data + originalName = peripheral.name + self.peripheral = peripheral + peripheral.otaInProgress = true + lastLoggedRaw = nil + phase = .running + emit(state: "preparing", percent: 0) + NSLog("[SmartcarOta] start: %d bytes, device=%@", data.count, originalName) + invoke(data) + return nil + } + + func cancel() { + guard phase != .idle else { return } + NSLog("[SmartcarOta] cancel (phase=%d)", phaseCode) + if phase == .running { + otaManager.cmdOTACancelResult(nil) + } + SmartcarBleCentral.shared.stopScan() + emit(state: "cancelled", percent: -1) + finish() + // 对齐 lumi cancelOta:主动断开,让设备退出升级态 + SmartcarBleCentral.shared.disconnect() + } + + /// 由插件在每次链路状态变化时调用 + func onLinkState(_ state: SmartcarLinkState, peripheral p: SmartcarPeripheral) { + guard phase != .idle else { return } + switch state { + case .disconnected: + // OTA 期间告诉 SDK 链路断了,否则它还以为连着继续往旧 peripheral 发数据 + // —— lumi 注明这是 stage1→stage2 续接能成功的关键 + otaManager.noteEntityDisconnected() + if phase == .stage2Connecting { + fail(code: 0xfd, message: "stage2 设备连上又断开") + } + case .ready: + guard phase == .stage2Connecting else { return } + NSLog("[SmartcarOta] stage2 已连上并认证,续跑 OTA") + self.peripheral = p + p.otaInProgress = true + phase = .running + otaManager.noteEntityConnected() + // 缺 cmdTargetFeature 时 SDK 会按默认 JL_OtaStatusNormal + BootLoaderYES 走 + // loader 下载路径,卡死在 "Need to download loader."(lumi 原话)。 + // 500ms 让认证收尾命令排空,再 1s 等设备 0x03 应答 + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in + guard let self = self, self.phase == .running else { return } + self.otaManager.cmdTargetFeature() + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in + guard let self = self, self.phase == .running, let d = self.firmware else { return } + self.invoke(d) + } + } + case .failed: + if phase == .stage2Connecting { + fail(code: 0xfd, message: "stage2 连接失败") + } + default: + break + } + } + + // MARK: - SDK 回调 + + private func invoke(_ data: Data) { + otaManager.cmdOTAData(data) { [weak self] result, prog in + self?.handle(result: result, prog: prog) + } + } + + /// `rawCode` 直接对应 `JL_OTAResult`,**不折叠**——0x08 升级中 / 0x0b 准备中会被误判成失败 + private func handle(result: JL_OTAResult, prog: Float) { + guard phase != .idle else { return } + let raw = result.rawValue + if raw != lastLoggedRaw { + NSLog("[SmartcarOta] cmdOTAData ===> 0x%02x", Int(raw)) + lastLoggedRaw = raw + } + switch raw { + case 0x00: + emit(state: "done", percent: 100) + finish() + case 0x08...0x0f: + emit(state: "transferring", percent: Int((prog * 100).rounded())) + case 0xfc, 0x09, 0xfe: + // stage1 完成,设备即将断开重启进 stage2。0x09/0xfe 是按 UUID/更新资源回连, + // lumi 只处理 0xfc;这里一并按"扫描回连"处理,比忽略掉安全 + guard phase == .running else { return } + let model = JLAssistBridge.shared.assist.mCmdManager.outputDeviceModel() + targetMac = (model.bleAddr ?? "").uppercased() + NSLog("[SmartcarOta] stage1 完成(0x%02x),等设备重启后回连 mac=%@ name=%@", Int(raw), targetMac, originalName) + emit(state: "stage2", percent: 15, message: "\(targetMac)|\(originalName)") + stage2Round = 0 + startStage2Scan() + case 0xe1: + emit(state: "cancelled", percent: -1) + finish() + case 0x01...0x07, 0xf1...0xfb, 0xfd, 0xe0, 0x10, 0x11: + fail(code: Int(raw), message: "OTA 失败 0x\(String(raw, radix: 16))") + default: + NSLog("[SmartcarOta] 未识别状态 0x%02x,忽略", Int(raw)) + } + } + + // MARK: - stage2 扫描回连 + + private func startStage2Scan() { + phase = .stage2Scanning + let central = SmartcarBleCentral.shared + central.scanInterceptor = { [weak self] hit in + guard let self = self, self.phase == .stage2Scanning else { return false } + guard self.matchesStage2(hit) else { return false } + NSLog("[SmartcarOta] stage2 命中 %@ (%@)", hit.name, hit.id) + self.phase = .stage2Connecting + self.stage2Timer?.invalidate() + central.stopScan() + central.scanInterceptor = nil + if let d = central.connectDelegate, central.connect(id: hit.id, delegate: d) == nil { + self.fail(code: 0xfd, message: "stage2 设备无法发起连接") + } + return true + } + central.startScan(timeoutSec: Self.stage2RoundSec) { [weak self] ok, reason in + guard let self = self else { return } + if !ok { self.fail(code: 0xfd, message: "stage2 扫描起不来: \(reason ?? "")") } + } + // 一轮到点还没命中:等 3s 让 BLE 栈收尾再起下一轮,最多 3 轮 ≈ 186s + stage2Timer?.invalidate() + stage2Timer = Timer.scheduledTimer(withTimeInterval: TimeInterval(Self.stage2RoundSec) + Self.stage2InterRoundDelay, + repeats: false) { [weak self] _ in + guard let self = self, self.phase == .stage2Scanning else { return } + self.stage2Round += 1 + if self.stage2Round < Self.stage2MaxRounds { + NSLog("[SmartcarOta] stage2 第 %d 轮未找到,起下一轮", self.stage2Round) + self.startStage2Scan() + } else { + self.fail(code: 0xfd, message: "3 轮扫描(约 3 分钟)都没等到设备重启后的广播") + } + } + // 上层看门狗 90s 没进度会判失败,stage2 窗口没有进度,用心跳喂它 + heartbeat?.invalidate() + heartbeat = Timer.scheduledTimer(withTimeInterval: 15, repeats: true) { [weak self] _ in + guard let self = self, self.phase == .stage2Scanning || self.phase == .stage2Connecting else { return } + self.emit(state: "stage2", percent: 15) + } + } + + private func matchesStage2(_ hit: SmartcarScanHit) -> Bool { + if let mfg = hit.manufacturerData, let mac = Self.parseAdvMac(mfg), !targetMac.isEmpty { + if mac == targetMac || Self.reverseMac(mac) == targetMac { return true } + } + // TODO(smartcar-ota): stage2 广播名待样机确认;先按"含原设备名"兜底(lumi 是固定名 Lumi-Music) + let name = hit.name.trimmingCharacters(in: .whitespaces).lowercased() + if !name.isEmpty { + if name.contains("smartcar") { return true } + let base = originalName.lowercased().split(separator: "-").first.map(String.init) ?? "" + if base.count >= 4 && name.contains(base) { return true } + } + return false + } + + /// 厂商数据:`05 85 | MAC(6) | 状态` —— 与 Dart 侧 `parseManufacturerData` 同口径 + private static func parseAdvMac(_ data: Data) -> String? { + guard data.count >= 8 else { return nil } + let b = [UInt8](data) + let cid = UInt16(b[0]) | (UInt16(b[1]) << 8) + guard cid == 0x8505 || cid == 0x0585 else { return nil } + return b[2..<8].map { String(format: "%02X", $0) }.joined(separator: ":") + } + + private static func reverseMac(_ mac: String) -> String { + let parts = mac.split(separator: ":") + guard parts.count == 6 else { return mac } + return parts.reversed().joined(separator: ":") + } + + // MARK: - 收尾 + + private func fail(code: Int, message: String) { + guard phase != .idle else { return } + NSLog("[SmartcarOta] failed: %@", message) + emit(state: "failed", percent: -1, code: code, message: message) + finish() + } + + private func finish() { + phase = .idle + firmware = nil + targetMac = "" + stage2Round = 0 + stage2Timer?.invalidate() + stage2Timer = nil + heartbeat?.invalidate() + heartbeat = nil + SmartcarBleCentral.shared.scanInterceptor = nil + peripheral?.otaInProgress = false + peripheral = nil + } + + private var phaseCode: Int { + switch phase { + case .idle: return 0 + case .running: return 1 + case .stage2Scanning: return 2 + case .stage2Connecting: return 3 + } + } + + private func emit(state: String, percent: Int, code: Int? = nil, message: String? = nil) { + var m: [String: Any] = ["type": "ota", "state": state, "percent": percent] + if let c = code { m["code"] = c } + if let s = message { m["message"] = s } + if Thread.isMainThread { + onEvent?(m) + } else { + DispatchQueue.main.async { [weak self] in self?.onEvent?(m) } + } + } +} diff --git a/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarPeripheral.swift b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarPeripheral.swift new file mode 100644 index 00000000..d401efc1 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/ios/device_smartcar/Sources/device_smartcar/SmartcarPeripheral.swift @@ -0,0 +1,338 @@ +import Foundation +import CoreBluetooth +import JL_BLEKit + +/// 链路状态。 +/// +/// ⚠️ `ready` 的含义是**杰理 RCSP 认证已通过**,不是 GATT 连上。 +/// Smartcar 固件(杰理芯片)在认证通过前不把手机当成已连接:屏幕显示 BLE 未连接、 +/// 也不响应 RCSP 命令。这是 lumi 两端代码里都写明的固件行为,不是我们能绕过的。 +enum SmartcarLinkState: String { + case disconnected + case connecting + /// GATT 已连上,正在发现服务 + case linkConnected + /// 已找到 AE00,杰理 SDK 正在跑认证握手 + case authenticating + /// 认证通过,业务可用 + case ready + case failed +} + +protocol SmartcarPeripheralDelegate: AnyObject { + func smartcarPeripheral(_ p: SmartcarPeripheral, didChange state: SmartcarLinkState, reason: String?) + func smartcarPeripheral(_ p: SmartcarPeripheral, didReceiveCustom data: Data) + /// AE02 的原始字节。**音频和 RCSP 命令共用这条通知**,所以两边都要看一眼: + /// SDK 那份照旧交给 JL_Assist,这份给 [SmartcarAudio] 挑 opus 帧。 + func smartcarPeripheral(_ p: SmartcarPeripheral, didReceiveJl data: Data) +} + +/// 一台 Smartcar 的 GATT 会话:自己持有连接,在同一条连接上复用两个服务。 +/// +/// 从 lumi 的 `BlePeripheral.swift`(1058 行)精简而来,保留的是与固件行为相关的部分: +/// - 发现 `AE00`(杰理)与 `ABC0`(C2 私有)两个服务; +/// - `AE00` 交给 `JL_Assist`:由它开 `AE02` 通知、跑认证;`AE02` 的数据全部转交 SDK; +/// - `ABC2` 的通知数据原样交给上层(组帧/CRC 在 Dart 侧); +/// - 连接 35s 超时、失败指数退避重试两次、断开时通知 SDK。 +/// +/// 去掉的是 OTA 大包分片/背压、周期 RSSI、表盘那些——控制帧只有几个字节,用不上。 +final class SmartcarPeripheral: NSObject { + static let jlService = CBUUID(string: "AE00") + static let jlTx = CBUUID(string: "AE01") + static let jlRx = CBUUID(string: "AE02") + static let customService = CBUUID(string: "0000ABC0-0000-1111-2222-123456789ABC") + static let customTx = CBUUID(string: "0000ABC1-0000-1111-2222-123456789ABC") + static let customRx = CBUUID(string: "0000ABC2-0000-1111-2222-123456789ABC") + + private static let connectTimeout: TimeInterval = 35 + /// lumi 对认证失败的处理是「等 SDK 自己重试或超时」;这里给一个明确上限, + /// 否则 UI 会停在「连接中」不动。 + private static let authTimeout: TimeInterval = 15 + private static let retryDelays: [TimeInterval] = [0.5, 2.0] + + let cb: CBPeripheral + private weak var central: CBCentralManager? + weak var delegate: SmartcarPeripheralDelegate? + + private(set) var state: SmartcarLinkState = .disconnected + + /// OTA 进行中:私有通道(ABC1)的写入一律拒绝——业务包会和 SDK 的 cmdOTAData 抢 AE01, + /// lumi 那边卡死过 + var otaInProgress = false + + private var txJL: CBCharacteristic? + private var rxJL: CBCharacteristic? + private var txCustom: CBCharacteristic? + private var rxCustom: CBCharacteristic? + + private var connectTimer: Timer? + private var authTimer: Timer? + private var retries = 0 + private var servicesPending = 0 + private var jlFound = false + + var id: String { cb.identifier.uuidString } + var name: String { cb.name ?? "" } + var isReady: Bool { state == .ready && cb.state == .connected } + + init(peripheral: CBPeripheral, central: CBCentralManager, delegate: SmartcarPeripheralDelegate?) { + self.cb = peripheral + self.central = central + self.delegate = delegate + super.init() + cb.delegate = self + } + + // MARK: - 连接管理 + + func connect() { + guard state == .disconnected || state == .failed else { return } + retries = 0 + startConnect() + } + + private func startConnect() { + guard let central = central else { + fail("CBCentralManager 已释放") + return + } + resetChars() + // CBPeripheral.delegate 是 weak,重连时必须重新绑回来 + cb.delegate = self + set(.connecting) + central.connect(cb, options: [ + CBConnectPeripheralOptionNotifyOnConnectionKey: true, + CBConnectPeripheralOptionNotifyOnDisconnectionKey: true, + ]) + connectTimer?.invalidate() + connectTimer = Timer.scheduledTimer(withTimeInterval: Self.connectTimeout, repeats: false) { [weak self] _ in + guard let self = self, self.state == .connecting else { return } + self.central?.cancelPeripheralConnection(self.cb) + self.fail("GATT 连接超时(\(Int(Self.connectTimeout))s),设备可能已被别的手机连着——BLE 被占用时不再广播也不接受新连接") + } + } + + func disconnect() { + connectTimer?.invalidate() + authTimer?.invalidate() + guard state != .disconnected else { return } + let wasConnecting = state == .connecting + central?.cancelPeripheralConnection(cb) + // 还在 connecting 阶段取消时 iOS 不一定回调 didDisconnect,兜底收状态 + if wasConnecting { + resetChars() + set(.disconnected) + } + } + + /// 往 C2 私有写特征发一帧(组帧/CRC 由 Dart 侧完成)。 + /// + /// 没有 ABC1 时退回 AE01——与 lumi 一致,兼容旧固件把私有协议塞在 RCSP 通道里的情况。 + @discardableResult + func writeCustom(_ data: Data) -> Bool { + guard cb.state == .connected, !data.isEmpty else { return false } + if otaInProgress { return false } + guard let ch = txCustom ?? txJL else { return false } + let type: CBCharacteristicWriteType = + ch.properties.contains(.writeWithoutResponse) ? .withoutResponse : .withResponse + cb.writeValue(data, for: ch, type: type) + return true + } + + // MARK: - 由 CentralManager 代理转发 + + func handleDidConnect() { + connectTimer?.invalidate() + retries = 0 + set(.linkConnected) + // 与 lumi 相同:连上后等 0.2s 再发现服务,太早会碰到 DLE 协商未完成 + DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in + guard let self = self, self.cb.state == .connected else { return } + self.servicesPending = 0 + self.jlFound = false + self.cb.discoverServices([Self.jlService, Self.customService]) + } + } + + func handleDidFailToConnect(_ error: Error?) { + connectTimer?.invalidate() + if retryIfPossible() { return } + fail("GATT 连接失败: \(error?.localizedDescription ?? "unknown")") + } + + func handleDidDisconnect(_ error: Error?) { + connectTimer?.invalidate() + authTimer?.invalidate() + // 让 SDK 清掉它自己那份状态,否则下次认证会用到陈旧的特征引用 + JLAssistBridge.shared.assist.assistDisconnectPeripheral(cb) + JLAssistBridge.shared.unbindEntity() + if state == .connecting, retryIfPossible() { return } + resetChars() + set(.disconnected, reason: error?.localizedDescription) + } + + // MARK: - 内部 + + private func retryIfPossible() -> Bool { + guard retries < Self.retryDelays.count else { return false } + let delay = Self.retryDelays[retries] + retries += 1 + state = .connecting + DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in + guard let self = self, self.state == .connecting else { return } + self.startConnect() + } + return true + } + + private func fail(_ reason: String) { + connectTimer?.invalidate() + authTimer?.invalidate() + resetChars() + set(.failed, reason: reason) + } + + private func set(_ s: SmartcarLinkState, reason: String? = nil) { + state = s + delegate?.smartcarPeripheral(self, didChange: s, reason: reason) + } + + private func resetChars() { + txJL = nil + rxJL = nil + txCustom = nil + rxCustom = nil + servicesPending = 0 + jlFound = false + } + + private func startAuthTimer() { + authTimer?.invalidate() + authTimer = Timer.scheduledTimer(withTimeInterval: Self.authTimeout, repeats: false) { [weak self] _ in + guard let self = self, self.state == .authenticating else { return } + self.fail("杰理 RCSP 认证超时(\(Int(Self.authTimeout))s):SDK 没有回调结果。" + + "多半是固件不接受这套认证密钥,或 AE02 通知没真正打开") + self.central?.cancelPeripheralConnection(self.cb) + } + } +} + +// MARK: - CBPeripheralDelegate + +extension SmartcarPeripheral: CBPeripheralDelegate { + + func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { + if let error = error { + fail("服务发现失败: \(error.localizedDescription)") + central?.cancelPeripheralConnection(cb) + return + } + let services = peripheral.services ?? [] + let list = services.map { $0.uuid.uuidString }.joined(separator: ", ") + + // ⚠️ 没有 AE00 就没法认证,固件不会认我们。把实际服务列出来,别只说"没找到"。 + guard services.contains(where: { $0.uuid == Self.jlService }) else { + fail("BLE 已连上,但设备没有杰理服务 AE00,认证走不了。实际服务: [\(list)]") + central?.cancelPeripheralConnection(cb) + return + } + + servicesPending = services.count + for service in services { + let whitelist: [CBUUID]? + if service.uuid == Self.jlService { + whitelist = [Self.jlTx, Self.jlRx] + } else if service.uuid == Self.customService { + whitelist = [Self.customTx, Self.customRx] + } else { + whitelist = nil + } + peripheral.discoverCharacteristics(whitelist, for: service) + } + } + + func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { + servicesPending -= 1 + let chars = service.characteristics ?? [] + + if service.uuid == Self.jlService { + txJL = chars.first { $0.uuid == Self.jlTx } + rxJL = chars.first { $0.uuid == Self.jlRx } + jlFound = txJL != nil && rxJL != nil + if jlFound { + let assist = JLAssistBridge.shared.assist + // 告诉 SDK RCSP 走哪条服务/特征,认证数据才会发对通道 + assist.mService = Self.jlService.uuidString + assist.mRcsp_W = Self.jlTx.uuidString + assist.mRcsp_R = Self.jlRx.uuidString + assist.mAuthEnable = true + set(.authenticating) + startAuthTimer() + // ★ 只调这个,让 SDK 自己去开 AE02 的通知;**不要**手动 setNotifyValue, + // 也不要在这里绑实体——lumi 照官方示例踩过,绑早了认证不过。 + assist.assistDiscoverCharacteristics(for: service, peripheral: peripheral) + } + } else if service.uuid == Self.customService { + txCustom = chars.first { $0.uuid == Self.customTx } + rxCustom = chars.first { $0.uuid == Self.customRx } + if let rx = rxCustom { + peripheral.setNotifyValue(true, for: rx) + } + } + + if servicesPending <= 0 && !jlFound { + let names = chars.map { $0.uuid.uuidString }.joined(separator: ", ") + fail("杰理服务 AE00 里缺少 AE01/AE02 特征。实际特征: [\(names)]") + central?.cancelPeripheralConnection(cb) + } + } + + func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { + guard characteristic.uuid == Self.jlRx else { return } + if let error = error { + fail("AE02 通知打不开: \(error.localizedDescription)") + central?.cancelPeripheralConnection(cb) + return + } + // AE02 通知一开,SDK 就开始认证握手;结果从这个回调回来 + JLAssistBridge.shared.assist.assistUpdate(characteristic, peripheral: peripheral) { [weak self] ok in + guard let self = self else { return } + self.authTimer?.invalidate() + if ok { + JLAssistBridge.shared.bindEntity(peripheral: peripheral, name: self.name) + if self.state != .ready && self.cb.state == .connected { + self.set(.ready) + } + } else { + self.fail("杰理 RCSP 认证失败:固件拒绝了这次握手") + self.central?.cancelPeripheralConnection(self.cb) + } + } + } + + func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { + guard error == nil, let data = characteristic.value else { return } + switch characteristic.uuid { + case Self.customRx: + delegate?.smartcarPeripheral(self, didReceiveCustom: data) + case Self.jlRx: + // 认证帧 / RCSP 帧全部交给 SDK,我们不解析 + JLAssistBridge.shared.assist.assistUpdateValue(for: characteristic) + // 音频帧也走这条通知,交给上层挑(SmartcarAudio 只认那个 7 字节头) + delegate?.smartcarPeripheral(self, didReceiveJl: data) + default: + break + } + } + + func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { + // 1.13 新增:SDK 内部的写队列靠这个推进(旧版 lumi 用的 1.12 没有它) + if characteristic.uuid == Self.jlTx { + JLAssistBridge.shared.assist.assistDidReady() + } + } + + func peripheralIsReady(toSendWriteWithoutResponse peripheral: CBPeripheral) { + JLAssistBridge.shared.assist.assistDidReady() + } +} diff --git a/apps/client/local_plugins/device_smartcar/lib/device_smartcar.dart b/apps/client/local_plugins/device_smartcar/lib/device_smartcar.dart new file mode 100644 index 00000000..237b7c0c --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/lib/device_smartcar.dart @@ -0,0 +1,82 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; + +/// Smartcar(车载香薰)原生链路的 Dart 通道封装。 +/// +/// 只做三件事:扫描、连接(**含杰理 RCSP 认证**)、收发 C2 私有通道的裸字节。 +/// 组帧 / CRC / 广播解析都在 App 侧的 `smartcar_protocol.dart`,这里不解释任何字节。 +/// +/// `connect()` 只在**认证通过**后才返回——固件在那之前不把手机当成已连接。 +class DeviceSmartcar { + DeviceSmartcar._(); + static final DeviceSmartcar instance = DeviceSmartcar._(); + + static const MethodChannel _method = MethodChannel('com.yimai.device_smartcar'); + static const EventChannel _events = EventChannel('com.yimai.device_smartcar/events'); + + Stream>? _stream; + + /// 原生事件(广播流)。每条形如 `{type: scan|scanStopped|state|custom|adapter, ...}`。 + Stream> get events { + return _stream ??= _events + .receiveBroadcastStream() + .map((e) => Map.from(e as Map)) + .asBroadcastStream(); + } + + Future adapterState() async => + (await _method.invokeMethod('adapterState')) ?? 'unknown'; + + /// 起不来抛 [PlatformException](code `SCAN_FAILED`,message 是原因)。 + Future startScan({int timeoutSec = 15}) => + _method.invokeMethod('startScan', {'timeoutSec': timeoutSec}); + + Future stopScan() => _method.invokeMethod('stopScan'); + + /// 认证通过才 resolve;失败抛 [PlatformException](code `CONNECT_FAILED` / `NOT_FOUND` / `BUSY`)。 + Future connect(String id, {int timeoutSec = 45}) => + _method.invokeMethod('connect', {'id': id, 'timeoutSec': timeoutSec}); + + Future disconnect() => _method.invokeMethod('disconnect'); + + Future isConnected() async => + (await _method.invokeMethod('isConnected')) ?? false; + + /// 认证通过后的杰理 RCSP 收尾序列(设时间 / GET_TARGET_INFO / GET_SYS_INFO), + /// 返回各步的 JL_CMDStatus(0 = 成功)。未认证抛 `NOT_READY`。 + Future> jlPostAuth() async { + final r = await _method.invokeMethod('jlPostAuth'); + return Map.from(r ?? const {}); + } + + /// 开始把设备麦克风的 opus 上行解码成 16k PCM 往上抛(`{type:'audio'}` 事件)。 + /// + /// ⚠️ **不控制设备开麦**:设备是收到 `0xCC 0x11` 唤醒后自己开麦的, + /// 这里只决定原生要不要解码转发。返回 false = opus 解码器起不来。 + Future audioStart() async => + (await _method.invokeMethod('audioStart')) ?? false; + + Future audioStop() => _method.invokeMethod('audioStop'); + + /// 排查用:`{running, framesIn, framesDup, pcmBytesOut}`。 + /// 真机"没声音"时先看这几个数,能立刻区分是没收到帧、全被当重复丢了、还是解码没出字节。 + Future> audioStats() async { + final r = await _method.invokeMethod('audioStats'); + return Map.from(r ?? const {}); + } + + /// 启动杰理 OTA(原生含 stage2 扫描回连)。进度从 [events] 的 `{type:'ota'}` 来。 + /// 起不来抛 [PlatformException](`OTA_FAILED` / `NOT_READY`)。 + Future otaStart(String filePath) => + _method.invokeMethod('otaStart', {'filePath': filePath}); + + Future otaCancel() => _method.invokeMethod('otaCancel'); + + Future otaIsRunning() async => + (await _method.invokeMethod('otaIsRunning')) ?? false; + + /// 往 ABC1 写一帧(已组好、含 CRC 的裸字节) + Future writeCustom(Uint8List data) async => + (await _method.invokeMethod('writeCustom', {'data': data})) ?? false; +} diff --git a/apps/client/local_plugins/device_smartcar/pubspec.yaml b/apps/client/local_plugins/device_smartcar/pubspec.yaml new file mode 100644 index 00000000..b986c345 --- /dev/null +++ b/apps/client/local_plugins/device_smartcar/pubspec.yaml @@ -0,0 +1,31 @@ +name: device_smartcar +description: >- + Smartcar(车载香薰,杰理方案,协议代号 C2)的 BLE 链路:自己持有 GATT 连接, + 同一条连接上跑杰理 RCSP 认证(AE00)与 C2 私有通道(ABC0)。 + 组帧/CRC/广播解析在 Dart 侧(lib/devices/smartcar/smartcar_protocol.dart),本插件只收发裸字节。 +version: 0.0.1 +publish_to: none + +environment: + sdk: ">=3.3.0 <4.0.0" + flutter: ">=3.3.0" + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + +flutter: + plugin: + platforms: + android: + package: com.yimai.device_smartcar + pluginClass: DeviceSmartcarPlugin + ios: + pluginClass: DeviceSmartcarPlugin + swiftPackage: + path: ios/device_smartcar diff --git a/apps/client/local_plugins/recorder_holder/eai_recorde_protocol.md b/apps/client/local_plugins/recorder_holder/EaiRec_protocol.md similarity index 85% rename from apps/client/local_plugins/recorder_holder/eai_recorde_protocol.md rename to apps/client/local_plugins/recorder_holder/EaiRec_protocol.md index 76ecdf50..ee5a5bef 100644 --- a/apps/client/local_plugins/recorder_holder/eai_recorde_protocol.md +++ b/apps/client/local_plugins/recorder_holder/EaiRec_protocol.md @@ -1,7 +1,7 @@ # EAI 录音支架 · BLE 协议规范 -版本:**v0.1(草案,待固件确认)** -日期:2026-09-08 +版本:**v0.2(协议待固件确认;App 侧已按本文落地)** +日期:2026-09-09(v0.1 于 2026-09-08) 适用设备:**带 TF 卡存储的 EAI 录音支架(唯一形态)** --- @@ -62,7 +62,7 @@ | 写特征写类型 | `WRITE_TYPE_NO_RESPONSE`(通道 A 控制) | | MTU 请求 | 连接后 `requestMtu(512)`,取双方 min,结果由 `onMtuChanged` 回传 | | **MTU 请求时机** | **必须在 CCCD 写完后延时 1s 再发**。vivo 等魔改 ROM 在 CCCD `writeDescriptor` 还在队列里时紧跟着发 `requestMtu` 会被协议栈**静默吞掉**(`accepted=true` 但 `ATT_EXCHANGE_MTU_REQ` 根本没上空中),空中抓不到协商 → 数据模式起不来 → 录音失败。同时 MCU 在 connection complete 后也需要几百 ms 进入待命态。 | -| 通知使能顺序 | **先使能音频特征通知,再使能控制特征通知**,顺序颠倒会收不到音频 | +| 通知使能顺序 | **先音频 `ae02` → 再控制 `abc2` → 再文件 `FDA6`**,顺序颠倒会收不到音频。**且必须串行**:Android GATT 同一时刻只允许一个未完成操作,连着发多个 `writeDescriptor` 除第一个外会被静默丢弃(返回 true 但 `onDescriptorWrite` 永不回调)。v0.2 已加 CCCD 队列,逐条发、等回调再发下一条 | | 自动重连 | 最多 10 次,退避 `2s/3s/5s/5s/10s`;主动断开不重连 | | 后台唤醒 | Android 走 CompanionDeviceManager + 前台服务;iOS 走 CoreBluetooth 后台中央模式 | @@ -248,11 +248,11 @@ App 侧当前把 `[2]` 当作整机电量展示。 **下行(App → 设备)**:`0000abc1-0001-…` 的 Write(带响应),**120 字节/块,60 ms 间隔**, 失败重试 1 次、间隔 30 ms。 -> ⚠️ **现状提醒:Android 侧下行音频是死的。** `BleService.kt` 的 `callWriteChar` 声明了但 -> **从未赋值**——`onServicesDiscovered` 只查找了 `abc0` 和 `ae00` 两个 service,没有查找 -> `abc0-0001`。所以 `sendAudioChunk()` 永远走 `callWriteChar == null` 分支直接 return, -> Android 上从来没有真正下行播放过音频;只有 iOS 实现完整。 -> 如果新支架要用下行音频,**Android 侧这条链路需要重新接通**,不是「沿用」而是「新做」。 +> ✅ **已修(v0.2)**:`BleService.kt` 的 `callWriteChar` 原先声明了却**从未赋值**—— +> `onServicesDiscovered` 只查找了 `abc0` 和 `ae00`,没查 `abc0-0001`,于是 +> `sendAudioChunk()` 永远走 `callWriteChar == null` 分支直接 return, +> **Android 上从来没有真正下行播放过音频**(只有 iOS 完整)。现已补上服务查找。 +> 真机上这条链路等于第一次通电,验收时要单独测。 ### 4.7 MTU @@ -634,20 +634,52 @@ u8 second; // 0~59 ## 10. App 侧落地影响清单 -给客户端开发看的「哪些代码要动」: +### 已落地(v0.2,2026-09-09) -| 模块 | 改动 | +**架构决定:通道 B 的协议逻辑全部在 Dart,原生只做搬运。** +原生侧只负责「发现 `0xFDA5`、使能 `0xFDA6` 通知、把原始字节转上来 / 把字节写进 `0xFDA7`」, +帧格式、seq、超时、状态机一律在 `lib/src/rec/`。这样状态机只有一份,Android / iOS +不会各自跑偏,也能脱离真机做单测。 + +> ⚠️ **通道 B 不能像 OTA 那样用 flutter_blue_plus 自己连一条。** 一部手机对同一个 +> peripheral 只能有一条 GATT 连接,通道 A 已经被原生占着了;OTA 能那么做,是因为它 +> 先 `setEnterOta(true)` 把原生连接让了出来,而通道 B 必须与通道 A 同时在线。 + +| 模块 | 状态 | +|---|---| +| `lib/src/rec/rec_protocol.dart` | ✅ 命令号 / 状态码 / 确认魔数 / 文件名校验 | +| `lib/src/rec/rec_frame.dart` | ✅ 包头编解码 + DATA 校验和(覆盖整包、sum 字段按 0) | +| `lib/src/rec/rec_models.dart` | ✅ `REC_INFO` / `FILE_LIST` / `FILE_INFO` / `SETUP_RSP` / `DATA` 解析 | +| `lib/src/rec/rec_client.dart` | ✅ 事务层:seq、3s 超时、FILE_LIST 多包累积、FILE_TRANSFER 会话(offset 跟踪 / 缺口重传 / 5s 空闲超时 / 断点续传 / 取消)、**通道内互斥闸** | +| `lib/src/rec/rec_transport.dart` | ✅ transport 抽象 + `FileRecSink`(落盘、天然续传)+ `MemoryRecFileSink`(单测) | +| `test/rec/` | ✅ 45 个用例:帧编解码、越界包、校验和、去重/重叠/缺口/续传/互斥/魔数 | +| `BleConst.kt` / `BleConst.swift` | ✅ `0xFDA5/6/7`;Android 补 `abc0-0001` | +| `BleService.kt` | ✅ 发现 `FDA5`、CCCD 串行队列、`FDA6` 分派、`writeRecCommand`、修 `callWriteChar` | +| `BleService.swift` | ✅ 同上(CoreBluetooth 自带串行,无需队列) | +| `RecorderHolderPlugin.{kt,swift}` | ✅ `writeRecCommand` / `isRecChannelReady` + `recData` 事件 | +| `EchoMeetDeviceSdk` | ✅ `recorder`(`RecClient`)、`ensureRecChannel()`、`recChannelReady` | +| `HolderDeviceService` | ✅ 连上即 `RTC_SYNC` → `REC_INFO`;`listRecordings` / `downloadRecording` / `deleteRecording`;`recInfo` / `recFiles` 可观测 | +| `device_category_view` | ✅ `phoneHolder` 不再是「链路未接」,路由到 `Routes.holderScan` | +| `AgentModules.defaultsByCategory` | ✅ 支架默认三件套改为 **语音纪要 / 现场录音 / EMAI助手** | +| `HolderDeviceService.bindToServer` | ✅ **未改**:仍是 MAC 上报、`code` 留空,服务端校验逻辑一行未动 | + +### 尚未做 + +| 项 | 说明 | |---|---| -| `BleConst.kt` / `BleConst.swift` | 新增 `0xFDA5/6/7` 三个 UUID | -| `BleService.onServicesDiscovered` | 新增查找 `FDA5` 服务并使能 `FDA6` 通知;**顺带补上一直缺失的 `abc0-0001` 查找**(Android 下行音频修复,见 §4.6) | -| `BleService.onCharacteristicChanged` | 已是 `when(c.uuid)` 分派,加一个 `FDA6` 分支即可;**新写一个通道 B 解析器,不要复用 `processDeviceResponse`**(len 位宽与校验方式都不同) | -| 新增 | 通道 B 的事务层:seq 管理、3s 超时、FILE_LIST 多包累积状态机、FILE_TRANSFER 会话状态机(offset 跟踪 / 5s 无数据超时 / 续传 / 取消) | -| 新增 | 通道 A / 通道 B 全局互斥闸(§7.1) | -| `HolderRecordingService` | 录音状态机从「App 主导」改为「设备主导 + App 观察」,见 §7.3 | -| 新增 UI | TF 卡文件列表页(大小/时间/下载进度/删除)、容量展示、格式化入口(二次确认) | -| `RecordingArchive` | 接入「从 TF 下载的 `.OGG`」这条来源;时长字段待 Q11 | -| `HolderDeviceService.bindToServer` | **不变**(MAC 上报,code 留空) | -| iOS | 通道 B 全部逻辑要在 `BleService.swift` 独立再实现一遍;确认后台 `bluetooth-central` 模式下长时间下载不被挂起 | +| TF 卡文件 UI | 列表页 / 下载进度 / 删除 / 格式化入口全部没有。协议层与 service 入口已就绪,接 UI 时不用再碰蓝牙 | +| `RecordingArchive` 接入 | 下载下来的 `.OGG` 还没走归档 / 上传。**卡在 Q11(没有时长字段)**——`archive()` 要求传 `seconds` | +| 录音状态机归属 | §7.3 说的「App 主导 → 设备主导」还没改,`HolderRecordingService` 仍是原样。**卡在 Q15**(`CC 21/22/23` 与 `REC_INFO` 是不是同一件事没定) | +| 跨通道互斥 | 目前互斥只做在通道 B 内部(传输期间拒绝其它 B 命令)。传输期间**不阻止**通道 A 下发命令,也没给电量上报降频 —— 见 §7.1,等 Q4 给出上报频率再定策略 | +| OTA | 见 §9,待 Q16 | + +### ⚠️ 真机第一件要确认的事 + +**扫描页一台设备都不出现 = 广播名对不上(Q1)**,不是蓝牙权限问题,且不报任何错。 +过滤名字在 `sdk/lib/src/client.dart` 的 `defaultNameFilters`,当前是 +`['EaiRec', 'EAIMAR', 'Pad Note']`,**按前缀、大小写不敏感**匹配 +(改成前缀是因为固件常在名字后挂序列号,如 `EaiRec-1A2B`,全等匹配会全滤掉)。 +拿到真机第一步就是把实际广播名填进去。 **落地顺序建议**(与草案一致): `RTC_SYNC` + `REC_INFO` + `FILE_LIST` + `FILE_TRANSFER` 先跑通只读链路 → 再接 `FILE_INFO` → @@ -655,6 +687,7 @@ u8 second; // 0~59 --- + ## 11. 待固件确认清单 请逐条回复,有异议的改动记进 §12。 @@ -685,3 +718,4 @@ u8 second; // 0~59 | 日期 | 版本 | 变更 | |---|---|---| | 2026-09-08 | v0.1 | 首版。合并现有支架代码实现(通道 A / A' / A'')与 TF 存储协议草案(通道 B),补充两通道互斥、录音状态机归属、App 落地清单与 16 条待确认项。 | +| 2026-09-09 | v0.2 | 落地通道 B:Dart 协议层 + 双端原生原始通道 + SDK/业务层接入(见 §10)。顺带修两处既有缺陷:Android 下行音频特征从未查找(§4.6)、CCCD 通知使能未串行(§2.2)。**协议本身一字未改,16 条待确认项仍全部有效。** | diff --git a/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleConst.kt b/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleConst.kt index d1356f47..308e43e9 100644 --- a/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleConst.kt +++ b/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleConst.kt @@ -25,6 +25,30 @@ object BleConst { /** 客户端特征配置描述符UUID */ val CLIENT_CHAR_CONFIG_UUID: UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") + // ===== 通话/下行音频服务(EaiRec_protocol.md §4.6 通道 A'')===== + // ⚠️ 这两个 UUID 以前只在 iOS 的 BleConst.swift 里有,Android 从来没查找过 + // 对应的 service —— 于是 callWriteChar 恒为 null,sendAudioChunk() 每次都走 + // 「特征值为空」分支直接 return,**Android 上的下行音频从来没通过**。 + /** 下行音频服务 */ + val CALL_AUDIO_SERVICE_UUID: UUID = UUID.fromString("0000abc0-0001-1111-2222-123456789abc") + + /** 下行音频写入特征 */ + val CALL_WRITE_AUDIO_CHAR_UUID: UUID = + UUID.fromString("0000abc1-0001-1111-2222-123456789abc") + + // ===== 通道 B:TF 卡文件(EaiRec_protocol.md §5.1)===== + // 16-bit UUID,展开成完整形式。与通道 A 的 abc0/abc1/abc2 是两套独立的 + // service,帧格式也完全不同(这边是 0xA5 magic + u16 长度,没有帧尾 CRC), + // **解析入口必须按 characteristic 分派,不能与通道 A 共用解析函数**。 + /** 文件服务 0xFDA5 */ + val REC_SERVICE_UUID: UUID = UUID.fromString("0000fda5-0000-1000-8000-00805f9b34fb") + + /** CMD_TX:设备 → APP,Notify */ + val REC_NOTIFY_CHAR_UUID: UUID = UUID.fromString("0000fda6-0000-1000-8000-00805f9b34fb") + + /** CMD_RX:APP → 设备,Write */ + val REC_WRITE_CHAR_UUID: UUID = UUID.fromString("0000fda7-0000-1000-8000-00805f9b34fb") + // ===== 标准 BLE Device Information Service(0x180A)===== // 新固件(2.x+)才提供此服务;用来做新/旧固件代差识别: // 存在此服务 → 新固件(支持 32kbps Opus / 80B 每帧) diff --git a/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleRecord.kt b/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleRecord.kt index f2a24ede..e575efd8 100644 --- a/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleRecord.kt +++ b/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleRecord.kt @@ -577,6 +577,10 @@ class BleRecord private constructor(private val context: Context) : BleService.C override fun onAudioDataReceived1(data: ByteArray) { } + /// 通道 B 的数据与录音流程无关(那是 TF 卡文件管理),这里不处理。 + override fun onRecDataReceived(data: ByteArray) { + } + override fun onWakeupSignalReceived() { } diff --git a/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleService.kt b/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleService.kt index 39ae5bde..4b3a8036 100644 --- a/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleService.kt +++ b/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/BleService.kt @@ -93,6 +93,11 @@ object BleService { // 唤醒信号相关回调 fun onWakeupSignalReceived() + /// 通道 B(TF 卡文件)的原始 BLE value。 + /// 原生**不解析**,原样上抛给 Dart —— 协议状态机只在 Dart 有一份, + /// 见 lib/src/rec/。这样 Android / iOS 不会各自跑偏,也能脱机单测。 + fun onRecDataReceived(data: ByteArray) + // 设备信息相关回调 - 统一回调接口 fun onDeviceInfoReceived(infoType: Int, infoData: Map) } @@ -116,6 +121,19 @@ object BleService { private var writeChar: BluetoothGattCharacteristic? = null private var audioChar: BluetoothGattCharacteristic? = null private var callWriteChar: BluetoothGattCharacteristic? = null + + // ===== 通道 B:TF 卡文件 ===== + private var recNotifyChar: BluetoothGattCharacteristic? = null + private var recWriteChar: BluetoothGattCharacteristic? = null + + /// CCCD 写入队列。 + /// + /// ⚠️ Android GATT **同一时刻只允许一个未完成的操作**:连着发多个 + /// writeDescriptor,除第一个外都会被静默丢弃(writeDescriptor 返回 true, + /// 但 onDescriptorWrite 永远不来)。原先只有音频 + 控制两条通知,第二条 + /// 时灵时不灵;现在加上通道 B 是三条,必须串起来一条一条发。 + private val cccdQueue: Queue = LinkedList() + private var cccdInFlight = false var recordfile: RecordingFile? = null var recordfile1: RecordingFile? = null @@ -758,6 +776,10 @@ object BleService { writeChar = null audioChar = null callWriteChar = null + recNotifyChar = null + recWriteChar = null + cccdQueue.clear() + cccdInFlight = false } } @@ -1002,6 +1024,15 @@ object BleService { return } + // 真机排障用的服务清单。**别删**:`发送命令失败: 设备未连接` 的根因 + // 十有八九是 abc0 私有服务压根没暴露(writeChar==null → checkConn() 恒 false), + // 而那条错误信息指向的是"连接",会把人带到完全错误的方向上去。 + Log.i(TAG, "🔍 服务发现完成,共 ${g.services.size} 个服务") + g.services.forEach { svc -> + Log.i(TAG, " └─ service ${svc.uuid} : " + + svc.characteristics.joinToString { it.uuid.toString() }) + } + // 识别固件代差:看 0x180A (Device Information Service) 是否存在 // - 存在 → 新固件,启用 V2 规格(32kbps/80B),并异步读 0x2A26 拿版本号记录 // - 不存在 → 旧固件,保持 LEGACY 规格(16kbps/40B) @@ -1032,19 +1063,53 @@ object BleService { val audioSvc = g.getService(BleConst.AUDIO_SERVICE_UUID) audioChar = audioSvc?.getCharacteristic(BleConst.RECEIVE_AUDIO_CHAR_UUID) + // 下行音频(通道 A'')。以前这里根本没查找,callWriteChar 恒为 null, + // Android 上的下行播放从来没通过 —— 见 BleConst 里的说明。 + val callSvc = g.getService(BleConst.CALL_AUDIO_SERVICE_UUID) + callWriteChar = callSvc?.getCharacteristic(BleConst.CALL_WRITE_AUDIO_CHAR_UUID) + if (callWriteChar != null) { + Log.i(TAG, "下行音频特征已找到") + } else { + Log.w(TAG, "未找到下行音频特征(本设备可能不支持下行播放)") + } + + // 通道 B:TF 卡文件服务。设备没有 TF 卡功能时找不到是正常的, + // 不影响通道 A,所以只记日志不改连接状态。 + val recSvc = g.getService(BleConst.REC_SERVICE_UUID) + recNotifyChar = recSvc?.getCharacteristic(BleConst.REC_NOTIFY_CHAR_UUID) + recWriteChar = recSvc?.getCharacteristic(BleConst.REC_WRITE_CHAR_UUID) + if (recSvc != null) { + Log.i(TAG, "📁 发现通道 B(TF 卡文件)服务 0xFDA5") + } else { + Log.i(TAG, "未发现 0xFDA5 服务 —— 本设备没有 TF 卡文件能力") + } + startBytesStatistics() writeChar?.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE - //要先设置音频服务的通知,否则接收不到 - // 设置音频服务的通知(如果存在) + // 写类型:协议要 Write 或 Write No Response 都行;设备支持无响应就用它, + // 吞吐更高。只支持有响应写时保持默认,别硬设——设成不支持的类型会写失败。 + recWriteChar?.let { c -> + if (c.properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE != 0) { + c.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE + } + } + + // 通知使能一律排队串行发(见 cccdQueue 的说明)。 + // 顺序仍是「先音频、再控制、最后文件」—— 音频那条历史上就必须排第一, + // 顺序颠倒会收不到音频流。 + cccdQueue.clear() + cccdInFlight = false if (audioChar != null) { - setupNotifications(g, audioChar) - Log.i(TAG, "音频服务特征找到并设置通知") + enqueueNotification(audioChar) + Log.i(TAG, "音频服务特征找到并排队设置通知") } else { Log.w(TAG, "音频服务特征未找到") } - - // 设置主服务的通知 - setupNotifications(g, notifyChar) + enqueueNotification(notifyChar) + if (recNotifyChar != null) { + enqueueNotification(recNotifyChar) + } + drainCccdQueue(g) // 主动请求 MTU 扩展。BLE 默认 23(payload 20B),对音频流几乎没用; // 协商到 247+ 能让 notify 吞吐提升一个数量级。512 是与固件约定的目标值, @@ -1129,6 +1194,12 @@ object BleService { Log.d(TAG, "收到音频数据: ${data.size} 字节") processAudioData(data) } + // 通道 B:TF 卡文件。原样上抛,**不要**走通道 A 的解析函数: + // 两边帧格式不同(这边 magic 0xA5 + u16 长度、无帧尾 CRC), + // 且命令号 0x01~0x07 数值重叠而语义完全不同。 + BleConst.REC_NOTIFY_CHAR_UUID -> { + notifyRecDataReceived(data) + } // 通知特征数据(命令和控制) BleConst.NOTIFY_CHAR_UUID -> { // Log.i(TAG, "收到通知特征数据(命令和控制)") @@ -1177,26 +1248,91 @@ object BleService { override fun onDescriptorWrite( g: BluetoothGatt, d: BluetoothGattDescriptor, status: Int ) { - if (status == BluetoothGatt.GATT_SUCCESS) + if (status == BluetoothGatt.GATT_SUCCESS) { Log.i(TAG, "通知描述符写入成功: ${d.characteristic.uuid}") + } else { + Log.w(TAG, "通知描述符写入失败(status=$status): ${d.characteristic.uuid}") + } + // 无论成功与否都要接着发下一条,否则一次失败会把后面的通知全卡死 + cccdInFlight = false + drainCccdQueue(g) } } /** * 设置特征的通知功能 */ - private fun setupNotifications(g: BluetoothGatt, characteristic: BluetoothGattCharacteristic?) { - if (characteristic == null || characteristic.properties.and(BluetoothGattCharacteristic.PROPERTY_NOTIFY) == 0) { + private fun enqueueNotification(characteristic: BluetoothGattCharacteristic?) { + if (characteristic == null || + characteristic.properties.and(BluetoothGattCharacteristic.PROPERTY_NOTIFY) == 0 + ) { Log.w(TAG, "特征不支持通知功能: ${characteristic?.uuid}") return } + cccdQueue.offer(characteristic) + } + + /** + * 逐条发出排队中的 CCCD 写入。 + * + * 一次只发一条,等 onDescriptorWrite 回来再发下一条 —— Android GATT 不 + * 允许并发操作,连着发只有第一条真正上空中。 + */ + @SuppressLint("MissingPermission") + private fun drainCccdQueue(g: BluetoothGatt) { + if (cccdInFlight) return + val c = cccdQueue.poll() ?: return + val desc = c.getDescriptor(BleConst.CLIENT_CHAR_CONFIG_UUID) + if (desc == null) { + Log.w(TAG, "特征缺少 CCCD 描述符,跳过: ${c.uuid}") + drainCccdQueue(g) + return + } + cccdInFlight = true + g.setCharacteristicNotification(c, true) + desc.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE + val ok = g.writeDescriptor(desc) + Log.d(TAG, "写 CCCD: ${c.uuid} accepted=$ok,队列剩 ${cccdQueue.size}") + if (!ok) { + // 立刻失败时不会有回调,得自己往下走,否则整条队列停摆 + cccdInFlight = false + drainCccdQueue(g) + } + } - g.setCharacteristicNotification(characteristic, true) - val desc = characteristic.getDescriptor(BleConst.CLIENT_CHAR_CONFIG_UUID) - desc?.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE - g.writeDescriptor(desc) + /** + * 通道 B:把一帧原始字节写到 0xFDA7。 + * + * 原生不认识帧格式,也不该认识 —— 组帧、seq、超时、状态机全在 Dart。 + */ + @SuppressLint("MissingPermission") + fun writeRecCommand(data: ByteArray): Boolean { + val c = recWriteChar + val g = bluetoothGatt + // ⚠️ **不能用 checkConn()**:它要求 `writeChar != null`,而那是**通道 A** + // (`abc1`)的写特征。EaiRec 支架的固件只暴露 0xFDA5 一个服务,根本没有 + // 通道 A,于是 checkConn() 恒为 false —— 通道 B 明明齐全却被锁死, + // 表现是「0xFDA5 发现了、握手却写不出去」,TF 卡录音一个都同步不下来。 + // 通道 B 的可用性只取决于它自己那两个特征,用 isRecChannelReady()。 + if (c == null || g == null || !isRecChannelReady()) { + Log.e(TAG, "通道 B 写入失败:未连接或未发现 0xFDA7 特征") + return false + } + return try { + c.value = data + val ok = g.writeCharacteristic(c) + if (!ok) Log.e(TAG, "通道 B writeCharacteristic 返回 false(${data.size} 字节)") + ok + } catch (e: Exception) { + Log.e(TAG, "通道 B 写入异常: ${e.message}", e) + false + } } + /** 通道 B 是否可用(已连接且发现了 0xFDA5 服务) */ + fun isRecChannelReady(): Boolean = + isConnected() && recWriteChar != null && recNotifyChar != null + /** * 处理音频数据 * @param data 音频数据 (Opus) @@ -2532,6 +2668,16 @@ object BleService { /** * 向所有回调监听器分发唤醒信号 */ + private fun notifyRecDataReceived(data: ByteArray) { + for (callback in callbacks) { + try { + callback.onRecDataReceived(data) + } catch (e: Exception) { + Log.e(TAG, "分发通道 B 数据异常: ${e.message}", e) + } + } + } + private fun notifyWakeupSignalReceived() { for (callback in callbacks) { try { diff --git a/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/RecorderHolderPlugin.kt b/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/RecorderHolderPlugin.kt index 70119530..7bd5f3bc 100644 --- a/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/RecorderHolderPlugin.kt +++ b/apps/client/local_plugins/recorder_holder/android/src/main/kotlin/com/recorder/holder/RecorderHolderPlugin.kt @@ -392,6 +392,19 @@ class RecorderHolderPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, val success = BleService.stopScan() result.success(success) } + // ===== 通道 B(TF 卡文件)===== + // 原生只做搬运:写字节 / 报字节。组帧与状态机都在 Dart。 + "writeRecCommand" -> { + val data = call.argument("data") + if (data == null || data.isEmpty()) { + result.error("INVALID_ARGUMENT", "data 不能为空", null) + } else { + result.success(BleService.writeRecCommand(data)) + } + } + "isRecChannelReady" -> { + result.success(BleService.isRecChannelReady()) + } "getDeviceInfo" -> { val address = call.argument("address")?:"" val info = BleService.getDeviceInfo(address); @@ -676,6 +689,11 @@ class RecorderHolderPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, // sendEvent(dataEventSink, mapOf("type" to "audioData", "data" to data), "发送音频数据异常") } + override fun onRecDataReceived(data: ByteArray) { + // 原样转给 Dart,协议解析在 lib/src/rec/ 里做 + sendEvent(dataEventSink, mapOf("type" to "recData", "data" to data), "发送通道B数据异常") + } + override fun onWakeupSignalReceived() { // 将唤醒事件发送到Flutter sendEvent(statusEventSink, mapOf("type" to "wakeup"), "发送唤醒信号异常") diff --git a/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/BleConst.swift b/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/BleConst.swift index bd238a60..d6149eb0 100644 --- a/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/BleConst.swift +++ b/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/BleConst.swift @@ -29,6 +29,19 @@ class BleConst { /** 客户端特征配置描述符UUID */ static let CLIENT_CHAR_CONFIG_UUID = CBUUID(string: "00002902-0000-1000-8000-00805f9b34fb") + // ===== 通道 B:TF 卡文件(EaiRec_protocol.md §5.1)===== + // 与通道 A(abc0/abc1/abc2)是两套独立 service,帧格式完全不同: + // 这边是 magic 0xA5 + u16 长度、无帧尾 CRC,且命令号 0x01~0x07 与通道 A + // 数值重叠而语义不同 —— **解析必须按 characteristic 分派**。 + /** 文件服务 0xFDA5 */ + static let REC_SERVICE_UUID = CBUUID(string: "FDA5") + + /** CMD_TX:设备 → APP,Notify */ + static let REC_NOTIFY_CHAR_UUID = CBUUID(string: "FDA6") + + /** CMD_RX:APP → 设备,Write */ + static let REC_WRITE_CHAR_UUID = CBUUID(string: "FDA7") + // ===== 标准 BLE Device Information Service(0x180A)===== // 新固件(2.x+)才提供;存在 → V2 (32kbps/80B),不存在 → LEGACY (16kbps/40B)。 static let DEVICE_INFO_SERVICE_UUID = CBUUID(string: "180A") diff --git a/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/BleService.swift b/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/BleService.swift index ec6f7d2d..e8655670 100644 --- a/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/BleService.swift +++ b/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/BleService.swift @@ -40,6 +40,10 @@ public class BleService: NSObject { // 唤醒信号回调 func onWakeupSignalReceived() + + /// 通道 B(TF 卡文件)的原始 BLE value。 + /// 原生**不解析**,原样上抛给 Dart —— 协议状态机只在 Dart 有一份(lib/src/rec/)。 + func onRecDataReceived(data: Data) // 设备信息相关回调 func onDeviceInfoReceived(infoType: Int, infoData: [String: Any]) @@ -53,6 +57,10 @@ public class BleService: NSObject { private var notifyCharacteristic: CBCharacteristic? private var audioCharacteristic: CBCharacteristic? + + // ===== 通道 B:TF 卡文件 ===== + private var recNotifyCharacteristic: CBCharacteristic? + private var recWriteCharacteristic: CBCharacteristic? // 添加录制文件管理器 private var recordingFile: RecordingFile? @@ -157,8 +165,13 @@ private var cmdReplyType: UInt8 = 0 } os_log("🔧 开始初始化CBCentralManager", log: logger, type: .info) + // ⚠️ restore identifier **必须进程内唯一**。这里原来也叫 "BLEAssistantCentral", + // 和 local_plugins/ble_service(它被 agent_service 原生依赖着,始终会被链进来 + // 并先于本插件初始化)的一模一样 —— CoreBluetooth 会让后注册同名 id 的那个 + // central 永远停在 .unsupported,表现就是 startScan 恒报「蓝牙未就绪」而 + // 同进程另一个 central 明明是 poweredOn。2026-09-11 iPhone 12 真机复现。 let options: [String: Any] = [ - CBCentralManagerOptionRestoreIdentifierKey: "BLEAssistantCentral", + CBCentralManagerOptionRestoreIdentifierKey: "com.recorder.holder.central", CBCentralManagerOptionShowPowerAlertKey: true ] @@ -291,7 +304,10 @@ private var cmdReplyType: UInt8 = 0 } guard let manager = centralManager, manager.state == .poweredOn else { - os_log("❌ 蓝牙未就绪,无法开始扫描", log: logger, type: .error) + // 把 state 值一起打出来(.error 级别才进 syslog): + // 2=unsupported 多半是 restore identifier 撞了别的插件,见 initializeCentralManager。 + os_log("❌ 蓝牙未就绪,无法开始扫描 (central.state=%d)", + log: logger, type: .error, centralManager?.state.rawValue ?? -1) return false } @@ -459,9 +475,11 @@ private var cmdReplyType: UInt8 = 0 callAudioCharacteristic = nil notifyCharacteristic = nil audioCharacteristic = nil + recNotifyCharacteristic = nil + recWriteCharacteristic = nil os_log("🔍 恢复会话时重新发现服务和特征", log: logger, type: .info) - peripheral.discoverServices([BleConst.PRIMARY_SERVICE_UUID, BleConst.AUDIO_SERVICE_UUID, BleConst.CALL_AUDIO_SERVICE_UUID, BleConst.DEVICE_INFO_SERVICE_UUID]) + peripheral.discoverServices([BleConst.PRIMARY_SERVICE_UUID, BleConst.AUDIO_SERVICE_UUID, BleConst.CALL_AUDIO_SERVICE_UUID, BleConst.REC_SERVICE_UUID, BleConst.DEVICE_INFO_SERVICE_UUID]) os_log("✅ 已恢复设备会话: %@", log: logger, type: .info, peripheral.identifier.uuidString) } @@ -647,6 +665,36 @@ private var cmdReplyType: UInt8 = 0 callback.onAudioDataReceived(data: data) } } + + /// 通知所有回调接收到通道 B(TF 卡文件)数据 + private func notifyRecDataReceived(_ data: Data) { + for callback in callbacks { + callback.onRecDataReceived(data: data) + } + } + + /// 通道 B:把一帧原始字节写到 0xFDA7。 + /// + /// 原生不认识帧格式,也不该认识 —— 组帧、seq、超时、状态机全在 Dart。 + /// 设备支持无响应写就用它(吞吐更高),否则退回有响应写。 + public func writeRecCommand(_ data: Data) -> Bool { + guard let peripheral = peripheralDevice, + let characteristic = recWriteCharacteristic else { + os_log("❌ 通道 B 写入失败:未连接或未发现 0xFDA7 特征", log: logger, type: .error) + return false + } + let type: CBCharacteristicWriteType = + characteristic.properties.contains(.writeWithoutResponse) ? .withoutResponse : .withResponse + peripheral.writeValue(data, for: characteristic, type: type) + return true + } + + /// 通道 B 是否可用(已连接且发现了 0xFDA5 的两个特征) + public func isRecChannelReady() -> Bool { + return peripheralDevice != nil + && recWriteCharacteristic != nil + && recNotifyCharacteristic != nil + } /// 通知所有回调接收到音频数据 private func notifyAudioDataReceived1(data: Data) { for callback in callbacks { @@ -1614,7 +1662,10 @@ extension BleService: SwiftOpusAudioProcessor.AudioDataCallback { @available(iOS 13.0, *) extension BleService: CBCentralManagerDelegate { public func centralManagerDidUpdateState(_ central: CBCentralManager) { - os_log("🔧 CBCentralManager状态更新: %d", log: logger, type: .info, central.state.rawValue) + // .default 而不是 .info:只有 .default/.error 会进设备 syslog, + // 状态机跳变是排 BLE 问题的第一手证据,必须能从 idevicesyslog 里看到。 + os_log("🔧 CBCentralManager状态更新: %d (0=unknown 1=resetting 2=unsupported 3=unauthorized 4=poweredOff 5=poweredOn)", + log: logger, type: .default, central.state.rawValue) switch central.state { case .poweredOn: @@ -1959,7 +2010,7 @@ extension BleService: CBCentralManagerDelegate { os_log("🔍 开始发现服务...", log: logger, type: .debug) // 查找服务(含 DEVICE_INFO_SERVICE_UUID 用于新旧固件识别) - peripheral.discoverServices([BleConst.PRIMARY_SERVICE_UUID, BleConst.AUDIO_SERVICE_UUID, BleConst.CALL_AUDIO_SERVICE_UUID, BleConst.DEVICE_INFO_SERVICE_UUID]) + peripheral.discoverServices([BleConst.PRIMARY_SERVICE_UUID, BleConst.AUDIO_SERVICE_UUID, BleConst.CALL_AUDIO_SERVICE_UUID, BleConst.REC_SERVICE_UUID, BleConst.DEVICE_INFO_SERVICE_UUID]) // 确保Opus解码器处于活跃状态 // if opusProcessor?.isDecoding() != true { @@ -2082,6 +2133,10 @@ extension BleService: CBPeripheralDelegate { os_log("🔍 发现通话音频服务,开始发现通话音频特征...", log: logger, type: .debug) // 通话音频服务,发现通话音频特征 peripheral.discoverCharacteristics([BleConst.CALL_WRITE_AUDIO_CHAR_UUID], for: service) + } else if service.uuid == BleConst.REC_SERVICE_UUID { + os_log("📁 发现通道 B(TF 卡文件)服务 0xFDA5", log: logger, type: .info) + peripheral.discoverCharacteristics( + [BleConst.REC_NOTIFY_CHAR_UUID, BleConst.REC_WRITE_CHAR_UUID], for: service) } else if service.uuid == BleConst.DEVICE_INFO_SERVICE_UUID { os_log("🔍 发现设备信息服务 (0x180A),开始发现固件版本特征...", log: logger, type: .debug) peripheral.discoverCharacteristics([BleConst.FIRMWARE_REVISION_CHAR_UUID], for: service) @@ -2120,6 +2175,13 @@ extension BleService: CBPeripheralDelegate { callAudioCharacteristic = characteristic os_log("🎵 通话音频特征已设置,开始发现描述符...", log: logger, type: .info) // 先发现描述符,再配置通知 + } else if characteristic.uuid == BleConst.REC_NOTIFY_CHAR_UUID { + recNotifyCharacteristic = characteristic + os_log("📁 通道 B 通知特征已设置,开始发现描述符...", log: logger, type: .info) + peripheral.discoverDescriptors(for: characteristic) + } else if characteristic.uuid == BleConst.REC_WRITE_CHAR_UUID { + recWriteCharacteristic = characteristic + os_log("📁 通道 B 写入特征已设置", log: logger, type: .info) } else if characteristic.uuid == BleConst.FIRMWARE_REVISION_CHAR_UUID { // 0x2A26 只读,异步读取一次,结果在 didUpdateValueFor 处理 os_log("📖 读取固件版本特征 0x2A26...", log: logger, type: .debug) @@ -2153,6 +2215,10 @@ extension BleService: CBPeripheralDelegate { } else if characteristic.uuid == BleConst.RECEIVE_AUDIO_CHAR_UUID { // 处理音频数据 processAudioData(data) + } else if characteristic.uuid == BleConst.REC_NOTIFY_CHAR_UUID { + // 通道 B:原样上抛,**不要**走 handleResponseData(那是通道 A 的 + // AA/BB/CC + CRC8 帧格式,与这边完全不同) + notifyRecDataReceived(data) } else if characteristic.uuid == BleConst.FIRMWARE_REVISION_CHAR_UUID { // 0x2A26 读到版本号字符串。码率判定不依赖内容,仅记录供诊断。 let version = String(data: data, encoding: .utf8)? @@ -2193,7 +2259,9 @@ extension BleService: CBPeripheralDelegate { characteristic.uuid.uuidString, characteristic.descriptors?.count ?? 0) // 对通知特征和音频特征配置通知 - if characteristic.uuid == BleConst.NOTIFY_CHAR_UUID || characteristic.uuid == BleConst.RECEIVE_AUDIO_CHAR_UUID { + if characteristic.uuid == BleConst.NOTIFY_CHAR_UUID + || characteristic.uuid == BleConst.RECEIVE_AUDIO_CHAR_UUID + || characteristic.uuid == BleConst.REC_NOTIFY_CHAR_UUID { setupNotification(for: peripheral, characteristic: characteristic) } } diff --git a/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/RecorderHolderPlugin.swift b/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/RecorderHolderPlugin.swift index 50a2f76d..cad15006 100644 --- a/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/RecorderHolderPlugin.swift +++ b/apps/client/local_plugins/recorder_holder/ios/recorder_holder/Sources/recorder_holder/RecorderHolderPlugin.swift @@ -133,6 +133,20 @@ public class RecorderHolderPlugin: NSObject, FlutterPlugin { BleService.shared.stopScan() result(true) + // ===== 通道 B(TF 卡文件)===== + // 原生只做搬运:写字节 / 报字节。组帧与状态机都在 Dart。 + case "writeRecCommand": + let arguments = call.arguments as? [String: Any] + guard let typed = arguments?["data"] as? FlutterStandardTypedData, + !typed.data.isEmpty else { + result(FlutterError(code: "INVALID_ARGUMENT", message: "data 不能为空", details: nil)) + return + } + result(BleService.shared.writeRecCommand(typed.data)) + + case "isRecChannelReady": + result(BleService.shared.isRecChannelReady()) + case "getDeviceList": let arguments = call.arguments as? [String: Any] let deviceName = (arguments?["deviceName"] as? String) ?? "" @@ -357,6 +371,18 @@ extension RecorderHolderPlugin: BleService.Callback { // Reserved } + public func onRecDataReceived(data: Data) { + // 原样转给 Dart,协议解析在 lib/src/rec/ 里做 + if let eventSink = dataEventSink { + DispatchQueue.main.async { + eventSink([ + "type": "recData", + "data": FlutterStandardTypedData(bytes: data) + ]) + } + } + } + public func onWakeupSignalReceived() { if let eventSink = statusEventSink { DispatchQueue.main.async { diff --git a/apps/client/local_plugins/recorder_holder/lib/recorder_holder_rec.dart b/apps/client/local_plugins/recorder_holder/lib/recorder_holder_rec.dart new file mode 100644 index 00000000..0b9df106 --- /dev/null +++ b/apps/client/local_plugins/recorder_holder/lib/recorder_holder_rec.dart @@ -0,0 +1,13 @@ +/// EaiRec 支架 · 通道 B(TF 卡文件)协议层。 +/// +/// 规范见 `EaiRec_protocol.md` §5。协议逻辑全部在 Dart,原生侧只负责把 +/// `0xFDA6` 的通知原样转上来、把字节写到 `0xFDA7`——所以状态机只有一份, +/// Android / iOS 不会各自跑偏,也能脱离真机做单测。 +library recorder_holder_rec; + +export 'src/rec/rec_client.dart'; +export 'src/rec/rec_frame.dart'; +export 'src/rec/rec_models.dart'; +export 'src/rec/rec_native_transport.dart'; +export 'src/rec/rec_protocol.dart'; +export 'src/rec/rec_transport.dart'; diff --git a/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_client.dart b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_client.dart new file mode 100644 index 00000000..4ed07d2d --- /dev/null +++ b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_client.dart @@ -0,0 +1,665 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'rec_frame.dart'; +import 'rec_models.dart'; +import 'rec_protocol.dart'; +import 'rec_transport.dart'; + +/// 协议层错误。[status] 有值表示设备明确回了一个非 OK 的状态码。 +class RecException implements Exception { + final String message; + final RecStatus? status; + + RecException(this.message, {this.status}); + + @override + String toString() => + 'RecException($message${status == null ? '' : ', status: $status'})'; +} + +/// 下载结果。 +class RecDownloadResult { + final String name; + final int bytes; + final int fileSize; + final int ftime; + + /// 期间发生过几次「offset 缺口 / 空闲超时」导致的重新 SETUP。 + /// 真机调优时这个数字比吞吐更能说明问题。 + final int resumes; + + const RecDownloadResult({ + required this.name, + required this.bytes, + required this.fileSize, + required this.ftime, + required this.resumes, + }); + + bool get complete => bytes == fileSize; +} + +/// 取消令牌。下载是长任务,UI 必须能中断它。 +class RecCancelToken { + bool _cancelled = false; + + bool get isCancelled => _cancelled; + + void cancel() => _cancelled = true; +} + +/// 通道 B(TF 卡文件)的事务层与状态机。 +/// +/// 对应 `EaiRec_protocol.md` §5。职责: +/// - 发送方 seq 递增与帧组装 +/// - 单事务串行 + 3s 超时([RecTiming.commandTimeout]) +/// - `FILE_LIST` 的多包累积,直到 `eof = 1` +/// - `FILE_TRANSFER` 会话:offset 跟踪、缺口重传、5s 空闲超时、断点续传 +/// - 设备主动上报(`REC_INFO` / 录音停止后的 `FILE_LIST`)的分发 +/// +/// **不负责**:GATT 连接、与通道 A 的互斥。后者由上层 +/// (`HolderDeviceService`)统一调度——协议层看不到通道 A。 +class RecClient { + RecClient({ + required RecTransport transport, + void Function(String msg)? log, + this.verifyChecksum = true, + this.commandTimeout = RecTiming.commandTimeout, + this.idleTimeout = RecTiming.transferIdleTimeout, + }) : _transport = transport, + _log = log ?? _noop; + + static void _noop(String _) {} + + final RecTransport _transport; + final void Function(String) _log; + + /// DATA 包是否校验 `sum`。 + /// + /// 默认开。协议文档 Q12 还留着「`sum = 0` 表示不启用」这个未定后门—— + /// 若真机上发现固件根本没实现校验和(表现为每包都判失败、传输走不动), + /// 把这个关掉可以先跑通链路,但**上线前必须和固件把 Q12 定死**。 + final bool verifyChecksum; + + /// 普通命令超时。默认取协议值,单测里调小以免每个用例真等 3 秒。 + final Duration commandTimeout; + + /// 传输期间「多久没收到新 DATA 就重来」。同上,可调只为可测。 + final Duration idleTimeout; + + StreamSubscription? _sub; + + int _seq = 0; + + // ---- 单事务:同一时刻只允许一个未完成的请求 ---- + Completer? _lock; + _Pending? _pending; + Timer? _pendingTimer; + + // ---- FILE_LIST 多包累积 ---- + final List _listAccum = []; + + // ---- FILE_TRANSFER 当前会话 ---- + _TransferSession? _transfer; + + final _infoCtrl = StreamController.broadcast(); + final _listCtrl = StreamController>.broadcast(); + + /// 设备状态。查询结果与主动上报都会推到这里。 + Stream get onRecInfo => _infoCtrl.stream; + + /// 设备**主动**推来的完整文件列表(录音停止后固件会自己推一次)。 + Stream> get onFileListPushed => _listCtrl.stream; + + bool get isTransferring => _transfer != null; + + /// 开始收包。 + void attach() { + _sub ??= _transport.incoming.listen(_onRaw, onError: (Object e) { + _log('通道 B 接收流异常: $e'); + }); + } + + Future detach() async { + await _sub?.cancel(); + _sub = null; + _failPending(RecException('链路已断开')); + _transfer?.fail(RecException('链路已断开')); + _transfer = null; + _listAccum.clear(); + } + + Future dispose() async { + await detach(); + await _infoCtrl.close(); + await _listCtrl.close(); + } + + // ========================================================================== + // 对外命令 + // ========================================================================== + + /// `0x07 RTC_SYNC`。协议建议每次连上就同步一次,成本低。 + /// + /// 时间按**设备本地时间**理解,不做时区协商(协议文档 §5.12), + /// 所以这里直接送手机的本地时间,不转 UTC。 + Future syncRtc([DateTime? now]) async { + final t = now ?? DateTime.now(); + final payload = [ + ...RecBytes.u16le(t.year), + t.month, + t.day, + t.hour, + t.minute, + t.second, + ]; + final rsp = await _request(RecCmd.rtcSync, payload); + _expectOk(rsp, 'RTC_SYNC'); + } + + /// `0x01 REC_INFO` + Future queryInfo() async { + final rsp = await _request(RecCmd.recInfo, const []); + final info = RecInfo.parse(rsp.payload); + if (info == null) throw RecException('REC_INFO 响应长度非法'); + return info; + } + + /// `0x02 FILE_LIST`。设备会连续推多包,这里一直收到 `eof = 1` 才返回。 + Future> listFiles() async { + _listAccum.clear(); + final rsp = await _request(RecCmd.fileList, const [], collectList: true); + // _request 在 eof 到达时才完成,累积结果挂在 pending 上 + final items = rsp.listResult; + if (items == null) throw RecException('FILE_LIST 未返回完整列表'); + return items; + } + + /// `0x03 FILE_INFO`(可选命令,固件可能未实现,会回 UNSUPPORTED) + Future fileInfo(String name) async { + _requireValidName(name); + final encoded = RecFileName.encode(name); + final rsp = await _request(RecCmd.fileInfo, [encoded.length, ...encoded]); + final info = RecFileInfo.parse(rsp.payload); + if (info == null) throw RecException('FILE_INFO 响应长度非法'); + if (!info.status.isOk) { + throw RecException('FILE_INFO 失败', status: info.status); + } + return info; + } + + /// `0x05 FILE_DELETE`。**调用前 UI 必须已二次确认**(协议文档 §5.10)。 + Future deleteFile(String name) async { + _requireValidName(name); + final encoded = RecFileName.encode(name); + final rsp = await _request(RecCmd.fileDelete, [ + ...RecBytes.u32le(RecConfirm.delete), + encoded.length, + ...encoded, + ]); + _expectOk(rsp, 'FILE_DELETE'); + } + + /// `0x06 REC_FORMAT`。**调用前 UI 必须已二次确认**,这是不可逆的数据销毁。 + Future format({int fsType = 0}) async { + final rsp = await _request(RecCmd.format, [ + ...RecBytes.u32le(RecConfirm.format), + fsType, + ]); + _expectOk(rsp, 'REC_FORMAT'); + } + + /// `0x04 FILE_TRANSFER`:下载一个文件到 [sink]。 + /// + /// 断点续传是天然的:起始 offset 取 `sink.length`,所以传入一个已经写了 + /// 一半的 sink 就是续传。 + /// + /// [maxResumes] 是「缺口 / 空闲超时」触发重新 SETUP 的次数上限,超了就报错, + /// 避免弱链路下无限重试把电量耗光。 + Future download({ + required String name, + required RecFileSink sink, + void Function(int received, int total)? onProgress, + RecCancelToken? cancelToken, + int maxResumes = 8, + }) async { + _requireValidName(name); + if (_transfer != null) { + throw RecException('已有文件传输在进行中', status: RecStatus.busy); + } + + final session = _TransferSession( + name: name, + sink: sink, + onProgress: onProgress, + log: _log, + verifyChecksum: verifyChecksum, + idleTimeout: idleTimeout, + ); + _transfer = session; + + try { + var resumes = 0; + while (true) { + if (cancelToken?.isCancelled ?? false) { + await _sendCancel(RecCancelReason.userCancel); + throw RecException('用户取消', status: RecStatus.cancelled); + } + + // ⚠️ 必须**先**开好接收窗口再发 SETUP:设备收到 SETUP_RSP 之后是立刻连续 + // 推 DATA 的,等 SETUP 的 await 返回再准备接收,中间那几包会被丢掉, + // 于是第一包就判 offset 缺口 → CANCEL → 重来,陷入死循环。 + session.beginAttempt(cancelToken); + + final setupRsp = await _setupTransfer(name, sink.length); + if (!setupRsp.status.isOk) { + throw RecException('SETUP 失败', status: setupRsp.status); + } + session.onSetup(setupRsp); + + // 设备实际给的起点可能与请求的不同;它比本地已有的还靠后就是空洞, + // 补不上,只能判失败——继续写下去文件中间会缺一段而大小却是对的。 + if (setupRsp.startOfs > sink.length) { + throw RecException( + 'SETUP 返回的 start_ofs(${setupRsp.startOfs}) 超过本地已有(${sink.length}),无法续传', + ); + } + + final outcome = await session.awaitOutcome(); + if (outcome == _TransferOutcome.done) { + return RecDownloadResult( + name: name, + bytes: sink.length, + fileSize: setupRsp.fileSize, + ftime: setupRsp.ftime, + resumes: resumes, + ); + } + + resumes++; + if (resumes > maxResumes) { + await _sendCancel(RecCancelReason.timeout); + throw RecException('重试 $maxResumes 次仍未完成,放弃'); + } + // 协议要求:发现缺口 / 超时先 CANCEL,再从期望 offset 重新 SETUP + await _sendCancel(RecCancelReason.offsetMismatch); + _log('通道 B 传输重来第 $resumes 次,从 offset ${sink.length} 续'); + } + } finally { + session.abort(); + _transfer = null; + await sink.close(); + } + } + + /// 主动中断当前传输。 + Future cancelTransfer() async { + if (_transfer == null) return; + await _sendCancel(RecCancelReason.userCancel); + _transfer?.fail(RecException('已取消', status: RecStatus.cancelled)); + } + + // ========================================================================== + // 内部:请求 / 响应 + // ========================================================================== + + Future<_Pending> _request( + int cmd, + List payload, { + bool collectList = false, + }) async { + // 协议文档 §7.1:文件传输期间禁止下发其它命令。设备侧「同一时间只允许一个 + // 传输」,中途插进来的命令会把它打断,所以闸门放在协议层而不是指望上层记得。 + if (_transfer != null && cmd != RecCmd.fileTransfer) { + throw RecException('文件传输进行中,拒绝命令 0x${cmd.toRadixString(16)}', + status: RecStatus.busy); + } + await _acquire(); + try { + final pending = _Pending(cmd: cmd, collectList: collectList); + _pending = pending; + _listAccum.clear(); + + final frame = RecFrame.build(cmd: cmd, seq: _nextSeq(), payload: payload); + await _transport.send(frame); + + _pendingTimer = Timer(commandTimeout, () { + _failPending(RecException( + '命令 0x${cmd.toRadixString(16)} 超时(${commandTimeout.inMilliseconds}ms)')); + }); + + return await pending.completer.future; + } finally { + _pendingTimer?.cancel(); + _pendingTimer = null; + _pending = null; + _release(); + } + } + + /// SETUP 走的是同一条单事务通道,但**只等 SETUP_RSP**; + /// 之后的 DATA 是设备连续推的,不占事务槽。 + Future _setupTransfer(String name, int startOfs) async { + final encoded = RecFileName.encode(name); + final rsp = await _request(RecCmd.fileTransfer, [ + RecTransferAction.setup, + ...RecBytes.u32le(startOfs), + encoded.length, + ...encoded, + ]); + final parsed = rsp.setupRsp; + if (parsed == null) throw RecException('SETUP_RSP 响应非法'); + return parsed; + } + + Future _sendCancel(int reason) async { + try { + final frame = RecFrame.build( + cmd: RecCmd.fileTransfer, + seq: _nextSeq(), + payload: [RecTransferAction.cancel, reason], + ); + await _transport.send(frame); + } catch (e) { + // 取消发不出去不该覆盖掉真正的失败原因 + _log('发送 CANCEL 失败(忽略): $e'); + } + } + + int _nextSeq() { + final s = _seq; + _seq = (_seq + 1) & 0xFF; + return s; + } + + Future _acquire() async { + while (_lock != null) { + await _lock!.future; + } + _lock = Completer(); + } + + void _release() { + final l = _lock; + _lock = null; + if (l != null && !l.isCompleted) l.complete(); + } + + void _failPending(RecException e) { + final p = _pending; + _pending = null; + _pendingTimer?.cancel(); + _pendingTimer = null; + if (p != null && !p.completer.isCompleted) { + p.completer.completeError(e); + } + } + + void _expectOk(_Pending rsp, String what) { + if (rsp.payload.isEmpty) { + throw RecException('$what 响应为空'); + } + final st = RecStatus.fromCode(rsp.payload[0] & 0xFF); + if (!st.isOk) throw RecException('$what 失败', status: st); + } + + void _requireValidName(String name) { + if (!RecFileName.isValid(name)) { + throw RecException('文件名非法: $name', status: RecStatus.paramErr); + } + } + + // ========================================================================== + // 内部:收包分发 + // ========================================================================== + + void _onRaw(Uint8List bytes) { + final frame = RecFrame.tryParse(bytes); + if (frame == null) { + // magic / len 不符一律丢弃,不回错误帧(协议文档 §5.2) + return; + } + switch (frame.cmd) { + case RecCmd.fileTransfer: + _onTransferFrame(frame); + break; + case RecCmd.fileList: + _onFileListFrame(frame); + break; + case RecCmd.recInfo: + _onRecInfoFrame(frame); + break; + default: + _completePending(frame); + } + } + + void _onRecInfoFrame(RecFrame frame) { + final info = RecInfo.parse(frame.payload); + if (info != null && !_infoCtrl.isClosed) { + // 查询结果与主动上报都推给订阅者:录音状态变化是设备驱动的, + // 上层要靠这条流才能知道「设备自己开始录了」。 + _infoCtrl.add(info); + } + _completePending(frame); + } + + void _onFileListFrame(RecFrame frame) { + final page = RecFileListPage.parse(frame.payload); + if (page == null) { + _log('FILE_LIST 包结构非法,已丢弃(len=${frame.payload.length})'); + return; + } + _listAccum.addAll(page.items); + if (!page.eof) return; + + final all = List.unmodifiable(_listAccum); + _listAccum.clear(); + + final p = _pending; + if (p != null && p.cmd == RecCmd.fileList) { + p.listResult = all; + _completePending(frame); + } else { + // 无人在等 → 这是录音停止后设备主动推的那一次 + if (!_listCtrl.isClosed) _listCtrl.add(all); + } + } + + void _onTransferFrame(RecFrame frame) { + if (frame.payload.isEmpty) return; + final action = frame.payload[0] & 0xFF; + final body = frame.payload.sublist(1); + + switch (action) { + case RecTransferAction.setupRsp: + final parsed = RecTransferSetupRsp.parse(body); + final p = _pending; + if (p != null && p.cmd == RecCmd.fileTransfer) { + p.setupRsp = parsed; + _completePending(frame); + } + break; + + case RecTransferAction.data: + final data = RecTransferData.parse(body, frame.raw); + if (data == null) { + _log('DATA 包结构非法,已丢弃'); + return; + } + _transfer?.onData(data); + break; + + case RecTransferAction.cancel: + final reason = body.isNotEmpty ? body[0] & 0xFF : -1; + _log('设备取消了传输,reason=$reason'); + _transfer?.fail( + RecException('设备中断了传输 (reason=$reason)', status: RecStatus.cancelled)); + break; + + default: + _log('未知的 FILE_TRANSFER action: 0x${action.toRadixString(16)}'); + } + } + + void _completePending(RecFrame frame) { + final p = _pending; + if (p == null || p.cmd != frame.cmd) return; + // FILE_LIST 要等 eof 才算完成 + if (p.collectList && p.listResult == null) return; + p.payload = frame.payload; + _pending = null; + _pendingTimer?.cancel(); + _pendingTimer = null; + if (!p.completer.isCompleted) p.completer.complete(p); + } +} + +/// 一次未完成的请求。 +class _Pending { + _Pending({required this.cmd, this.collectList = false}); + + final int cmd; + final bool collectList; + final Completer<_Pending> completer = Completer<_Pending>(); + + Uint8List payload = Uint8List(0); + List? listResult; + RecTransferSetupRsp? setupRsp; +} + +enum _TransferOutcome { done, needResume } + +/// 一次文件传输的接收侧状态机。 +class _TransferSession { + _TransferSession({ + required this.name, + required this.sink, + required this.log, + required this.verifyChecksum, + required this.idleTimeout, + this.onProgress, + }); + + final String name; + final RecFileSink sink; + final void Function(String) log; + final bool verifyChecksum; + final Duration idleTimeout; + final void Function(int received, int total)? onProgress; + + int _fileSize = 0; + Completer<_TransferOutcome>? _done; + Timer? _idle; + RecCancelToken? _cancelToken; + bool _aborted = false; + + /// 落盘是异步的,而 DATA 是连续推来的——必须串起来,否则并发 append + /// 会把字节顺序写乱,而且 [sink.length] 在两次 await 之间是不可信的。 + Future _writeChain = Future.value(); + + void onSetup(RecTransferSetupRsp rsp) => _fileSize = rsp.fileSize; + + /// 开启一次尝试的接收窗口。**在发 SETUP 之前调用。** + void beginAttempt(RecCancelToken? cancelToken) { + _cancelToken = cancelToken; + _done = Completer<_TransferOutcome>(); + _restartIdle(); + } + + Future<_TransferOutcome> awaitOutcome() { + final d = _done; + if (d == null) { + throw StateError('awaitOutcome 必须在 beginAttempt 之后调用'); + } + return d.future; + } + + /// 整个下载结束(成功或失败)时清场,避免定时器泄漏。 + void abort() { + _aborted = true; + _idle?.cancel(); + _idle = null; + } + + void onData(RecTransferData d) { + if (_aborted || _done == null || _done!.isCompleted) return; + + if (verifyChecksum && !d.checksumOk) { + // 校验不过就当没收到:不推进 offset,靠空闲超时重来。 + log('DATA 校验和不符 @${d.fileOfs},丢弃'); + return; + } + + if (_cancelToken?.isCancelled ?? false) { + _finish(RecException('用户取消', status: RecStatus.cancelled)); + return; + } + + _restartIdle(); + _writeChain = _writeChain.then((_) => _apply(d)).catchError((Object e) { + _finish(e is RecException ? e : RecException('落盘失败: $e')); + }); + } + + Future _apply(RecTransferData d) async { + if (_done == null || _done!.isCompleted) return; + + final expected = sink.length; + + if (d.fileOfs > expected) { + // 缺口:协议要求 CANCEL 后从期望 offset 重新 SETUP + log('offset 缺口:收到 ${d.fileOfs},期望 $expected'); + _finishOutcome(_TransferOutcome.needResume); + return; + } + + if (d.fileOfs + d.data.length <= expected) { + // 整包都是已经写过的,直接丢 + return; + } + + // 部分重叠:只接尾巴那一段 + final skip = expected - d.fileOfs; + final slice = skip > 0 ? d.data.sublist(skip) : d.data; + if (slice.isNotEmpty) { + await sink.append(slice); + onProgress?.call(sink.length, _fileSize); + } + + if (d.isEnd) { + if (_fileSize > 0 && sink.length != _fileSize) { + // END 到了但大小对不上:中间丢过东西,让外层重新 SETUP 补齐 + log('收到 END 但大小不符:本地 ${sink.length} / 应为 $_fileSize'); + _finishOutcome(_TransferOutcome.needResume); + return; + } + _finishOutcome(_TransferOutcome.done); + } + } + + void _restartIdle() { + _idle?.cancel(); + _idle = Timer(idleTimeout, () { + log('传输空闲超过 ${idleTimeout.inMilliseconds}ms,准备续传'); + _finishOutcome(_TransferOutcome.needResume); + }); + } + + void fail(RecException e) => _finish(e); + + void _finish(Object error) { + _idle?.cancel(); + _idle = null; + final d = _done; + if (d != null && !d.isCompleted) d.completeError(error); + } + + void _finishOutcome(_TransferOutcome o) { + _idle?.cancel(); + _idle = null; + final d = _done; + if (d != null && !d.isCompleted) d.complete(o); + } +} diff --git a/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_frame.dart b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_frame.dart new file mode 100644 index 00000000..4c100e45 --- /dev/null +++ b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_frame.dart @@ -0,0 +1,112 @@ +import 'dart:typed_data'; + + +/// 小端读写helper。通道 B 的所有多字节整数一律 little-endian(协议文档 §5.2)。 +class RecBytes { + RecBytes._(); + + static List u16le(int v) => [v & 0xFF, (v >> 8) & 0xFF]; + + static List u32le(int v) => [ + v & 0xFF, + (v >> 8) & 0xFF, + (v >> 16) & 0xFF, + (v >> 24) & 0xFF, + ]; + + static int readU16le(List b, int off) => + (b[off] & 0xFF) | ((b[off + 1] & 0xFF) << 8); + + static int readU32le(List b, int off) => + (b[off] & 0xFF) | + ((b[off + 1] & 0xFF) << 8) | + ((b[off + 2] & 0xFF) << 16) | + ((b[off + 3] & 0xFF) << 24); +} + +/// 通道 B 的包头:`magic(1) | cmd(1) | seq(1) | len(2 LE)`,共 5 字节。 +class RecHeader { + RecHeader._(); + + static const int magic = 0xA5; + static const int size = 5; +} + +/// 一个解析好的通道 B 帧。 +class RecFrame { + final int cmd; + final int seq; + final Uint8List payload; + + /// 原始 BLE value(含包头)。`FILE_TRANSFER/DATA` 的校验和要按整包算, + /// 所以必须把原始字节留着,不能只保留 payload。 + final Uint8List raw; + + RecFrame({ + required this.cmd, + required this.seq, + required this.payload, + required this.raw, + }); + + /// 解析一个 BLE value。 + /// + /// 返回 `null` 表示这个包**应当被丢弃**(协议文档 §5.2:magic 不符或 len 不符 + /// 直接丢弃,不回错误帧)。这里刻意不抛异常——通道上混进别的数据是正常现象, + /// 抛异常会把接收循环打断。 + static RecFrame? tryParse(List bytes) { + if (bytes.length < RecHeader.size) return null; + if ((bytes[0] & 0xFF) != RecHeader.magic) return null; + final len = RecBytes.readU16le(bytes, 3); + if (bytes.length != RecHeader.size + len) return null; + return RecFrame( + cmd: bytes[1] & 0xFF, + seq: bytes[2] & 0xFF, + payload: Uint8List.fromList(bytes.sublist(RecHeader.size)), + raw: Uint8List.fromList(bytes), + ); + } + + /// 组一个 App → 设备的帧。 + static Uint8List build({ + required int cmd, + required int seq, + List payload = const [], + }) { + final out = BytesBuilder(); + out.addByte(RecHeader.magic); + out.addByte(cmd & 0xFF); + out.addByte(seq & 0xFF); + out.add(RecBytes.u16le(payload.length)); + out.add(payload); + return out.toBytes(); + } + + @override + String toString() => + 'RecFrame(cmd: 0x${cmd.toRadixString(16)}, seq: $seq, len: ${payload.length})'; +} + +/// `FILE_TRANSFER/DATA` 的校验和(协议文档 §5.9)。 +/// +/// 「整个 BLE value 逐字节累加的 u16,计算时 sum 字段自身两字节按 0 处理」。 +/// +/// ⚠️ **计算范围包含包头**。最容易写错成只算 `data[]`——那样算出来永远对不上, +/// 表现是每一包都被判校验失败、传输永远走不动。 +class RecChecksum { + RecChecksum._(); + + /// DATA 包里 `sum` 字段相对于**整包起始**的偏移: + /// hdr(5) + action_cmd(1) + file_ofs(4) + control(1) = 11 + static const int sumOffsetInPacket = 11; + + static int compute(List packet, {int sumOffset = sumOffsetInPacket}) { + var sum = 0; + for (var i = 0; i < packet.length; i++) { + // sum 字段自身两字节按 0 参与计算 + if (i == sumOffset || i == sumOffset + 1) continue; + sum = (sum + (packet[i] & 0xFF)) & 0xFFFF; + } + return sum; + } +} diff --git a/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_models.dart b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_models.dart new file mode 100644 index 00000000..202c5b71 --- /dev/null +++ b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_models.dart @@ -0,0 +1,250 @@ +import 'dart:typed_data'; + +import 'rec_frame.dart'; +import 'rec_protocol.dart'; + +/// `REC_INFO` 响应(协议文档 §5.6)。 +/// +/// payload: `status(1) fs_type(1) total_kb(4) used_kb(4) rec_state(1)` = 11 字节 +class RecInfo { + final RecStatus status; + final int fsType; + final int totalKb; + final int usedKb; + + /// 是否正在录音。协议明确:**本字段始终有效**, + /// 即使 `status != OK` 也要采信它,其余字段按 0 处理。 + final bool recording; + + const RecInfo({ + required this.status, + required this.fsType, + required this.totalKb, + required this.usedKb, + required this.recording, + }); + + static const int payloadSize = 11; + + int get freeKb => (totalKb - usedKb).clamp(0, totalKb); + + /// 有没有卡。`NO_CARD` 是明确信号;容量为 0 只能算旁证,不作判据。 + bool get hasCard => status != RecStatus.noCard; + + static RecInfo? parse(List p) { + if (p.length < payloadSize) return null; + final status = RecStatus.fromCode(p[0] & 0xFF); + final ok = status.isOk; + return RecInfo( + status: status, + // status != OK 时其余字段按 0 处理(协议文档 §5.6) + fsType: ok ? p[1] & 0xFF : 0, + totalKb: ok ? RecBytes.readU32le(p, 2) : 0, + usedKb: ok ? RecBytes.readU32le(p, 6) : 0, + recording: (p[10] & 0xFF) != 0, + ); + } + + @override + String toString() => 'RecInfo(status: $status, fs: ${RecFsType.describe(fsType)}, ' + '$usedKb/$totalKb KB, recording: $recording)'; +} + +/// 文件列表里的一条(协议文档 §5.7)。 +/// +/// 线格式: `size(4) ftime(4) name_len(1) name[name_len]` +class RecFileItem { + final String name; + final int size; + + /// 原始 FAT 时间戳。解不出合法日期时 [time] 为 null,但这里始终保留原值。 + final int ftime; + + const RecFileItem({ + required this.name, + required this.size, + required this.ftime, + }); + + /// 按标准 FAT 布局解码:高 16 位是日期,低 16 位是时间。 + /// + /// ⚠️ 协议只写了「格式同 `fs_get_ftime()`」,没给字段布局。这里按 FAT 通行布局 + /// 实现(date = year-1980 << 9 | month << 5 | day;time = hour << 11 | + /// min << 5 | sec/2)。**真机第一次拿到列表时要核对这个解码是否对得上**, + /// 对不上会表现为「文件时间全是 1980 年」或日期乱跳。见协议文档 Q11 附近。 + DateTime? get time { + final date = (ftime >> 16) & 0xFFFF; + final t = ftime & 0xFFFF; + final year = 1980 + ((date >> 9) & 0x7F); + final month = (date >> 5) & 0x0F; + final day = date & 0x1F; + final hour = (t >> 11) & 0x1F; + final minute = (t >> 5) & 0x3F; + final second = (t & 0x1F) * 2; + if (month < 1 || month > 12 || day < 1 || day > 31) return null; + if (hour > 23 || minute > 59 || second > 59) return null; + try { + return DateTime(year, month, day, hour, minute, second); + } catch (_) { + return null; + } + } + + @override + String toString() => 'RecFileItem($name, $size B, ${time ?? ftime})'; +} + +/// `FILE_LIST` 的单个响应包(一次查询会有多包,直到 [eof])。 +class RecFileListPage { + final RecStatus status; + final bool eof; + final List items; + + const RecFileListPage({ + required this.status, + required this.eof, + required this.items, + }); + + /// payload: `status(1) item_count(1) eof(1) items[]` + /// + /// 返回 null 表示这一包结构非法(长度对不上、item 越界、文件名不合法)。 + /// 协议要求 App「同时校验 hdr.len 与 item_count,避免异常包越界解析」。 + static RecFileListPage? parse(List p) { + if (p.length < 3) return null; + final status = RecStatus.fromCode(p[0] & 0xFF); + final count = p[1] & 0xFF; + final eof = (p[2] & 0xFF) != 0; + + final items = []; + var off = 3; + for (var i = 0; i < count; i++) { + // size(4) + ftime(4) + name_len(1) + if (off + 9 > p.length) return null; + final size = RecBytes.readU32le(p, off); + final ftime = RecBytes.readU32le(p, off + 4); + final nameLen = p[off + 8] & 0xFF; + final nameStart = off + 9; + if (nameLen < RecFileName.minNameLen) return null; + if (nameStart + nameLen > p.length) return null; + final raw = p.sublist(nameStart, nameStart + nameLen); + if (!RecFileName.isValidRaw(raw)) return null; + items.add(RecFileItem( + name: RecFileName.decode(raw), + size: size, + ftime: ftime, + )); + off = nameStart + nameLen; + } + // item_count 说有 N 条就必须正好是 N 条,多出来的尾巴说明这一包结构已经坏了 + if (off != p.length) return null; + return RecFileListPage(status: status, eof: eof, items: items); + } +} + +/// `FILE_INFO` 响应(协议文档 §5.8)。 +class RecFileInfo { + final RecStatus status; + final int size; + final int ftime; + + const RecFileInfo({ + required this.status, + required this.size, + required this.ftime, + }); + + static const int payloadSize = 9; + + static RecFileInfo? parse(List p) { + if (p.length < payloadSize) return null; + final status = RecStatus.fromCode(p[0] & 0xFF); + final ok = status.isOk; + return RecFileInfo( + status: status, + size: ok ? RecBytes.readU32le(p, 1) : 0, + ftime: ok ? RecBytes.readU32le(p, 5) : 0, + ); + } +} + +/// `FILE_TRANSFER / SETUP_RSP`(协议文档 §5.9)。 +/// +/// payload(不含 action_cmd): `status(1) file_size(4) start_ofs(4) ftime(4) data_len(2)` +class RecTransferSetupRsp { + final RecStatus status; + final int fileSize; + final int startOfs; + final int ftime; + + /// 设备侧采用的单包 data 长度。 + /// + /// ⚠️ **只用于日志和限速判断,不能拿它当每包的固定长度去切数据**—— + /// 最后一包通常更短。实际长度一律用 `hdr.len - 8`。 + final int dataLen; + + const RecTransferSetupRsp({ + required this.status, + required this.fileSize, + required this.startOfs, + required this.ftime, + required this.dataLen, + }); + + static const int bodySize = 15; + + static RecTransferSetupRsp? parse(List body) { + if (body.length < bodySize) return null; + final status = RecStatus.fromCode(body[0] & 0xFF); + final ok = status.isOk; + return RecTransferSetupRsp( + status: status, + fileSize: ok ? RecBytes.readU32le(body, 1) : 0, + startOfs: ok ? RecBytes.readU32le(body, 5) : 0, + ftime: ok ? RecBytes.readU32le(body, 9) : 0, + dataLen: ok ? RecBytes.readU16le(body, 13) : 0, + ); + } +} + +/// `FILE_TRANSFER / DATA`(协议文档 §5.9)。 +class RecTransferData { + final int fileOfs; + final int control; + final int sum; + final Uint8List data; + + const RecTransferData({ + required this.fileOfs, + required this.control, + required this.sum, + required this.data, + required this.checksumOk, + }); + + /// 收到的 sum 与本地按整包算出来的是否一致。 + /// + /// 刻意做成字段而不是「校验失败就返回 null」:调用方需要区分 + /// 「包坏了」和「校验和对不上」,前者只能丢,后者要打日志—— + /// 协议文档 Q12 还留着「sum = 0 表示不启用」这个未定的后门, + /// 真机上第一次对不上时,日志是唯一能判断固件到底实现了哪种语义的依据。 + final bool checksumOk; + + bool get isEnd => control == RecDataControl.end; + + /// [body] 是去掉 action_cmd 之后的部分;[whole] 是整包(校验和要按整包算)。 + /// + /// 返回 null 只表示**包结构非法**;校验和结果看 [checksumOk]。 + static RecTransferData? parse(List body, List whole) { + // file_ofs(4) + control(1) + sum(2) + if (body.length < 7) return null; + final sum = RecBytes.readU16le(body, 5); + return RecTransferData( + fileOfs: RecBytes.readU32le(body, 0), + control: body[4] & 0xFF, + sum: sum, + data: Uint8List.fromList(body.sublist(7)), + checksumOk: RecChecksum.compute(whole) == sum, + ); + } +} diff --git a/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_native_transport.dart b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_native_transport.dart new file mode 100644 index 00000000..154e541f --- /dev/null +++ b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_native_transport.dart @@ -0,0 +1,43 @@ +import 'dart:typed_data'; + +import '../recorder_holder.dart'; +import 'rec_transport.dart'; + +/// 走原生 GATT 的通道 B 传输实现。 +/// +/// 原生侧只做两件事:把 `0xFDA6` 的通知原样转上来、把字节写到 `0xFDA7`。 +/// 因此这里薄得只剩转发——所有协议逻辑都在 [RecClient]。 +/// +/// ⚠️ **不要改成用 flutter_blue_plus 自己连一条**:一部手机对同一个 peripheral +/// 只能有一条 GATT 连接,而通道 A(控制 / 实时音频)已经被原生占着了。 +/// OTA 那边能用 flutter_blue_plus,是因为它先 `setEnterOta(true)` 把原生连接让了出来。 +class RecNativeTransport implements RecTransport { + RecNativeTransport({RecorderHolder? plugin}) + : _plugin = plugin ?? RecorderHolder(); + + final RecorderHolder _plugin; + + bool _ready = false; + + @override + Stream get incoming => _plugin.onRecData; + + @override + bool get isReady => _ready; + + /// 向原生确认通道是否可用,并把结果缓存到 [isReady]。 + Future refreshReady() async { + _ready = await _plugin.isRecChannelReady(); + return _ready; + } + + @override + Future send(List data) async { + final ok = await _plugin.writeRecCommand(data); + if (!ok) { + // 写失败必须抛,不能静默返回:上层 RecClient 正等着响应, + // 吞掉的话它只会一路等到 3 秒超时,日志里看不出是写没出去。 + throw StateError('通道 B 写入失败(${data.length} 字节)'); + } + } +} diff --git a/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_protocol.dart b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_protocol.dart new file mode 100644 index 00000000..a360bfd4 --- /dev/null +++ b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_protocol.dart @@ -0,0 +1,191 @@ +/// EaiRec 支架 · 通道 B(TF 卡文件)协议常量。 +/// +/// 规范见 `EaiRec_protocol.md` §5。本文件只放"线上格式"的常量, +/// 不含任何状态机逻辑,方便固件对照。 +library recorder_holder_rec_protocol; + +/// 通道 B 的 GATT UUID(16-bit,与协议文档 §5.1 一致)。 +class RecUuid { + RecUuid._(); + + /// Service `0xFDA5` + static const int service16 = 0xFDA5; + + /// CMD_TX:设备 → App,Notify + static const int notify16 = 0xFDA6; + + /// CMD_RX:App → 设备,Write / Write No Response + static const int cmdRx16 = 0xFDA7; + + static const String service = '0000fda5-0000-1000-8000-00805f9b34fb'; + static const String notify = '0000fda6-0000-1000-8000-00805f9b34fb'; + static const String cmdRx = '0000fda7-0000-1000-8000-00805f9b34fb'; +} + +/// 命令号(协议文档 §5.4)。 +/// +/// ⚠️ 与通道 A 的 `0x01~0x07` **数值重叠但语义完全不同**(A 的 0x04 是电量, +/// 这里的 0x04 是文件传输)。两者在不同 characteristic 上,解析入口必须按 +/// characteristic 分派,不能共用。 +class RecCmd { + RecCmd._(); + + static const int recInfo = 0x01; + static const int fileList = 0x02; + static const int fileInfo = 0x03; + static const int fileTransfer = 0x04; + static const int fileDelete = 0x05; + static const int format = 0x06; + static const int rtcSync = 0x07; +} + +/// `FILE_TRANSFER` 的子操作。 +class RecTransferAction { + RecTransferAction._(); + + /// App → 设备:设置传输配置 + static const int setup = 0x01; + + /// 设备 → App:配置响应 + static const int setupRsp = 0x02; + + /// 设备 → App:文件数据 + static const int data = 0x03; + + /// 双向:取消 / 中断 + static const int cancel = 0x04; +} + +/// `DATA.control` +class RecDataControl { + RecDataControl._(); + + static const int cont = 0x00; + static const int end = 0x01; +} + +/// `CANCEL.reason` +class RecCancelReason { + RecCancelReason._(); + + static const int userCancel = 0; + static const int offsetMismatch = 1; + static const int timeout = 2; + static const int deviceError = 3; +} + +/// 状态码(协议文档 §5.3)。 +enum RecStatus { + ok(0x00), + paramErr(0x01), + busy(0x02), + noCard(0x03), + fsErr(0x04), + fileNotFound(0x05), + accessDenied(0x06), + unsupported(0x07), + noSpace(0x08), + cancelled(0x09); + + const RecStatus(this.code); + + final int code; + + bool get isOk => this == RecStatus.ok; + + static RecStatus fromCode(int code) { + for (final s in RecStatus.values) { + if (s.code == code) return s; + } + return RecStatus.fsErr; + } +} + +/// 文件系统类型(`REC_INFO.fs_type`)。 +class RecFsType { + RecFsType._(); + + static const int fat12 = 1; + static const int fat16 = 2; + static const int fat32 = 3; + static const int exfat = 4; + + static String describe(int v) { + switch (v) { + case fat12: + return 'FAT12'; + case fat16: + return 'FAT16'; + case fat32: + return 'FAT32'; + case exfat: + return 'exFAT'; + default: + return 'unknown($v)'; + } + } +} + +/// 危险操作的确认魔数(协议文档 §5.10 / §5.11)。 +class RecConfirm { + RecConfirm._(); + + /// "DEL!" + static const int delete = 0x44454C21; + + /// "FMT!" + static const int format = 0x464D5421; +} + +/// 协议里写死的时序常量(协议文档 §5.2 / §5.9)。 +class RecTiming { + RecTiming._(); + + /// 普通命令超时。超时后重发当前命令。 + static const Duration commandTimeout = Duration(seconds: 3); + + /// 文件传输期间「多久没收到新 DATA 就判超时」。 + /// + /// 注意这条**不能**照搬 [commandTimeout]:SETUP 之后设备是连续推数据的, + /// 中途一次卡顿就重来会让大文件永远传不完。 + static const Duration transferIdleTimeout = Duration(seconds: 5); +} + +/// 协议要求的文件名校验(协议文档 §5.5)。 +/// +/// 设备返回的名字也要过这一关——固件返回脏数据时,不校验就会把文件写到 +/// `\REC\` 以外的地方去。 +class RecFileName { + RecFileName._(); + + /// `name[]` 允许的最小总长度(含结尾 `\0`):1 个字符 + 1 个 `\0`。 + static const int minNameLen = 2; + + /// 校验一个**已含结尾 `\0`** 的原始 name 字节序列。 + static bool isValidRaw(List raw) { + if (raw.length < minNameLen) return false; + if (raw.last != 0x00) return false; + for (var i = 0; i < raw.length - 1; i++) { + final c = raw[i]; + // 中间不允许再出现 \0,也不允许路径分隔符 + if (c == 0x00 || c == 0x2F /* / */ || c == 0x5C /* \ */) return false; + } + return true; + } + + /// 校验一个 App 侧要发出去的文件名(不含 `\0`)。 + static bool isValid(String name) { + if (name.isEmpty) return false; + for (final c in name.codeUnits) { + if (c == 0x00 || c == 0x2F || c == 0x5C || c > 0x7F) return false; + } + return true; + } + + /// 编码成协议要求的 `name[]`:ASCII + 结尾 `\0`。 + static List encode(String name) => [...name.codeUnits, 0x00]; + + /// 从原始 `name[]` 解出字符串(去掉结尾 `\0`)。 + static String decode(List raw) => + String.fromCharCodes(raw.sublist(0, raw.length - 1)); +} diff --git a/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_transport.dart b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_transport.dart new file mode 100644 index 00000000..14f485ab --- /dev/null +++ b/apps/client/local_plugins/recorder_holder/lib/src/rec/rec_transport.dart @@ -0,0 +1,97 @@ +import 'dart:io'; +import 'dart:typed_data'; + +/// 通道 B 的传输抽象。 +/// +/// 与 OTA 那边的 `FotTransport` 同一个思路:把状态机与具体 BLE 栈解耦, +/// 于是协议逻辑可以用假 transport 做单测,而真机上走原生 GATT。 +/// +/// ⚠️ **通道 B 不能用 flutter_blue_plus 自己再连一条**。一部手机对同一个 +/// peripheral 只能有一条 GATT 连接,而通道 A(控制 / 实时音频)已经被原生侧 +/// 占着了。OTA 之所以能用 flutter_blue_plus,是因为它会先 `setEnterOta(true)` +/// 把原生那条连接让出来——通道 B 要与通道 A 同时在线,没有这个条件。 +abstract class RecTransport { + /// 设备 → App 的原始 BLE value 流(`0xFDA6` notify),一次通知一个事件。 + Stream get incoming; + + /// App → 设备写一帧(`0xFDA7`)。 + Future send(List data); + + /// 通道是否就绪(GATT 已连接且 FDA5 服务已发现)。 + bool get isReady; +} + +/// 下载时的落盘出口。 +/// +/// 抽象出去有两个理由:单测不碰文件系统;以及 App 侧可能想边下边算时长/校验, +/// 不必都塞进协议层。 +/// +/// **只需要追加写**:DATA 按 `file_ofs` 顺序推,乱序包由 [RecClient] 负责丢弃或 +/// 重新 SETUP,所以 sink 永远只会被要求从 [length] 处往后接。这也让断点续传 +/// 天然成立——重连后 [length] 就是新的 `start_ofs`。 +abstract class RecFileSink { + /// 已写入的字节数,等于「期望的下一个 file_ofs」。 + int get length; + + Future append(List data); + + Future close(); +} + +/// 内存 sink,单测与小文件用。 +class MemoryRecFileSink implements RecFileSink { + final BytesBuilder _buf = BytesBuilder(); + + @override + int get length => _buf.length; + + @override + Future append(List data) async => _buf.add(data); + + @override + Future close() async {} + + Uint8List get bytes => _buf.toBytes(); +} + +/// 落到本地文件的 sink,带断点续传。 +/// +/// [length] 直接取文件当前大小,所以「上次没下完的那个文件」传进来就是续传, +/// 不需要额外记进度。 +class FileRecSink implements RecFileSink { + FileRecSink(this.file); + + final File file; + + RandomAccessFile? _raf; + int _length = 0; + + /// 打开文件并定位到末尾。文件不存在就新建。 + Future open() async { + if (!await file.parent.exists()) { + await file.parent.create(recursive: true); + } + _raf = await file.open(mode: FileMode.append); + _length = await _raf!.length(); + await _raf!.setPosition(_length); + } + + @override + int get length => _length; + + @override + Future append(List data) async { + final raf = _raf; + if (raf == null) throw StateError('FileRecSink 未 open()'); + await raf.writeFrom(data); + _length += data.length; + } + + @override + Future close() async { + // flush 之后再关:BLE 下载动辄几分钟,中途被杀进程时已落盘的部分要能续上 + await _raf?.flush(); + await _raf?.close(); + _raf = null; + } +} diff --git a/apps/client/local_plugins/recorder_holder/lib/src/recorder_holder.dart b/apps/client/local_plugins/recorder_holder/lib/src/recorder_holder.dart index 8b90a671..422ab02e 100644 --- a/apps/client/local_plugins/recorder_holder/lib/src/recorder_holder.dart +++ b/apps/client/local_plugins/recorder_holder/lib/src/recorder_holder.dart @@ -54,6 +54,7 @@ class RecorderHolder { // ==================== Typed streams (lazy) ==================== Stream? _audioDataStream; + Stream? _recDataStream; Stream? _connectionStateStream; Stream>? _scanResultStream; Stream? _deviceInfoStream; @@ -90,6 +91,23 @@ class RecorderHolder { return _audioDataStream!; } + /// 通道 B(TF 卡文件)的原始 BLE value(`0xFDA6` 通知)。 + /// + /// 原生不解析,一次通知一个事件。协议解析在 `lib/src/rec/` 的 [RecClient] 里, + /// 只有一份实现,Android / iOS 共用。 + Stream get onRecData { + _recDataStream ??= _dataStream + .where((event) => + event is Map && event['type'] == 'recData' && event['data'] != null) + .map((event) { + final data = event['data']; + if (data is Uint8List) return data; + if (data is List) return Uint8List.fromList(data); + return Uint8List(0); + }); + return _recDataStream!; + } + /// All status events (connection, scan, device info, recording) Stream get onStatusEvent { _statusEventStream ??= _statusStream @@ -190,6 +208,34 @@ class RecorderHolder { } } + /// 通道 B:写一帧到 `0xFDA7`。 + /// + /// [data] 是**已经组好帧**的完整 BLE value(含 0xA5 包头)——组帧由 + /// [RecFrame.build] 负责,原生只搬运。 + Future writeRecCommand(List data) async { + try { + return await _methodChannel.invokeMethod( + 'writeRecCommand', + {'data': Uint8List.fromList(data)}, + ) ?? + false; + } catch (e) { + return false; + } + } + + /// 通道 B 是否可用(已连接且发现了 `0xFDA5` 服务)。 + /// + /// 设备没有 TF 卡能力时为 false,此时通道 A 仍然正常工作。 + Future isRecChannelReady() async { + try { + return await _methodChannel.invokeMethod('isRecChannelReady') ?? + false; + } catch (e) { + return false; + } + } + /// Stop scanning for BLE devices Future stopScan() async { try { diff --git a/apps/client/local_plugins/recorder_holder/recorder_protocol(2)(1).md b/apps/client/local_plugins/recorder_holder/recorder_protocol(2)(1).md deleted file mode 100644 index cd713f49..00000000 --- a/apps/client/local_plugins/recorder_holder/recorder_protocol(2)(1).md +++ /dev/null @@ -1,489 +0,0 @@ -# BLE Recorder File Protocol Draft - -版本:V0.1 - -本文档定义 APP 通过 BLE 同步设备 TF 卡内容的私有协议草案,覆盖 TF 信息查询、文件列表、文件信息、文件传输、删除文件、格式化和录音状态上报。 - -## BLE GATT - -建议使用一个自定义 Service,两个 Characteristic。 - -| Characteristic | 方向 | 属性 | 用途 | -| --- | --- | --- | --- | -| CMD_RX | APP -> Device | Write 或 Write Without Response | APP 下发命令、传输配置、取消 | -| CMD_TX | Device -> APP | Notify | 设备返回响应、连续文件数据 | - -当前工程实现使用 16-bit UUID: - -| 项目 | UUID | -| --- | --- | -| Service | `0xFDA5` | -| CMD_TX | `0xFDA6` | -| CMD_RX | `0xFDA7` | - -文件传输使用 Notify,不使用 Indicate。Indicate 每包都需要 ATT 确认,吞吐会明显下降。 - -## 基础约定 - -- 所有多字节整数均为 little-endian。 -- 所有结构体均为 packed。 -- 每个 BLE value 均以 `ble_rec_pkt_hdr_t` 开头。 -- 请求和响应不再用 `type` 区分,由 BLE 方向和 `cmd` 决定。 -- 文件查询、传输、删除固定在 TF 卡 `\REC\` 目录下。 -- APP 只传文件名,不传路径,例如 `MIC0016.OGG`。 -- 第一版文件名固定使用 8.3 短文件名,建议大写 ASCII,例如 `MIC0016.OGG`。 -- 所有变长 `name[]` 均必须带字符串结束符 `\0`。 -- `name_len` 表示 `name[]` 总长度,包含结尾 `\0`。例如 `MIC0016.OGG` 的 `name_len = 12`。 -- 接收方应同时校验 `name_len` 和结尾 `\0`,两者任一异常都按参数错误处理。 -- `name_len` 最小值为 2,最后一个字节必须是 `0x00`,前面的文件名内容不能包含 `\` 或 `/`。 -- 协议版本不在线协商,APP 和固件按项目版本配套发布。后续新增字段尽量只在结构体末尾扩展。 - -结构体说明: - -- 文档中的 packed 结构体表示 BLE 线格式,不要求 APP 或固件直接对收包 buffer 做结构体指针强转。 -- 解析 `u16/u32` 时应按 little-endian 从字节流读取,避免非对齐访问问题。 -- `hdr.len` 表示 payload 长度,即 `BLE value 总长度 - sizeof(ble_rec_pkt_hdr_t)`。 -- 变长数组所在结构体的实际长度需要按字段长度计算,不能使用 `sizeof()` 直接得到完整包长。 - -示例宏: - -```c -#ifndef PACKED -#define PACKED __attribute__((packed)) -#endif -``` - -## 包头 - -包头保留 `magic/cmd/seq/len`,用于快速识别协议包、匹配请求响应、检查 payload 长度。 - -```c -#define BLE_REC_PKT_MAGIC 0xA5 - -typedef struct PACKED { - u8 magic; // BLE_REC_PKT_MAGIC - u8 cmd; // BLE_REC_CMD_xxx - u8 seq; // 发送方独立递增序号 - u16 len; // payload 长度,不包含本包头 -} ble_rec_pkt_hdr_t; -``` - -约定: - -- APP -> Device 和 Device -> APP 两个方向的 `seq` 独立递增。 -- `seq` 为 u8,递增到 0xFF 后回绕到 0x00。 -- 设备响应不回填 APP 请求的 `seq`,而是使用设备侧自己的响应 `seq`。 -- 第一版协议按单事务处理:APP 发出请求后,等待对应 `cmd` 的设备响应,再发下一个普通请求。 -- 录音状态变化时的 `REC_INFO` 和录音停止后紧随的 `FILE_LIST` 是设备主动 Notify,不对应 APP 请求。 -- 文件传输 DATA 使用设备侧连续递增 `seq`,数据顺序和缺口主要由 `file_ofs` 判断。 -- `len` 必须等于 BLE value 长度减 `sizeof(ble_rec_pkt_hdr_t)`。 -- 收到 `magic` 不匹配或 `len` 不匹配的包,直接丢弃。 -- 普通命令建议 APP 使用 3 秒超时;超时后可重新发送当前命令。 - -## MTU 和数据长度 - -BLE ATT Notify/Write 的应用 value 最大长度通常为: - -```text -ble_value_max = att_mtu - 3 -``` - -协议本身不再协商 `max_payload`。设备端从 BLE 栈获取当前 MTU 后自行计算单包最大 data 长度。 - -文件 DATA 包最大数据长度: - -```text -data_max = att_mtu - 3 - sizeof(ble_rec_pkt_hdr_t) - sizeof(action_cmd) - - sizeof(file_ofs) - sizeof(control) - sizeof(sum) - -data_max = att_mtu - 16 -``` - -例:`att_mtu = 247` 时,`data_max = 231`。 - -设备实现时可再取 `min(data_max, 512)`,避免文件系统读缓存过大。 - -## 命令总览 - -| Cmd | 名称 | 说明 | 第一版建议 | -| ---: | --- | --- | --- | -| 0x01 | REC_INFO | 查询 TF 信息和录音状态;录音状态变化时设备主动上报 | 必做 | -| 0x02 | FILE_LIST | 获取完整文件列表 | 必做 | -| 0x03 | FILE_INFO | 查询指定文件信息 | 可选 | -| 0x04 | FILE_TRANSFER | 文件传输,设备连续 Notify | 必做 | -| 0x05 | FILE_DELETE | 删除文件 | 第二步 | -| 0x06 | REC_FORMAT | 格式化 TF 卡 | 第二步 | -| 0x07 | RTC_SYNC | APP 同步设备 RTC 时间 | 必做 | - -说明: - -- `FILE_INFO` 不是首版必需,因为 `FILE_LIST` 已返回文件大小和时间;保留它是为了 APP 删除/下载前单独刷新文件状态。 -- 删除和格式化属于危险操作,建议等列表和传输稳定后再接。 - -## 状态码 - -响应结构体中的 `status` 使用以下取值。 - -```c -enum { - BLE_REC_ST_OK = 0x00, - BLE_REC_ST_PARAM_ERR = 0x01, - BLE_REC_ST_BUSY = 0x02, - BLE_REC_ST_NO_CARD = 0x03, - BLE_REC_ST_FS_ERR = 0x04, - BLE_REC_ST_FILE_NOT_FOUND = 0x05, - BLE_REC_ST_ACCESS_DENIED = 0x06, - BLE_REC_ST_UNSUPPORTED = 0x07, - BLE_REC_ST_NO_SPACE = 0x08, - BLE_REC_ST_CANCELLED = 0x09, -}; -``` - -## 0x01 REC_INFO - -查询 TF 卡信息和录音状态。容量单位为 KB;录音开始、停止时,设备也使用此响应结构主动 Notify。 - -```c -#define BLE_REC_CMD_INFO 0x01 - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_INFO, len = 0 -} ble_rec_info_req_t; - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_INFO - u8 status; // BLE_REC_ST_xxx - u8 fs_type; // 1:FAT12 / 2:FAT16 / 3:FAT32 / 4:exFAT - u32 total_kb; // TF 总容量,单位 KB - u32 used_kb; // 已使用容量,单位 KB - u8 rec_state; // 0:已停止 / 1:录音中 -} ble_rec_info_rsp_t; -``` - -`u32` KB 单位最大可表示约 4TB,足够覆盖当前 128MB TF 卡和后续常见容量。 - -`used_kb` 建议按 `total_kb - free_kb` 计算。如果当前文件系统接口暂时无法快速获取剩余空间,可以后续补实现,但协议字段保持不变。 - -`rec_state` 始终有效。如果 `status != BLE_REC_ST_OK`,APP 仍可更新录音状态,其余信息字段按 0 处理。 - -录音状态变化时,设备主动发送 `REC_INFO`,`status = BLE_REC_ST_OK`。其中容量信息取最近一次成功查询的结果,APP 应以 `rec_state` 为主要关注字段。录音停止状态发送成功后,设备主动发送完整 `FILE_LIST`,用于刷新新生成的录音文件。 - -## 0x02 FILE_LIST - -获取 `\REC\` 目录下的完整文件列表。APP 只发一次请求,设备固定返回所有文件条目;如果一包放不下,设备连续 Notify 多个 FILE_LIST 响应包,直到 `eof = 1`。 - -文件顺序由 FAT 目录项扫描顺序决定,不保证按文件名或时间排序。APP 如需排序,建议本地排序。 - -```c -#define BLE_REC_CMD_FILE_LIST 0x02 - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_FILE_LIST, len = 0 -} ble_rec_file_list_req_t; - -typedef struct PACKED { - u32 size; // 文件大小 - u32 ftime; // FAT 时间,格式同 fs_get_ftime() - u8 name_len; // name[] 总长度,包含结尾 '\0' - u8 name[]; // 文件名,变长,以 '\0' 结尾 -} ble_rec_file_item_t; - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_FILE_LIST - u8 status; // BLE_REC_ST_xxx - u8 item_count; // 本包 item 数量 - u8 eof; // 1: 所有文件列表返回结束 - u8 items[]; // ble_rec_file_item_t 数组,逐项变长解析 -} ble_rec_file_list_rsp_t; -``` - -建议: - -- 默认固定扫描 `\REC\` 目录,过滤隐藏/系统文件。 -- 如果 `\REC\` 目录不存在,返回 `status = BLE_REC_ST_OK`、`item_count = 0`、`eof = 1`。 -- 如果 TF 卡不存在,返回 `status = BLE_REC_ST_NO_CARD`、`item_count = 0`、`eof = 1`。 -- 设备每个响应包尽量填满当前 MTU 可容纳的 item。 -- 单个 `ble_rec_file_item_t` 不跨 BLE 包;如果当前剩余空间放不下完整 item,则放到下一个 FILE_LIST 响应包。 -- 每个 item 的实际长度为 `sizeof(size) + sizeof(ftime) + sizeof(name_len) + name_len`,其中 `name_len` 包含结尾 `\0`。 -- APP 解析时应同时校验 `hdr.len` 和 `item_count`,避免异常包导致越界解析。 -- 如果文件列表需要多包返回,除最后一包外 `eof = 0`,最后一包 `eof = 1`。 -- 删除或新增文件后,APP 重新发送一次 FILE_LIST 获取完整列表。 - -## 0x03 FILE_INFO - -查询指定文件信息。该命令可选,首版可以先不实现。 - -```c -#define BLE_REC_CMD_FILE_INFO 0x03 - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_FILE_INFO - u8 name_len; // name[] 总长度,包含结尾 '\0' - u8 name[]; // \REC\ 目录下的文件名,以 '\0' 结尾 -} ble_rec_file_info_req_t; - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_FILE_INFO - u8 status; // BLE_REC_ST_xxx - u32 size; // 文件大小 - u32 ftime; // FAT 时间 -} ble_rec_file_info_rsp_t; -``` - -如果 `status != BLE_REC_ST_OK`,APP 只处理 `status` 字段,其余字段按 0 处理。 - -## 0x04 FILE_TRANSFER - -文件传输使用一个命令,通过 `action_cmd` 区分配置、数据、取消。 - -核心策略: - -- APP 发一次 SETUP。 -- 设备返回 SETUP_RSP 后连续 Notify DATA。 -- APP 不逐包请求数据。 -- 设备同一时间只允许一个文件传输,DATA/CANCEL 默认作用于当前传输。 -- 如果 APP 发现 offset 缺口,发送 CANCEL,然后重新 SETUP,从期望 offset 继续。 - -### 结构体 - -```c -#define BLE_REC_CMD_FILE_TRANSFER 0x04 - -enum { - BLE_REC_TRANS_SETUP = 0x01, // APP -> Device,设置传输配置 - BLE_REC_TRANS_SETUP_RSP = 0x02, // Device -> APP,配置响应 - BLE_REC_TRANS_DATA = 0x03, // Device -> APP,文件数据 - BLE_REC_TRANS_CANCEL = 0x04, // 双向,取消/中断传输 -}; - -enum { - BLE_REC_DATA_CONTINUE = 0x00, // 继续 - BLE_REC_DATA_END = 0x01, // 本包后传输结束 -}; - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_FILE_TRANSFER - u8 action_cmd; // BLE_REC_TRANS_xxx - union { - /* BLE_REC_TRANS_SETUP: APP -> Device */ - struct PACKED { - u32 start_ofs; // 起始偏移,断点续传时使用 - u8 name_len; // name[] 总长度,包含结尾 '\0' - u8 name[]; // \REC\ 目录下的文件名,以 '\0' 结尾 - } setup; - - /* BLE_REC_TRANS_SETUP_RSP: Device -> APP */ - struct PACKED { - u8 status; // BLE_REC_ST_xxx - u32 file_size; // 文件总大小 - u32 start_ofs; // 实际起始偏移 - u32 ftime; // FAT 时间 - u16 data_len; // 设备实际采用的单包 data 长度 - } setup_rsp; - - /* BLE_REC_TRANS_DATA: Device -> APP */ - struct PACKED { - u32 file_ofs; // 本包 data 在文件中的偏移 - u8 control; // BLE_REC_DATA_CONTINUE / BLE_REC_DATA_END - u16 sum; // 本包校验和,计算时 sum 字段按 0 处理 - u8 data[]; // 文件数据 - } data; - - /* BLE_REC_TRANS_CANCEL: 双向 */ - struct PACKED { - u8 reason; // 0:用户取消 / 1:offset异常 / 2:超时 / 3:设备错误 - } cancel; - }; -} ble_rec_file_transfer_t; -``` - -SETUP_RSP 说明: - -- 如果 `status != BLE_REC_ST_OK`,APP 只处理 `status` 字段,其余字段按 0 处理。 -- 如果 `status == BLE_REC_ST_OK`,APP 保存 `file_size/start_ofs/data_len`,后续 DATA/CANCEL 都默认属于当前传输。 -- 当前传输结束、取消、超时或 BLE 断开后,设备清空当前传输状态;断点续传需要重新 SETUP。 - -DATA 实际数据长度: - -```text -data_actual_len = hdr.len - sizeof(action_cmd) - - sizeof(file_ofs) - - sizeof(control) - - sizeof(sum) - -data_actual_len = hdr.len - 8 -``` - -APP 必须使用 `data_actual_len` 解析 `data[]`,不要使用 SETUP_RSP 里的 `data_len` 作为每包固定长度。最后一包通常会小于 `data_len`。 - -### DATA 校验和 - -`sum` 是一个轻量 sanity check,不用于替代 BLE 链路层 CRC。 - -建议算法: - -```c -u16 sum = 0; -for (i = 0; i < packet_len; i++) { - sum += packet[i]; -} -``` - -校验范围为整个 BLE value,即从 `hdr.magic` 到 `data[]` 最后一个字节。计算时 `sum` 字段两个字节按 0 处理。APP 收到 DATA 后按同样方式计算,结果一致才写入本地文件。 - -如果实测 CPU 开销影响吞吐,可以后续约定 `sum = 0` 表示不启用 DATA 校验和;第一版建议先保留,方便调试。 - -### 设备发送策略 - -- 如果 `\REC\` 目录不存在或目标文件不存在,SETUP_RSP 返回 `BLE_REC_ST_FILE_NOT_FOUND`。 -- SETUP 成功后,设备尽快连续发送 DATA。 -- 能发就发,直到 BLE TX 队列满、文件结束、收到 CANCEL 或文件系统错误。 -- 如果传输过程中发生文件系统错误,设备发送 `BLE_REC_TRANS_CANCEL`,`reason = 3`。 -- BLE TX 队列满时不要忙等,等 notify complete/tx credit 回调后继续发送。 -- 每次从 TF 读取的长度不超过 `data_len`,复用一个静态缓冲。 -- 长文件传输循环中定期喂狗。 -- 最后一包 DATA 的 `control = BLE_REC_DATA_END`。如果文件大小刚好按 data_len 对齐,可以发送一个 0 字节 END 包。 - -### APP 接收策略 - -- 按 `file_ofs` 写入本地文件。 -- 如果收到重复 DATA,可按 offset 去重。 -- 如果 `file_ofs` 不等于期望 offset,发送 CANCEL,然后重新 SETUP,从期望 offset 继续。 -- 如果 APP 超过 5 秒没有收到新的 DATA 或 CANCEL,可认为传输超时,重新 SETUP 从已保存 offset 续传。 - -## 0x05 FILE_DELETE - -删除指定文件。 - -```c -#define BLE_REC_CMD_FILE_DELETE 0x05 -#define BLE_REC_DELETE_CONFIRM 0x44454C21 // "DEL!" - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_FILE_DELETE - u32 confirm; // BLE_REC_DELETE_CONFIRM - u8 name_len; // name[] 总长度,包含结尾 '\0' - u8 name[]; // \REC\ 目录下的文件名,以 '\0' 结尾 -} ble_rec_file_delete_req_t; - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_FILE_DELETE - u8 status; // BLE_REC_ST_xxx -} ble_rec_file_delete_rsp_t; -``` - -安全要求: - -- 录音中返回 `BLE_REC_ST_BUSY`。 -- 文件传输中返回 `BLE_REC_ST_BUSY`,或要求 APP 先 CANCEL。 -- 如果 `\REC\` 目录不存在或目标文件不存在,返回 `BLE_REC_ST_FILE_NOT_FOUND`。 -- APP UI 侧必须二次确认。 - -## 0x06 REC_FORMAT - -格式化 TF 卡。 - -```c -#define BLE_REC_CMD_FORMAT 0x06 -#define BLE_REC_FORMAT_CONFIRM 0x464D5421 // "FMT!" - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_FORMAT - u32 confirm; // BLE_REC_FORMAT_CONFIRM - u8 fs_type; // 0: 自动 -} ble_rec_format_req_t; - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_FORMAT - u8 status; // BLE_REC_ST_xxx -} ble_rec_format_rsp_t; -``` - -安全要求: - -- 录音中返回 `BLE_REC_ST_BUSY`。 -- 文件传输中返回 `BLE_REC_ST_BUSY`。 -- 低电量返回 `BLE_REC_ST_ACCESS_DENIED`。 -- TF 卡不存在返回 `BLE_REC_ST_NO_CARD`。 -- APP UI 侧必须二次确认。 - -## 0x07 RTC_SYNC - -APP 将本地时间同步到设备 RTC。设备后续创建录音文件时,使用 RTC 时间生成 FAT 创建时间。 - -```c -#define BLE_REC_CMD_RTC_SYNC 0x07 - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_RTC_SYNC - u16 year; // 1980~2106 - u8 month; // 1~12 - u8 day; // 1~31,设备按年月校验 - u8 hour; // 0~23 - u8 minute; // 0~59 - u8 second; // 0~59 -} ble_rec_rtc_sync_req_t; - -typedef struct PACKED { - ble_rec_pkt_hdr_t hdr; // cmd = BLE_REC_CMD_RTC_SYNC - u8 status; // BLE_REC_ST_xxx -} ble_rec_rtc_sync_rsp_t; -``` - -说明: -- 时间按设备本地时间理解,不做时区字段协商。 -- 建议 APP 在 BLE 连接成功后主动同步一次 RTC,再查询/下载文件。 -- 如果设备 RTC 未同步或时间无效,录音文件创建时间会回退到旧的递增时间策略,避免写入非法 FAT 时间。 - -## 典型流程 - -### 枚举文件 - -1. APP 使能 CMD_TX Notify。 -2. APP -> `RTC_SYNC`。 -3. APP -> `REC_INFO`。 -4. APP -> `FILE_LIST`。 -5. 设备连续返回 FILE_LIST 响应包,APP 收集 item,直到 `eof = 1`。 - -### 下载文件,最高速度模式 - -1. APP -> `FILE_TRANSFER / SETUP`,`start_ofs = 0`。 -2. 设备 -> `FILE_TRANSFER / SETUP_RSP`。 -3. 设备连续 Notify `FILE_TRANSFER / DATA`。 -4. APP 按 offset 写文件。 -5. APP 收到 `control = BLE_REC_DATA_END` 后,确认本地文件大小等于 `file_size`。 - -### 断点续传 - -1. APP 本地已有 `saved_offset`。 -2. APP -> `FILE_TRANSFER / SETUP`,`start_ofs = saved_offset`。 -3. 设备从该 offset 开始连续发送 DATA。 - -### 删除文件 - -1. APP UI 二次确认。 -2. APP -> `FILE_DELETE(confirm = "DEL!")`。 -3. 设备返回 OK 后,APP 重新 `FILE_LIST`。 - -### 格式化 - -1. APP UI 二次确认。 -2. APP -> `REC_FORMAT(confirm = "FMT!")`。 -3. 成功后 APP 重新 `REC_INFO` 和 `FILE_LIST`。 - -## 第一版实现建议 - -第一版建议只实现: - -- `REC_INFO` -- `RTC_SYNC` -- `FILE_LIST` -- `FILE_TRANSFER` - -之后再补: - -- `FILE_INFO` -- `FILE_DELETE` -- `REC_FORMAT` - -这样可以先把 APP 浏览和高速下载主链路跑通,再加危险操作。 diff --git a/apps/client/docs/recorder_protocol.md b/apps/client/local_plugins/recorder_holder/recorder_protocol.md similarity index 100% rename from apps/client/docs/recorder_protocol.md rename to apps/client/local_plugins/recorder_holder/recorder_protocol.md diff --git a/apps/client/local_plugins/recorder_holder/sdk/lib/echomeet_device_sdk.dart b/apps/client/local_plugins/recorder_holder/sdk/lib/echomeet_device_sdk.dart index 728cf7af..ec5207d5 100644 --- a/apps/client/local_plugins/recorder_holder/sdk/lib/echomeet_device_sdk.dart +++ b/apps/client/local_plugins/recorder_holder/sdk/lib/echomeet_device_sdk.dart @@ -11,3 +11,20 @@ library echomeet_device_sdk; export 'src/models.dart'; export 'src/client.dart'; + +// 通道 B(TF 卡文件)的协议类型:文件列表项、状态码、下载结果等。 +// 业务层拿 EchoMeetDeviceSdk.instance.recorder 用它们。 +export 'package:recorder_holder/recorder_holder_rec.dart' + show + RecClient, + RecCancelToken, + RecDownloadResult, + RecException, + RecFileInfo, + RecFileItem, + RecFileSink, + FileRecSink, + RecFsType, + RecInfo, + RecStatus, + MemoryRecFileSink; diff --git a/apps/client/local_plugins/recorder_holder/sdk/lib/src/client.dart b/apps/client/local_plugins/recorder_holder/sdk/lib/src/client.dart index 18ade3cf..7ef3c0ce 100644 --- a/apps/client/local_plugins/recorder_holder/sdk/lib/src/client.dart +++ b/apps/client/local_plugins/recorder_holder/sdk/lib/src/client.dart @@ -3,6 +3,7 @@ import 'dart:io' show Platform; import 'package:flutter/foundation.dart'; import 'package:recorder_holder/recorder_holder.dart'; +import 'package:recorder_holder/recorder_holder_rec.dart'; import 'models.dart'; @@ -11,8 +12,8 @@ import 'models.dart'; /// 封装底层 [RecorderHolder],对外只暴露:搜索、连接、录音、状态监听。 /// **不包含** OSS 上传、账号、会议等业务。 /// -/// 支持设备(蓝牙名): -/// - `Echomeet`(录音支架) +/// 支持设备(蓝牙名前缀): +/// - `EaiRec`(AI 手机支架,带 TF 卡存储) /// - `Pad Note`(UI 名 AI Pencil) class EchoMeetDeviceSdk { EchoMeetDeviceSdk._(); @@ -21,8 +22,45 @@ class EchoMeetDeviceSdk { final RecorderHolder _plugin = RecorderHolder(); - /// 默认只保留 EchoMeet 产品线广播名。 - static const List defaultNameFilters = ['Echomeet', 'Pad Note']; + /// 通道 B(TF 卡文件)客户端。 + /// + /// 协议状态机在 recorder_holder 的 `lib/src/rec/` 里,这里只负责在连接建立/ + /// 断开时挂上和摘掉。设备没有 TF 卡能力时 [recChannelReady] 为 false, + /// 调用会以超时告终——所以用之前先看那个标志。 + late final RecNativeTransport _recTransport = RecNativeTransport(plugin: _plugin); + late final RecClient recorder = RecClient( + transport: _recTransport, + log: (m) => debugPrint('[EaiRec/通道B] $m'), + ); + + bool _recReady = false; + + /// 通道 B 是否可用(已连接且设备提供了 0xFDA5 服务)。 + bool get recChannelReady => _recReady; + + /// 默认保留的广播名**前缀**(大小写不敏感)。 + /// + /// ⚠️ **`EaiRec` 是按产品名推的,尚未在真机上确认**(见 EaiRec_protocol.md + /// 的待确认项 Q1)。名字对不上的表现是**扫描页一台设备都不出现**,而不会 + /// 报任何错——真机第一次扫不到时先查这里,别去怀疑蓝牙权限。 + /// + /// 改成前缀匹配而不是原来的全等:固件常在名字后面挂序列号后缀 + /// (`EaiRec-1A2B`),全等匹配会把这类设备全滤掉。 + /// 扫描保留的广播名**前缀**(大小写不敏感,`startsWith` 匹配)。 + /// + /// ★ **这是切换设备名的唯一入口**(协议 §2.1:App 不做 Service UUID 过滤, + /// 只按设备名前缀筛)。名字对不上的表现是**扫描页一台设备都不出现,且不报任何错**。 + /// + /// 2026-09-10 现状:**在用的支架固件广播名是 `Echomeet`**(用户实测)。 + /// `EaiRec` 是产品改名后的目标名,固件还没刷,先都留着: + /// - 设备刷成 `EaiRec` 之后,这里不用改也能扫到(两个前缀都在); + /// - 真要只认新名,把 `Echomeet` 从列表里删掉即可。 + static const List defaultNameFilters = [ + 'Echomeet', // ← 当前在用的固件广播名 + 'EaiRec', // ← 改名后的目标名 + 'EAIMAR', + 'Pad Note', + ]; List _nameFilters = List.from(defaultNameFilters); @@ -98,8 +136,15 @@ class EchoMeetDeviceSdk { if (!_connectionController.isClosed) { _connectionController.add(_connectionState); } + if (_connectionState == EchoMeetConnectionState.connected) { + // 服务发现是异步的,连接状态先到、0xFDA5 特征后到, + // 所以这里只是探一次,真正的判定交给 ensureRecChannel()。 + unawaited(ensureRecChannel()); + } if (_connectionState == EchoMeetConnectionState.disconnected || _connectionState == EchoMeetConnectionState.error) { + _recReady = false; + unawaited(recorder.detach()); _emitRecording(const EchoMeetRecordingState()); } }); @@ -169,6 +214,8 @@ class EchoMeetDeviceSdk { _recSub = null; _infoSub = null; _audioSub = null; + _recReady = false; + await recorder.detach(); _bound = false; } @@ -198,10 +245,19 @@ class EchoMeetDeviceSdk { .toList(); } - /// 连接设备。 + /// 连接设备。协议 §8.1 第 3 步:**扫描之后要真的发起 GATT 连接**。 /// - /// - iOS:`startDeviceAssociation` - /// - Android:`registerBackgroundScan` + /// - iOS:`startDeviceAssociation` → 原生 `connectToDevice(uuid:)`,本身就是直连。 + /// - Android:`registerBackgroundScan` **只是注册系统后台扫描的 PendingIntent** + /// (`savePairedMacAddress` + `ScanFilter(mac)` + `SCAN_MODE_LOW_POWER`), + /// 它一次 `connectGatt` 都不发;真正连接要等系统扫到广播 → `BleWakeReceiver` + /// (还带 10s 去抖)→ 拉起前台服务才发生。 + /// + /// ⚠️ 以前这里到此为止就 `return true`,于是「点连接」立刻成功、 + /// `waitConnected()` 干等 25 秒超时 —— 表现就是**扫得到但永远连不上**。 + /// 现在注册完后台回连后**立刻再直连一次**(原生早就暴露了 `connectToDevice` + /// → `BleService.connect(mac)` → `device.connectGatt`,只是 Dart 侧没调)。 + /// 两者不冲突:后台注册管「设备下次靠近自动连」,直连管「用户现在就要连」。 Future connect({ required String name, required String address, @@ -223,7 +279,13 @@ class EchoMeetDeviceSdk { macAddress: address, ); } else { - ok = await _plugin.registerBackgroundScan(macAddress: address); + // 后台回连注册失败不阻断本次连接:它只影响「下次设备靠近自动连」 + final registered = await _plugin.registerBackgroundScan(macAddress: address); + if (!registered) { + // ignore: avoid_print + print('[EaiRec] 后台扫连注册失败,仅影响自动回连,继续直连'); + } + ok = await _plugin.connectToDevice(address); } if (!ok) { @@ -235,6 +297,17 @@ class EchoMeetDeviceSdk { return ok; } + /// 确认通道 B 是否就绪,就绪就挂上收包。 + /// + /// 可以重复调用:连接状态回调、以及业务层第一次要用文件功能时都会调一次。 + /// 服务发现比连接状态晚到,只在连接回调里探一次会漏。 + Future ensureRecChannel() async { + final ready = await _recTransport.refreshReady(); + _recReady = ready; + if (ready) recorder.attach(); + return ready; + } + Future connectDevice(EchoMeetScannedDevice device) { return connect(name: device.name, address: device.address); } @@ -320,7 +393,9 @@ class EchoMeetDeviceSdk { bool _matchesFilter(String name) { if (_nameFilters.isEmpty) return true; - return _nameFilters.any((f) => f == name); + final n = name.trim().toLowerCase(); + if (n.isEmpty) return false; + return _nameFilters.any((f) => n.startsWith(f.toLowerCase())); } void _emitRecording(EchoMeetRecordingState state) { diff --git a/apps/client/local_plugins/recorder_holder/test/rec/rec_client_test.dart b/apps/client/local_plugins/recorder_holder/test/rec/rec_client_test.dart new file mode 100644 index 00000000..9bc65f4c --- /dev/null +++ b/apps/client/local_plugins/recorder_holder/test/rec/rec_client_test.dart @@ -0,0 +1,458 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:recorder_holder/recorder_holder_rec.dart'; + +import 'rec_frame_test.dart' show buildDataPacket; + +/// 可编程的假设备:把 App 发来的帧记下来,并按剧本回包。 +class FakeDevice implements RecTransport { + final _ctrl = StreamController.broadcast(); + final List sent = []; + + /// 收到一帧时的回调,用来编排设备行为。 + void Function(RecFrame frame)? onFrame; + + @override + Stream get incoming => _ctrl.stream; + + @override + bool get isReady => true; + + @override + Future send(List data) async { + final bytes = Uint8List.fromList(data); + sent.add(bytes); + final f = RecFrame.tryParse(bytes); + if (f != null) onFrame?.call(f); + } + + void push(List bytes) => _ctrl.add(Uint8List.fromList(bytes)); + + /// 设备侧回一个「只有 status 一个字节」的响应。 + void reply(int cmd, int status) => + push(RecFrame.build(cmd: cmd, seq: 0, payload: [status])); + + void pushSetupRsp({ + required int fileSize, + required int startOfs, + int status = 0, + int dataLen = 231, + }) { + push(RecFrame.build( + cmd: RecCmd.fileTransfer, + seq: 0, + payload: [ + RecTransferAction.setupRsp, + status, + ...RecBytes.u32le(fileSize), + ...RecBytes.u32le(startOfs), + ...RecBytes.u32le(0), + ...RecBytes.u16le(dataLen), + ], + )); + } + + void pushData({ + required int fileOfs, + required List data, + bool end = false, + int? forceSum, + }) { + push(buildDataPacket( + seq: 0, + fileOfs: fileOfs, + control: end ? RecDataControl.end : RecDataControl.cont, + data: data, + forceSum: forceSum, + )); + } + + Future dispose() => _ctrl.close(); +} + +/// 取出最后一次发出去的帧 +RecFrame lastFrame(FakeDevice d) => RecFrame.tryParse(d.sent.last)!; + +void main() { + late FakeDevice dev; + late RecClient client; + + setUp(() { + dev = FakeDevice(); + client = RecClient( + transport: dev, + // 协议值是 3s / 5s,单测里调小,否则每个超时用例都要真等 + commandTimeout: const Duration(milliseconds: 200), + idleTimeout: const Duration(milliseconds: 300), + ); + client.attach(); + }); + + tearDown(() async { + await client.dispose(); + await dev.dispose(); + }); + + group('RTC_SYNC', () { + test('按设备本地时间下发,不转 UTC', () async { + dev.onFrame = (f) => dev.reply(RecCmd.rtcSync, RecStatus.ok.code); + await client.syncRtc(DateTime(2026, 9, 8, 13, 45, 30)); + + final f = RecFrame.tryParse(dev.sent.single)!; + expect(f.cmd, RecCmd.rtcSync); + expect(RecBytes.readU16le(f.payload, 0), 2026); + expect(f.payload[2], 9); + expect(f.payload[3], 8); + expect(f.payload[4], 13); + expect(f.payload[5], 45); + expect(f.payload[6], 30); + }); + + test('设备回非 OK 时抛出并带上状态码', () async { + dev.onFrame = (f) => dev.reply(RecCmd.rtcSync, RecStatus.paramErr.code); + expect( + () => client.syncRtc(DateTime(2026, 1, 1)), + throwsA(isA() + .having((e) => e.status, 'status', RecStatus.paramErr)), + ); + }); + }); + + group('单事务与超时', () { + test('无响应时超时报错', () async { + await expectLater(client.queryInfo(), throwsA(isA())); + }); + + test('超时后事务槽释放,下一条命令还能发', () async { + await expectLater(client.queryInfo(), throwsA(isA())); + dev.onFrame = (f) => dev.reply(RecCmd.rtcSync, RecStatus.ok.code); + await client.syncRtc(DateTime(2026, 1, 1)); + }); + + test('协议规定的超时值没有被改动', () { + expect(RecTiming.commandTimeout, const Duration(seconds: 3)); + expect(RecTiming.transferIdleTimeout, const Duration(seconds: 5)); + }); + }); + + group('FILE_LIST 多包累积', () { + test('收齐 eof=1 才返回,且顺序保持', () async { + List item(String name) { + final n = RecFileName.encode(name); + return [...RecBytes.u32le(1), ...RecBytes.u32le(0), n.length, ...n]; + } + + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileList) return; + dev.push(RecFrame.build( + cmd: RecCmd.fileList, + seq: 0, + payload: [RecStatus.ok.code, 1, 0, ...item('A.OGG')], + )); + dev.push(RecFrame.build( + cmd: RecCmd.fileList, + seq: 1, + payload: [RecStatus.ok.code, 1, 0, ...item('B.OGG')], + )); + dev.push(RecFrame.build( + cmd: RecCmd.fileList, + seq: 2, + payload: [RecStatus.ok.code, 1, 1, ...item('C.OGG')], + )); + }; + + final list = await client.listFiles(); + expect(list.map((e) => e.name), ['A.OGG', 'B.OGG', 'C.OGG']); + }); + + test('无人等待时的 FILE_LIST 走「设备主动推」流', () async { + final n = RecFileName.encode('Z.OGG'); + final pushed = client.onFileListPushed.first; + dev.push(RecFrame.build( + cmd: RecCmd.fileList, + seq: 0, + payload: [ + RecStatus.ok.code, + 1, + 1, + ...RecBytes.u32le(5), + ...RecBytes.u32le(0), + n.length, + ...n, + ], + )); + expect((await pushed).single.name, 'Z.OGG'); + }); + }); + + group('REC_INFO 主动上报', () { + test('录音状态变化推到 onRecInfo', () async { + final first = client.onRecInfo.first; + dev.push(RecFrame.build( + cmd: RecCmd.recInfo, + seq: 0, + payload: [ + RecStatus.ok.code, + RecFsType.fat32, + ...RecBytes.u32le(100), + ...RecBytes.u32le(10), + 1, + ], + )); + expect((await first).recording, isTrue); + }); + }); + + group('下载', () { + test('顺序收包直到 END', () async { + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileTransfer) return; + if (f.payload[0] != RecTransferAction.setup) return; + dev.pushSetupRsp(fileSize: 6, startOfs: 0); + dev.pushData(fileOfs: 0, data: [1, 2, 3]); + dev.pushData(fileOfs: 3, data: [4, 5, 6], end: true); + }; + + final sink = MemoryRecFileSink(); + final r = await client.download(name: 'MIC0016.OGG', sink: sink); + expect(r.complete, isTrue); + expect(r.resumes, 0); + expect(sink.bytes, [1, 2, 3, 4, 5, 6]); + }); + + test('重复包按 offset 去重,不会写两遍', () async { + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileTransfer) return; + if (f.payload[0] != RecTransferAction.setup) return; + dev.pushSetupRsp(fileSize: 4, startOfs: 0); + dev.pushData(fileOfs: 0, data: [1, 2]); + dev.pushData(fileOfs: 0, data: [1, 2]); // 重复 + dev.pushData(fileOfs: 2, data: [3, 4], end: true); + }; + + final sink = MemoryRecFileSink(); + await client.download(name: 'A.OGG', sink: sink); + expect(sink.bytes, [1, 2, 3, 4]); + }); + + test('部分重叠的包只接尾巴', () async { + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileTransfer) return; + if (f.payload[0] != RecTransferAction.setup) return; + dev.pushSetupRsp(fileSize: 4, startOfs: 0); + dev.pushData(fileOfs: 0, data: [1, 2]); + dev.pushData(fileOfs: 1, data: [2, 3, 4], end: true); // 前 1 字节是旧的 + }; + + final sink = MemoryRecFileSink(); + await client.download(name: 'A.OGG', sink: sink); + expect(sink.bytes, [1, 2, 3, 4]); + }); + + test('offset 缺口触发 CANCEL + 从期望 offset 重新 SETUP', () async { + var setups = 0; + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileTransfer) return; + if (f.payload[0] != RecTransferAction.setup) return; + setups++; + final startOfs = RecBytes.readU32le(f.payload, 1); + if (setups == 1) { + dev.pushSetupRsp(fileSize: 4, startOfs: 0); + dev.pushData(fileOfs: 0, data: [1, 2]); + dev.pushData(fileOfs: 99, data: [9]); // 缺口 + } else { + expect(startOfs, 2, reason: '必须从本地已有的长度续,不能从 0 重来'); + dev.pushSetupRsp(fileSize: 4, startOfs: startOfs); + dev.pushData(fileOfs: 2, data: [3, 4], end: true); + } + }; + + final sink = MemoryRecFileSink(); + final r = await client.download(name: 'A.OGG', sink: sink); + expect(setups, 2); + expect(r.resumes, 1); + expect(sink.bytes, [1, 2, 3, 4]); + + final cancels = dev.sent + .map(RecFrame.tryParse) + .where((f) => + f != null && + f.cmd == RecCmd.fileTransfer && + f.payload.isNotEmpty && + f.payload[0] == RecTransferAction.cancel) + .length; + expect(cancels, 1, reason: '重新 SETUP 之前必须先 CANCEL'); + }); + + test('传入已有内容的 sink 即断点续传', () async { + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileTransfer) return; + if (f.payload[0] != RecTransferAction.setup) return; + expect(RecBytes.readU32le(f.payload, 1), 2); + dev.pushSetupRsp(fileSize: 4, startOfs: 2); + dev.pushData(fileOfs: 2, data: [3, 4], end: true); + }; + + final sink = MemoryRecFileSink(); + await sink.append([1, 2]); + final r = await client.download(name: 'A.OGG', sink: sink); + expect(sink.bytes, [1, 2, 3, 4]); + expect(r.complete, isTrue); + }); + + test('校验和不符的包被丢弃,不推进 offset', () async { + var setups = 0; + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileTransfer) return; + if (f.payload[0] != RecTransferAction.setup) return; + setups++; + if (setups == 1) { + dev.pushSetupRsp(fileSize: 2, startOfs: 0); + dev.pushData(fileOfs: 0, data: [1, 2], end: true, forceSum: 0xDEAD); + // 坏包被丢后靠重传补上 + dev.pushData(fileOfs: 0, data: [1, 2], end: true); + } + }; + + final sink = MemoryRecFileSink(); + await client.download(name: 'A.OGG', sink: sink); + expect(sink.bytes, [1, 2]); + }); + + test('SETUP 返回 FILE_NOT_FOUND 时报错并带状态码', () async { + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileTransfer) return; + if (f.payload[0] != RecTransferAction.setup) return; + dev.pushSetupRsp( + fileSize: 0, startOfs: 0, status: RecStatus.fileNotFound.code); + }; + expect( + () => client.download(name: 'NOPE.OGG', sink: MemoryRecFileSink()), + throwsA(isA() + .having((e) => e.status, 'status', RecStatus.fileNotFound)), + ); + }); + + test('END 到了但大小不符 → 续传而不是当成功', () async { + var setups = 0; + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileTransfer) return; + if (f.payload[0] != RecTransferAction.setup) return; + setups++; + if (setups == 1) { + dev.pushSetupRsp(fileSize: 4, startOfs: 0); + dev.pushData(fileOfs: 0, data: [1, 2], end: true); // 谎报结束 + } else { + dev.pushSetupRsp(fileSize: 4, startOfs: 2); + dev.pushData(fileOfs: 2, data: [3, 4], end: true); + } + }; + final sink = MemoryRecFileSink(); + final r = await client.download(name: 'A.OGG', sink: sink); + expect(setups, 2); + expect(sink.bytes, [1, 2, 3, 4]); + expect(r.complete, isTrue); + }); + + test('设备发 CANCEL 时下载失败', () async { + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileTransfer) return; + if (f.payload[0] != RecTransferAction.setup) return; + dev.pushSetupRsp(fileSize: 4, startOfs: 0); + dev.push(RecFrame.build( + cmd: RecCmd.fileTransfer, + seq: 0, + payload: [RecTransferAction.cancel, RecCancelReason.deviceError], + )); + }; + expect( + () => client.download(name: 'A.OGG', sink: MemoryRecFileSink()), + throwsA(isA()), + ); + }); + }); + + group('互斥闸', () { + test('传输期间拒绝其它命令', () async { + final gate = Completer(); + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileTransfer) return; + if (f.payload[0] != RecTransferAction.setup) return; + dev.pushSetupRsp(fileSize: 4, startOfs: 0); + dev.pushData(fileOfs: 0, data: [1, 2]); + gate.complete(); // 传输已开始、尚未结束 + }; + + final dl = client.download(name: 'A.OGG', sink: MemoryRecFileSink()); + await gate.future; + + await expectLater( + client.queryInfo(), + throwsA(isA() + .having((e) => e.status, 'status', RecStatus.busy)), + ); + + dev.pushData(fileOfs: 2, data: [3, 4], end: true); + await dl; + }); + + test('已有传输时再发起下载直接拒绝', () async { + final gate = Completer(); + dev.onFrame = (f) { + if (f.cmd != RecCmd.fileTransfer) return; + if (f.payload[0] != RecTransferAction.setup) return; + dev.pushSetupRsp(fileSize: 4, startOfs: 0); + dev.pushData(fileOfs: 0, data: [1, 2]); + if (!gate.isCompleted) gate.complete(); + }; + final dl = client.download(name: 'A.OGG', sink: MemoryRecFileSink()); + await gate.future; + + await expectLater( + client.download(name: 'B.OGG', sink: MemoryRecFileSink()), + throwsA(isA() + .having((e) => e.status, 'status', RecStatus.busy)), + ); + + dev.pushData(fileOfs: 2, data: [3, 4], end: true); + await dl; + }); + }); + + group('危险操作', () { + test('删除带 "DEL!" 魔数', () async { + dev.onFrame = (f) => dev.reply(RecCmd.fileDelete, RecStatus.ok.code); + await client.deleteFile('MIC0016.OGG'); + final f = RecFrame.tryParse(dev.sent.single)!; + expect(RecBytes.readU32le(f.payload, 0), RecConfirm.delete); + expect(RecConfirm.delete, 0x44454C21); + }); + + test('格式化带 "FMT!" 魔数', () async { + dev.onFrame = (f) => dev.reply(RecCmd.format, RecStatus.ok.code); + await client.format(); + final f = RecFrame.tryParse(dev.sent.single)!; + expect(RecBytes.readU32le(f.payload, 0), RecConfirm.format); + expect(RecConfirm.format, 0x464D5421); + }); + + test('录音中删除返回 BUSY', () async { + dev.onFrame = (f) => dev.reply(RecCmd.fileDelete, RecStatus.busy.code); + expect( + () => client.deleteFile('A.OGG'), + throwsA(isA() + .having((e) => e.status, 'status', RecStatus.busy)), + ); + }); + + test('非法文件名在本地就被挡下,不发包', () async { + expect( + () => client.deleteFile('../secret'), + throwsA(isA()), + ); + expect(dev.sent, isEmpty); + }); + }); +} diff --git a/apps/client/local_plugins/recorder_holder/test/rec/rec_frame_test.dart b/apps/client/local_plugins/recorder_holder/test/rec/rec_frame_test.dart new file mode 100644 index 00000000..124a193f --- /dev/null +++ b/apps/client/local_plugins/recorder_holder/test/rec/rec_frame_test.dart @@ -0,0 +1,248 @@ +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:recorder_holder/recorder_holder_rec.dart'; + +/// 按协议文档 §5.9 组一个 DATA 包(含正确校验和)。 +Uint8List buildDataPacket({ + required int seq, + required int fileOfs, + required int control, + required List data, + int? forceSum, +}) { + final body = [ + RecTransferAction.data, + ...RecBytes.u32le(fileOfs), + control, + 0, 0, // sum 占位 + ...data, + ]; + final packet = RecFrame.build(cmd: RecCmd.fileTransfer, seq: seq, payload: body); + final sum = forceSum ?? RecChecksum.compute(packet); + packet[RecChecksum.sumOffsetInPacket] = sum & 0xFF; + packet[RecChecksum.sumOffsetInPacket + 1] = (sum >> 8) & 0xFF; + return packet; +} + +void main() { + group('包头', () { + test('组包与解析对称', () { + final f = RecFrame.build(cmd: RecCmd.recInfo, seq: 7, payload: [1, 2, 3]); + expect(f[0], 0xA5); + expect(f[1], RecCmd.recInfo); + expect(f[2], 7); + // len 是 u16 小端 + expect(f[3], 3); + expect(f[4], 0); + + final p = RecFrame.tryParse(f)!; + expect(p.cmd, RecCmd.recInfo); + expect(p.seq, 7); + expect(p.payload, [1, 2, 3]); + }); + + test('magic 不符直接丢弃', () { + final f = RecFrame.build(cmd: 1, seq: 0, payload: const []); + f[0] = 0xA6; + expect(RecFrame.tryParse(f), isNull); + }); + + test('len 与实际长度不符直接丢弃', () { + final f = RecFrame.build(cmd: 1, seq: 0, payload: [1, 2, 3]); + // 声称 payload 有 4 字节,实际只有 3 + f[3] = 4; + expect(RecFrame.tryParse(f), isNull); + }); + + test('短于包头的包直接丢弃', () { + expect(RecFrame.tryParse([0xA5, 0x01]), isNull); + }); + + test('seq 到 0xFF 回绕', () { + final f = RecFrame.build(cmd: 1, seq: 0xFF, payload: const []); + expect(RecFrame.tryParse(f)!.seq, 0xFF); + }); + }); + + group('DATA 校验和', () { + test('覆盖整包且 sum 字段按 0 参与计算', () { + final pkt = buildDataPacket(seq: 1, fileOfs: 0, control: 0, data: [9, 9, 9]); + final parsed = RecFrame.tryParse(pkt)!; + final d = RecTransferData.parse(parsed.payload.sublist(1), parsed.raw)!; + expect(d.checksumOk, isTrue); + expect(d.data, [9, 9, 9]); + expect(d.fileOfs, 0); + }); + + test('只算 data 段的实现会算错(守住最容易写反的那一处)', () { + final pkt = buildDataPacket(seq: 1, fileOfs: 0, control: 0, data: [9, 9, 9]); + const dataOnlySum = 9 + 9 + 9; + expect(RecChecksum.compute(pkt), isNot(dataOnlySum)); + }); + + test('校验和不符时 checksumOk=false 而不是解析失败', () { + final pkt = + buildDataPacket(seq: 1, fileOfs: 0, control: 0, data: [1], forceSum: 0x1234); + final parsed = RecFrame.tryParse(pkt)!; + final d = RecTransferData.parse(parsed.payload.sublist(1), parsed.raw); + expect(d, isNotNull); + expect(d!.checksumOk, isFalse); + }); + + test('data 实际长度按 hdr.len-8 得出,不用 SETUP_RSP.data_len', () { + final pkt = buildDataPacket( + seq: 1, fileOfs: 100, control: RecDataControl.end, data: [1, 2]); + final parsed = RecFrame.tryParse(pkt)!; + // payload = action(1)+ofs(4)+control(1)+sum(2)+data(2) = 10 + expect(parsed.payload.length, 10); + final d = RecTransferData.parse(parsed.payload.sublist(1), parsed.raw)!; + expect(d.data.length, 2); + expect(d.isEnd, isTrue); + }); + }); + + group('文件名校验', () { + test('必须以 \\0 结尾', () { + expect(RecFileName.isValidRaw('MIC0016.OGG'.codeUnits), isFalse); + expect(RecFileName.isValidRaw([...'MIC0016.OGG'.codeUnits, 0]), isTrue); + }); + + test('name_len 含结尾 \\0', () { + expect(RecFileName.encode('MIC0016.OGG').length, 12); + }); + + test('拒绝路径分隔符(防止写到 \\REC\\ 之外)', () { + expect(RecFileName.isValidRaw([...'../x'.codeUnits, 0]), isFalse); + expect(RecFileName.isValidRaw([...r'a\b'.codeUnits, 0]), isFalse); + expect(RecFileName.isValid('a/b'), isFalse); + expect(RecFileName.isValid(r'a\b'), isFalse); + }); + + test('最小长度为 2', () { + expect(RecFileName.isValidRaw([0]), isFalse); + expect(RecFileName.isValidRaw([65, 0]), isTrue); + }); + }); + + group('REC_INFO', () { + test('正常解析', () { + final p = [ + RecStatus.ok.code, + RecFsType.fat32, + ...RecBytes.u32le(124928), + ...RecBytes.u32le(1024), + 1, + ]; + final info = RecInfo.parse(p)!; + expect(info.status, RecStatus.ok); + expect(info.fsType, RecFsType.fat32); + expect(info.totalKb, 124928); + expect(info.usedKb, 1024); + expect(info.recording, isTrue); + expect(info.freeKb, 124928 - 1024); + }); + + test('status 非 OK 时其余字段归零,但 rec_state 仍然采信', () { + final p = [ + RecStatus.noCard.code, + RecFsType.fat32, + ...RecBytes.u32le(999), + ...RecBytes.u32le(999), + 1, + ]; + final info = RecInfo.parse(p)!; + expect(info.status, RecStatus.noCard); + expect(info.totalKb, 0); + expect(info.recording, isTrue, reason: 'rec_state 协议明确始终有效'); + expect(info.hasCard, isFalse); + }); + }); + + group('FILE_LIST', () { + List item(String name, int size, int ftime) { + final n = RecFileName.encode(name); + return [...RecBytes.u32le(size), ...RecBytes.u32le(ftime), n.length, ...n]; + } + + test('多条变长 item 逐项解析', () { + final p = [ + RecStatus.ok.code, + 2, + 1, + ...item('MIC0016.OGG', 1234, 0), + ...item('MIC0017.OGG', 5678, 0), + ]; + final page = RecFileListPage.parse(p)!; + expect(page.eof, isTrue); + expect(page.items.length, 2); + expect(page.items[0].name, 'MIC0016.OGG'); + expect(page.items[0].size, 1234); + expect(page.items[1].name, 'MIC0017.OGG'); + }); + + test('item_count 与实际内容不符时整包判非法', () { + final p = [RecStatus.ok.code, 3, 1, ...item('A.OGG', 1, 0)]; + expect(RecFileListPage.parse(p), isNull); + }); + + test('name_len 越界不会读到包外', () { + final n = RecFileName.encode('A.OGG'); + final p = [ + RecStatus.ok.code, + 1, + 1, + ...RecBytes.u32le(1), + ...RecBytes.u32le(0), + 99, // 谎报的 name_len + ...n, + ]; + expect(RecFileListPage.parse(p), isNull); + }); + + test('空目录:count=0 且 eof=1', () { + final page = RecFileListPage.parse([RecStatus.ok.code, 0, 1])!; + expect(page.items, isEmpty); + expect(page.eof, isTrue); + }); + + test('FAT 时间按标准布局解码', () { + // 2026-09-08 12:30:04 → date=(46<<9)|(9<<5)|8, time=(12<<11)|(30<<5)|2 + const date = ((2026 - 1980) << 9) | (9 << 5) | 8; + const time = (12 << 11) | (30 << 5) | 2; + const ftime = (date << 16) | time; + final page = + RecFileListPage.parse([RecStatus.ok.code, 1, 1, ...item('A.OGG', 1, ftime)])!; + expect(page.items.single.time, DateTime(2026, 9, 8, 12, 30, 4)); + }); + }); + + group('SETUP_RSP', () { + test('正常解析', () { + final body = [ + RecStatus.ok.code, + ...RecBytes.u32le(10000), + ...RecBytes.u32le(256), + ...RecBytes.u32le(0), + ...RecBytes.u16le(231), + ]; + final r = RecTransferSetupRsp.parse(body)!; + expect(r.fileSize, 10000); + expect(r.startOfs, 256); + expect(r.dataLen, 231); + }); + + test('status 非 OK 时其余字段归零', () { + final body = [ + RecStatus.fileNotFound.code, + ...RecBytes.u32le(10000), + ...RecBytes.u32le(256), + ...RecBytes.u32le(0), + ...RecBytes.u16le(231), + ]; + final r = RecTransferSetupRsp.parse(body)!; + expect(r.status, RecStatus.fileNotFound); + expect(r.fileSize, 0); + }); + }); +} diff --git a/apps/client/pubspec.lock b/apps/client/pubspec.lock index cbc2c8a1..61e12eaf 100644 --- a/apps/client/pubspec.lock +++ b/apps/client/pubspec.lock @@ -236,7 +236,7 @@ packages: source: hosted version: "1.4.1" chat_api: - dependency: "direct main" + dependency: transitive description: path: "local_plugins/chat_api" relative: true @@ -400,12 +400,19 @@ packages: source: path version: "0.0.1" device_plugin_interface: - dependency: transitive + dependency: "direct main" description: path: "local_plugins/device_plugin_interface" relative: true source: path - version: "0.1.0" + version: "0.2.0" + device_smartcar: + dependency: "direct main" + description: + path: "local_plugins/device_smartcar" + relative: true + source: path + version: "0.0.1" diff_match_patch: dependency: transitive description: @@ -1060,18 +1067,18 @@ packages: dependency: "direct main" description: name: in_app_purchase - sha256: ad59b45d998868b8ace0f606e09b348ffd888952a3cf8ff9f7956aaf4844e6e2 + sha256: "0e9510b80b0074e89ab0a8e0fc901439b779dc9ae575ab8d419253c6e1627716" url: "https://pub.dev" source: hosted - version: "3.2.4" + version: "3.3.0" in_app_purchase_android: dependency: "direct main" description: name: in_app_purchase_android - sha256: "518b48a385dfc1aa278080472969c6cee0c3d41ef8b9511b0071dd015473ecf1" + sha256: b8af1b6f0e57076b5da5ede71e3af2d727017c0416ad2a41017c6ed2b102381d url: "https://pub.dev" source: hosted - version: "0.4.0+11" + version: "0.5.0" in_app_purchase_platform_interface: dependency: transitive description: @@ -1104,13 +1111,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" - jl_opus: - dependency: "direct main" - description: - path: "local_plugins/jl_opus" - relative: true - source: path - version: "0.0.1" jni: dependency: transitive description: @@ -1309,13 +1309,6 @@ packages: url: "https://pub.dev" source: hosted version: "9.5.0" - open_ai_service: - dependency: "direct main" - description: - path: "local_plugins/open_ai_service" - relative: true - source: path - version: "0.0.1" package_config: dependency: transitive description: @@ -1579,13 +1572,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.3" - realtime: - dependency: "direct main" - description: - path: "local_plugins/realtime" - relative: true - source: path - version: "0.0.1" record: dependency: "direct main" description: @@ -1659,7 +1645,7 @@ packages: source: hosted version: "1.0.7" recorder_holder: - dependency: transitive + dependency: "direct main" description: path: "local_plugins/recorder_holder" relative: true diff --git a/apps/client/pubspec.yaml b/apps/client/pubspec.yaml index 71e23b7f..d03c8d17 100644 --- a/apps/client/pubspec.yaml +++ b/apps/client/pubspec.yaml @@ -1,7 +1,7 @@ name: eaimar description: "Eaimar - AI Voice Assistant." publish_to: "none" -version: 1.0.1+6 +version: 1.0.1+7 environment: sdk: ">=3.3.0 <4.0.0" @@ -20,7 +20,7 @@ dependencies: flutter_shaders: ^0.0.6 get: ^4.7.2 - in_app_purchase: ^3.2.3 + in_app_purchase: ^3.3.0 json_annotation: ^4.9.0 get_storage: ^2.1.1 http: ^1.3.0 @@ -80,9 +80,14 @@ dependencies: # 源自 echomeet 项目 local_plugins/recorder_holder,原样拉取未改协议实现。 echomeet_device_sdk: path: local_plugins/recorder_holder/sdk + # 插件本体。⚠️ 必须显式声明:`lib/devices/holder/holder_ota_port.dart` 直接 + # import 了它的 OTA 实现(`recorder_holder_ota.dart`),只靠 sdk 的传递依赖 + # 拿到是不作数的 —— 上游哪天不再依赖它,这边就编不过了。 + recorder_holder: + path: local_plugins/recorder_holder tobias: ^5.2.0 # 支付宝SDK url_launcher: ^6.3.1 - in_app_purchase_android: ^0.4.0+5 + in_app_purchase_android: ^0.5.0 # Play Billing 8.0(Google Play 2026-08-31 起的最低要求) app_links: firebase_core: ^4.0.0 firebase_auth: ^6.0.1 @@ -102,18 +107,29 @@ dependencies: path: local_plugins/speech azure_speech: path: local_plugins/azure_speech - chat_api: - path: local_plugins/chat_api - open_ai_service: - path: local_plugins/open_ai_service chat_storage: path: local_plugins/chat_storage + # ⚠️ 下面三个 Dart 侧已无引用,但**原生侧仍被别的插件依赖**,不能删: + # - device_jieli:recorder_holder 的 iOS Package.swift 引用它 vendor 的 JLAudioUnitKit(支架 Opus 解码) + # - classic_bluetooth:azure_speech 的 iOS Package.swift 引用它 + # - test:agent_service 的 iOS Package.swift 引用它 + # 要真正摘掉得先把那几个 xcframework 搬进使用方,属于原生改动,本轮不做。 device_jieli: path: local_plugins/device_jieli + # Smartcar 车载香薰(杰理方案)的 BLE 链路:自持 GATT,在同一条连接上跑杰理 RCSP 认证 + # (AE00)与 C2 私有通道(ABC0)。iOS 通过 device_jieli 暴露的 jl-blekit 产品复用同一份 + # JL_BLEKit 动态库。Android 目前是桩。 + device_smartcar: + path: local_plugins/device_smartcar classic_bluetooth: path: local_plugins/classic_bluetooth + test: + path: local_plugins/test bluetooth_manager: path: local_plugins/bluetooth_manager + # 设备插件契约(纯 Dart):厂商插件 / 会话 / 能力 / 音频 / OTA + device_plugin_interface: + path: local_plugins/device_plugin_interface # 恒玄(BES)固件 OTA 升级:自包含 BES OTA SDK(Android Java / iOS ObjC)与原生桥接。 # ⚠️ 它自管到耳机的 SPP 连接,不复用 bluetooth_manager 的连接——多数固件同时 # 只接受一条 SPP 链路,升级前必须先 disconnectDevice() 让路,见 ota_upgrade_controller。 @@ -134,18 +150,12 @@ dependencies: path: local_plugins/amap_service location_service: path: local_plugins/location_service - realtime: - path: local_plugins/realtime - jl_opus: - path: local_plugins/jl_opus user_portrait: path: local_plugins/user_portrait qq_music: path: local_plugins/qq_music floating_ui_plugin: path: local_plugins/floating_ui_plugin - test: - path: local_plugins/test dev_dependencies: flutter_test: diff --git a/apps/client/test/appconfig_model_test.dart b/apps/client/test/appconfig_model_test.dart new file mode 100644 index 00000000..be445fbb --- /dev/null +++ b/apps/client/test/appconfig_model_test.dart @@ -0,0 +1,73 @@ +import 'package:eaimar/data/models/appconfig_model.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// `user_getappconfig` 响应的契约测试:服务端少下发字段、下发 null, +/// 客户端都要能解出来,而不是整个 fromJson 抛 TypeError。 +void main() { + test('完整响应正常解析', () { + final resp = UserGetAppConfigResp.fromJson({ + 'env': {'AGENT_TYPE': 'default'}, + 'agents': [ + { + 'id': 'a1', + 'name': 'Emma', + 'avatarUrl': '', + 'description': '', + 'tag': '', + 'isOnline': true, + 'voice': 'v', + 'welcomeMessage': null, + 'voiceWelcomeMessage': null, + 'systemPrompt': 'hi', + 'tools': null, + } + ], + 'mcps': { + 'm': {'servername': 'm', 'url': 'u', 'type': 1, 'tools': ''} + }, + 'products': [ + { + 'id': 45091, + 'factoryid': 1, + 'devicetype': 0, + 'devicename': 'Echo-one', + 'productimage': null, + 'version': '0.0.3', + 'isforceupdate': false, + 'iscontinuouschat': null, + 'wakeupenable': null, + 'broadcastpeertranslate': null, + 'updatedescription': null, + 'updatepackageaddress': null, + } + ], + }); + expect(resp.products.single.devicename, 'Echo-one'); + expect(resp.agents.single.systemPrompt, 'hi'); + expect(resp.mcps['m']!.type, 1); + }); + + test('顶层键缺失时给空集合,不抛', () { + final resp = UserGetAppConfigResp.fromJson({}); + expect(resp.env, isEmpty); + expect(resp.agents, isEmpty); + expect(resp.mcps, isEmpty); + expect(resp.products, isEmpty); + }); + + test('产品缺 devicetype / factoryid / devicename 时用默认值', () { + final p = DBProduct.fromJson({'id': 1, 'version': '1.0.0'}); + expect(p.devicetype, 0); + expect(p.factoryid, 0); + expect(p.devicename, ''); + expect(p.version, '1.0.0'); + expect(p.updateonmismatch, isNull); + }); + + test('agent 缺非空字段时用默认值', () { + final a = DBAgent.fromJson({'id': 'x'}); + expect(a.name, ''); + expect(a.isOnline, isFalse); + expect(a.voice, ''); + }); +} diff --git a/apps/client/test/assistant_directive_test.dart b/apps/client/test/assistant_directive_test.dart index 424e7858..103dfb98 100644 --- a/apps/client/test/assistant_directive_test.dart +++ b/apps/client/test/assistant_directive_test.dart @@ -211,4 +211,58 @@ void main() { expect(back.source, 'earphone'); expect(back.synced, isFalse); }); + + group('commands 形状(2026-09-11 车载助手真机帧)', () { + // Smartcar 车载助手的指令不在 tool_calls 里,而是 extra_info.commands。 + // 只解析 tool_calls 的话这里恒为 0 条 —— 表现就是"AI 说已经关闭了、实际没反应"。 + Map frame() => { + 'dialog_id': 'd1', + 'round_id': 'r3', + 'text': '好的,那我先不打扰你啦,有需要随时叫我哦~', + 'finish_reason': 'stop', + 'extra_info': { + 'tool_infos': [], + 'agent_info': { + 'intent_infos': [ + {'domain': 'general_command', 'intent': 'quit'} + ], + 'round': 3, + }, + 'commands': [ + { + 'intent_info': {'domain': 'general_command', 'intent': 'quit'}, + 'name': 'quit', + 'params': [], + } + ], + 'query': '关闭对话。', + }, + }; + + test('解得出 quit 指令', () { + final list = + AssistantDirective.parseFromOutput(frame(), source: 'earphone'); + expect(list.length, 1); + expect(list.first.name, 'quit'); + expect(list.first.args['intent'], 'quit'); + expect(list.first.replyText, contains('不打扰')); + }); + + test('两种形状同时出现时都要解出来', () { + final f = frame(); + (f['extra_info'] as Map)['tool_calls'] = [ + { + 'function': {'name': 'SET_clock', 'arguments': '{"time":"08:00"}'} + } + ]; + final list = AssistantDirective.parseFromOutput(f, source: 'earphone'); + expect(list.map((d) => d.name).toList(), ['SET_clock', 'quit']); + }); + + test('commands 为空时不产生指令', () { + final f = frame(); + (f['extra_info'] as Map)['commands'] = []; + expect(AssistantDirective.parseFromOutput(f, source: 'earphone'), isEmpty); + }); + }); } diff --git a/apps/client/test/device_file_match_test.dart b/apps/client/test/device_file_match_test.dart new file mode 100644 index 00000000..3a7adbe0 --- /dev/null +++ b/apps/client/test/device_file_match_test.dart @@ -0,0 +1,43 @@ +import 'package:eaimar/data/utils/device_file_match.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// 删除设备原件的闸门(第一道:按标题找到那条已上传的记录)。 +/// 用例里的标题都是 2026-09-10 真机那次同步的实际值。 +/// +/// ⚠️ 第二道闸(本机文件长度 == 设备文件长度)在 DeviceFileImportService +/// 里做,因为要读磁盘。**两道都过才允许删**,放宽任何一道都是永久丢用户数据。 +void main() { + const uploaded = { + 'HOLDER_20260907_181224_MIC0049.OGG': '/data/.../LocalAudio/a.ogg', + 'HOLDER_20260907_184120_MIC0056.OGG': '/data/.../LocalAudio/b.ogg', + 'EARBUDS_20260902_223314.WAV': '/data/.../LocalAudio/c.wav', + }; + + test('设备上是大写短名,标题里是小写,要能对上', () { + expect(uploadedLocalPathFor(uploaded, 'MIC0049.OGG'), + '/data/.../LocalAudio/a.ogg'); + expect(uploadedLocalPathFor(uploaded, 'mic0056.ogg'), + '/data/.../LocalAudio/b.ogg'); + }); + + test('设备上有、但没有对应的已上传记录 → 拿不到路径,删不了', () { + expect(uploadedLocalPathFor(uploaded, 'MIC0099.OGG'), isNull); + }); + + test('⚠️ 后缀匹配不能被短名蒙混:IC0049 不是 MIC0049', () { + expect(uploadedLocalPathFor(uploaded, 'IC0049.OGG'), isNull); + }); + + test('没有已上传记录时一律删不了', () { + expect(uploadedLocalPathFor(const {}, 'MIC0049.OGG'), isNull); + }); + + test('空文件名一律拒绝', () { + expect(uploadedLocalPathFor(uploaded, ''), isNull); + }); + + test('记录里没有本机路径(服务端同步下来的行)→ 不作数', () { + const noPath = {'HOLDER_20260907_181224_MIC0049.OGG': ''}; + expect(uploadedLocalPathFor(noPath, 'MIC0049.OGG'), isNull); + }); +} diff --git a/apps/client/test/devices/bes_protocol_test.dart b/apps/client/test/devices/bes_protocol_test.dart new file mode 100644 index 00000000..553a7f7d --- /dev/null +++ b/apps/client/test/devices/bes_protocol_test.dart @@ -0,0 +1,110 @@ +import 'package:eaimar/devices/bes/bes_protocol.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// 恒玄协议金测试:帧全部来自真机抓包或厂商文档样例,**一个字节都不能改**。 +/// 这些测试红了,先怀疑改动、别怀疑帧。 +void main() { + List h(String s) => s + .trim() + .split(RegExp(r'\s+')) + .where((e) => e.isNotEmpty) + .map((e) => int.parse(e, radix: 16)) + .toList(); + + group('BB 0A 状态帧', () { + test('Echo-one 0.0.2 真机帧:不在盒内,无属性 3,帧尾 MAC 逐字节吻合', () { + // 2026-09-01 真机抓帧(属性 6 那 12 字节按实测样本填) + final frame = h('BB 0A 25 ' + '02 01 45 ' + '02 02 56 ' + '02 04 49 ' + '02 05 6C ' + '0D 06 00 01 01 70 B3 B1 4D 33 DC 00 00 00 ' + '07 07 11 11 22 33 33 A4'); + final st = BesProtocol.parseStatus(frame); + expect(st.batteryLeft, 69); + expect(st.batteryRight, 86); + expect(st.batteryCase, isNull, reason: '不在盒内时没有属性 3'); + expect(st.chargingLeft, isFalse); + expect(st.chargingRight, isFalse); + expect(st.mac, '11:11:22:33:33:A4'); + expect(st.summaryBattery, 69, reason: '左右取较低一侧'); + }); + + test('厂商文档样例:三个电量都在', () { + final frame = h('BB 0A 28 02 01 2B 02 02 18 02 03 64 02 04 85 02 05 6E'); + final st = BesProtocol.parseStatus(frame); + expect(st.batteryLeft, 43); + expect(st.batteryRight, 24); + expect(st.batteryCase, 100); + expect(st.summaryBattery, 24); + }); + + test('最高位是充电指示位,必须 & 0x7F', () { + final frame = h('BB 0A 09 02 01 C5 02 02 56'); + final st = BesProtocol.parseStatus(frame); + expect(st.batteryLeft, 69); + expect(st.chargingLeft, isTrue); + expect(st.batteryRight, 86); + expect(st.chargingRight, isFalse); + }); + + test('属性 4/5 的值超过 100 不会被当成电量', () { + final frame = h('BB 0A 06 02 04 89 02 05 6E'); + final st = BesProtocol.parseStatus(frame); + expect(st.hasBattery, isFalse); + }); + + test('从偏移 4 开始解(固件版本帧的写法)会一个值都解不出——守住起点是 3', () { + final frame = h('BB 0A 25 02 01 45 02 02 56 02 04 49 02 05 6C'); + // 人为错位一格模拟旧 bug:第一个「块长度」读到的是属性号 0x01 < 2 + final shifted = [frame[0], frame[1], frame[2], 0x00, ...frame.sublist(3)]; + expect(BesProtocol.parseStatus(shifted).hasBattery, isFalse); + expect(BesProtocol.parseStatus(frame).hasBattery, isTrue); + }); + }); + + group('固件版本帧', () { + test('BB 86 优先左耳,版本取块后 3 字节', () { + final frame = h('BB 86 14 00 ' + '09 01 00 00 00 00 00 00 00 02 ' + '09 02 00 00 00 00 00 00 00 03'); + final fw = BesProtocol.parseFirmware(frame); + expect(fw.left, '0.0.2'); + expect(fw.right, '0.0.3'); + expect(fw.preferred, '0.0.2'); + }); + }); + + group('命令字节', () { + test('每个 feature 对应的字节序列固定', () { + expect(BesCmd.frame(BesCmd.firmwareVersion), [0xAA, 0x06]); + expect(BesCmd.frame(BesCmd.status), [0xAA, 0x09]); + expect(BesCmd.frame(BesCmd.callState), [0xAA, 0x0E]); + expect(BesCmd.frame(BesCmd.callModeStart), [0xAA, 0x51]); + expect(BesCmd.frame(BesCmd.callModeStop), [0xAA, 0x52]); + expect(BesCmd.frame(BesCmd.asrStarted), [0xAA, 0x57]); + expect(BesCmd.frame(BesCmd.asrStopped), [0xAA, 0x58]); + expect(BesCmd.frame(BesCmd.micRecordStart), [0xAA, 0x59]); + expect(BesCmd.frame(BesCmd.micRecordStop), [0xAA, 0x5A]); + expect(BesCmd.frame(BesCmd.aiExit), [0xAA, 0x65]); + expect(BesCmd.frame(BesCmd.faceToFaceStart), [0xAA, 0x66]); + expect(BesCmd.frame(BesCmd.faceToFaceStop), [0xAA, 0x67]); + expect(BesCmd.frame(BesCmd.aiAccept), [0xAA, 0x6A]); + }); + + test('电量请求是 09 不是 0A,也不是 |0x80 推出来的任何值', () { + expect(BesCmd.status, 0x09); + expect(BesResp.status, 0x0A); + expect(BesCmd.status | 0x80, isNot(BesResp.status)); + }); + + test('0x51~0x6A 会切工作模式,探测时必须跳过', () { + for (var c = 0x51; c <= 0x6A; c++) { + expect(BesCmd.switchesMode(c), isTrue, reason: '0x${c.toRadixString(16)}'); + } + expect(BesCmd.switchesMode(0x09), isFalse); + expect(BesCmd.switchesMode(0x06), isFalse); + }); + }); +} diff --git a/apps/client/test/devices/bes_session_commands_test.dart b/apps/client/test/devices/bes_session_commands_test.dart new file mode 100644 index 00000000..1b73a2a3 --- /dev/null +++ b/apps/client/test/devices/bes_session_commands_test.dart @@ -0,0 +1,52 @@ +import 'package:device_plugin_interface/device_plugin_interface.dart'; +import 'package:eaimar/devices/bes/bes_device_plugin.dart'; +import 'package:eaimar/devices/bes/bes_protocol.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// feature key → 发给恒玄耳机的字节,**冻结**。 +/// +/// 业务层只认 feature key,这张表是它与线上固件之间唯一的翻译;改一个字节 +/// 等于改协议。表里的每一条都对应已量产固件的真实行为。 +void main() { + test('通用 feature 到字节的映射逐条固定', () { + const expected = >{ + DeviceFeatures.recordStart: [0xAA, 0x59], + DeviceFeatures.recordStop: [0xAA, 0x5A], + DeviceFeatures.callStart: [0xAA, 0x51], + DeviceFeatures.callStop: [0xAA, 0x52], + DeviceFeatures.callQuery: [0xAA, 0x0E], + DeviceFeatures.asrStarted: [0xAA, 0x57], + DeviceFeatures.asrStopped: [0xAA, 0x58], + DeviceFeatures.aiAccept: [0xAA, 0x6A], + DeviceFeatures.aiExit: [0xAA, 0x65], + DeviceFeatures.f2fStart: [0xAA, 0x66], + DeviceFeatures.f2fStop: [0xAA, 0x67], + DeviceFeatures.batteryQuery: [0xAA, 0x09], + 'bes.firmware.query': [0xAA, 0x06], + }; + for (final e in expected.entries) { + final cmd = BesDeviceSession.featureCommands[e.key]; + expect(cmd, isNotNull, reason: '${e.key} 没有映射'); + expect(BesCmd.frame(cmd!), e.value, reason: e.key); + } + expect(BesDeviceSession.featureCommands.length, expected.length, + reason: '多出来的映射也要在这里登记'); + }); + + test('恒玄会话声明的能力集:只增不删', () { + const must = { + DeviceCapability.battery, + DeviceCapability.macAddress, + DeviceCapability.micUplink, + DeviceCapability.speakerDownlink, + DeviceCapability.micRecording, + DeviceCapability.callAudioTap, + DeviceCapability.callState, + DeviceCapability.aiWake, + DeviceCapability.translationDownlink, + DeviceCapability.faceToFace, + DeviceCapability.ota, + }; + expect(BesDeviceSession.caps.containsAll(must), isTrue); + }); +} diff --git a/apps/client/test/devices/device_hub_boundary_test.dart b/apps/client/test/devices/device_hub_boundary_test.dart new file mode 100644 index 00000000..6fc2ad8d --- /dev/null +++ b/apps/client/test/devices/device_hub_boundary_test.dart @@ -0,0 +1,62 @@ +import 'dart:io'; + +import 'package:flutter_test/flutter_test.dart'; + +/// 分层边界:业务层不认厂商。 +/// +/// `lib/modules`、`lib/core`、`lib/data` 只能 import `lib/devices/*.dart`(中枢) +/// 与 `device_plugin_interface`,**不能** import `lib/devices//…`, +/// 也不能出现厂商类名。新接一种芯片只动 `lib/devices//` 与 bootstrap。 +void main() { + final vendorImport = RegExp(r"devices/(bes|holder|smartcar)/"); + final vendorTypes = RegExp( + r'\b(BesBluetoothService|BesDevicePlugin|BesDeviceSession|BesDeviceAuth|' + r'HolderDeviceService|HolderDevicePlugin|HolderDeviceSession|' + r'EchoMeetDeviceSdk|BluetoothManager\(\))'); + final vendorPackages = RegExp( + r"package:(bluetooth_manager|echomeet_device_sdk|bes_ota_manager)/"); + + List dartFiles(String dir) => Directory(dir) + .listSync(recursive: true) + .whereType() + .where((f) => f.path.endsWith('.dart')) + .toList(); + + /// 只看代码,注释里提到厂商名不算 + String codeOnly(File f) => f + .readAsLinesSync() + .where((l) => !l.trimLeft().startsWith('//')) + .map((l) => l.replaceFirst(RegExp(r'\s//.*$'), '')) + .join('\n'); + + test('lib/modules、lib/core、lib/data 不引用任何厂商实现', () { + final offenders = []; + for (final dir in ['lib/modules', 'lib/core', 'lib/data']) { + for (final f in dartFiles(dir)) { + final src = codeOnly(f); + if (vendorImport.hasMatch(src) || + vendorTypes.hasMatch(src) || + vendorPackages.hasMatch(src)) { + offenders.add(f.path); + } + } + } + expect(offenders, isEmpty, + reason: '这些文件绕过了 DeviceHub 直接碰厂商实现:\n${offenders.join('\n')}'); + }); + + test('厂商目录之间互不引用', () { + final offenders = []; + for (final f in dartFiles('lib/devices')) { + final parts = f.path.split('/'); + final idx = parts.indexOf('devices'); + if (idx < 0 || idx + 2 >= parts.length) continue; // 顶层文件不限制 + final myVendor = parts[idx + 1]; + final src = codeOnly(f); + for (final m in vendorImport.allMatches(src)) { + if (m.group(1) != myVendor) offenders.add('${f.path} -> ${m.group(0)}'); + } + } + expect(offenders, isEmpty, reason: offenders.join('\n')); + }); +} diff --git a/apps/client/test/devices/smartcar_protocol_test.dart b/apps/client/test/devices/smartcar_protocol_test.dart new file mode 100644 index 00000000..8a77eb53 --- /dev/null +++ b/apps/client/test/devices/smartcar_protocol_test.dart @@ -0,0 +1,258 @@ +import 'package:eaimar/devices/smartcar/smartcar_protocol.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// Smartcar C2 协议的字节级金测试。 +/// +/// 协议是**冻结的**:同一个命令永远发同样的字节。这些用例就是那份契约—— +/// 改动这里等于改协议,必须先在真机上验过。 +void main() { + group('CRC-8/MAXIM', () { + test('空数据为 0', () { + expect(SmartcarProtocol.crc8Maxim(const []), 0x00); + }); + + // 与 lumi BleProtocol.calcCrc 同算法(poly 0x31 反射 0x8C / init 0 / xorOut 0)。 + // 这几个值是标准 CRC-8/MAXIM 的公认结果,可离线核对。 + test('标准向量', () { + expect(SmartcarProtocol.crc8Maxim([0x00]), 0x00); + // "123456789" 的 CRC-8/MAXIM 标准 check 值是 0xA1 + expect( + SmartcarProtocol.crc8Maxim( + '123456789'.codeUnits), + 0xA1, + ); + }); + + test('逐位实现与查表口径一致(对 0..255 单字节全覆盖)', () { + for (var b = 0; b < 256; b++) { + var crc = 0; + crc ^= b; + for (var i = 0; i < 8; i++) { + crc = (crc & 1) != 0 ? (crc >> 1) ^ 0x8C : crc >> 1; + } + expect(SmartcarProtocol.crc8Maxim([b]), crc & 0xFF); + } + }); + }); + + group('组帧', () { + test('无参命令:获取版本号', () { + final p = SmartcarProtocol.buildPacket(SmartcarProtocol.cmdGetVersion); + expect(p[0], 0xAA); + expect(p[1], 0x01); + expect(p[2], 0x00); // len + expect(p.length, 4); + expect(p[3], SmartcarProtocol.crc8Maxim([0xAA, 0x01, 0x00])); + }); + + test('带参命令:设音量', () { + final p = SmartcarProtocol.buildPacket( + SmartcarProtocol.cmdSetVolume, const [0x05]); + expect(p.sublist(0, 4), [0xAA, 0x0B, 0x01, 0x05]); + expect(p.length, 5); + expect(p[4], SmartcarProtocol.crc8Maxim([0xAA, 0x0B, 0x01, 0x05])); + }); + + test('组出来的帧能被自己解回去', () { + final p = SmartcarProtocol.buildPacket(0x42, const [1, 2, 3]); + // buildPacket 发的是 0xAA,parseFrame 也认这个头 + final f = SmartcarProtocol.parseFrame(p); + expect(f, isNotNull); + expect(f!.cmd, 0x42); + expect(f.payload, [1, 2, 3]); + }); + }); + + group('解帧', () { + /// 造一帧设备应答 + List resp(int cmd, List payload) { + final head = [0xBB, cmd, payload.length, ...payload]; + return [...head, SmartcarProtocol.crc8Maxim(head)]; + } + + test('正常应答', () { + final f = SmartcarProtocol.parseFrame(resp(0x04, const [0x64])); + expect(f, isNotNull); + expect(f!.isResponse, isTrue); + expect(f.cmd, SmartcarProtocol.cmdGetBattery); + expect(f.payload, [100]); + expect(f.success, isTrue); + }); + + test('len=0 表示命令执行失败', () { + final f = SmartcarProtocol.parseFrame(resp(0x01, const [])); + expect(f, isNotNull); + expect(f!.success, isFalse); + }); + + test('主动上报帧头 0xCC', () { + final head = [0xCC, SmartcarProtocol.notifyAiWake, 0x00]; + final f = SmartcarProtocol + .parseFrame([...head, SmartcarProtocol.crc8Maxim(head)]); + expect(f!.isNotify, isTrue); + expect(f.cmd, 0x11); + }); + + test('CRC 不符必须丢弃', () { + final bad = resp(0x04, const [0x64]); + bad[bad.length - 1] = (bad.last + 1) & 0xFF; + expect(SmartcarProtocol.parseFrame(bad), isNull); + }); + + test('帧头不认识 / 长度不够 一律 null', () { + expect(SmartcarProtocol.parseFrame(const [0x12, 0x01, 0x00, 0x00]), isNull); + expect(SmartcarProtocol.parseFrame(const [0xBB, 0x01]), isNull); + // 声明 len=5 但实际只有 1 字节 payload + expect( + SmartcarProtocol.parseFrame(const [0xBB, 0x01, 0x05, 0x00, 0x00]), + isNull); + }); + }); + + group('广播解析', () { + /// 造一段 26 字节广播:CID 0x8505 / BID 0xA001 / PID 0x0001, + /// 经典蓝牙已连,MAC 11:22:33:44:55:66(存的是 XOR 0x5A 之后的值) + /// 真机实测(2026-09-10):CoreBluetooth 给的厂商数据 `05 85 a9 1a b3 21 e4 dd 00`, + /// 链路层补回 `[长度, 0xFF]` 后交给解析器 + List adv({int btState = 0x00}) => [ + 10, 0xFF, + 0x05, 0x85, // CID 小端 → 0x8505 + 0xA9, 0x1A, 0xB3, 0x21, 0xE4, 0xDD, // MAC 原样 + btState, + ]; + + test('真机广播:MAC 原样取 CID 之后 6 字节', () { + final a = SmartcarProtocol.parseManufacturerData(adv())!; + expect(a.cid, 0x8505); + expect(a.macAddress, 'A9:1A:B3:21:E4:DD'); + expect(a.classicBtConnected, isFalse); + }); + + test('状态字节 0x0C 视为经典蓝牙已连', () { + final a = SmartcarProtocol.parseManufacturerData(adv(btState: 0x0C))!; + expect(a.classicBtConnected, isTrue); + }); + + test('没有状态字节也能解出 MAC', () { + final a = SmartcarProtocol.parseManufacturerData(adv().sublist(0, 10))!; + expect(a.macAddress, 'A9:1A:B3:21:E4:DD'); + }); + + test('长度不足返回 null,不能抛', () { + expect(SmartcarProtocol.parseManufacturerData(null), isNull); + expect(SmartcarProtocol.parseManufacturerData(List.filled(9, 0)), isNull); + // Type 不是 0xFF 的段不是厂商数据 + expect(SmartcarProtocol.parseManufacturerData([10, 0x09, ...List.filled(8, 0)]), isNull); + }); + }); + + group('0x15 参数汇总', () { + test('14 字节逐项解对', () { + final s = SmartcarAllSettings.parse(const [ + 0x00, // OTA 正常 + 0x06, // 音量 6 + 0x1E, // 随机表情频次 30 + 0x08, // 亮度 8 + 0x50, // 电量 80 + 1, 2, 3, // 版本 1.2.3 + 0x01, // 启停开 + 0x03, // 摇头风格 3 + 0x01, // 音乐表情开 + 0x00, // 陀螺仪关 + 0x00, // 保留 + 0x01, // 电机开 + ])!; + expect(s.otaAbnormal, isFalse); + expect(s.volume, 6); + expect(s.randomExprFreq, 30); + expect(s.brightness, 8); + expect(s.battery, 80); + expect(s.firmwareVersion, '1.2.3'); + expect(s.powerSwitch, isTrue); + expect(s.musicHeadStyle, 3); + expect(s.musicExpression, isTrue); + expect(s.gyroscope, isFalse); + expect(s.motor, isTrue); + }); + + test('短包返回 null', () { + expect(SmartcarAllSettings.parse(List.filled(13, 0)), isNull); + }); + }); + + group('命令号(2026-09-11 按 lumi 运行时代码 + 协议文档定稿)', () { + test('0x05 是音乐播放状态、0x07 是 AI 状态,别按 BleConst.kt 的旧名字改回去', () { + // 判据:lumi `BleService.swift` 的 checkMusicPlaybackState() 实际发的是 + // 0x05 [0x01]/[0x00](手机在放/停止放音乐),与协议文档一致; + // "遥控电机"另有其号 0x0E,所以 0x07 不是控制动作。 + expect(SmartcarProtocol.cmdMusicPlayState, 0x05); + expect(SmartcarProtocol.cmdAiState, 0x07); + expect(SmartcarProtocol.cmdRemoteMotor, 0x0E); + }); + + test('0x11 双向共号:0xAA 是陀螺仪开关,0xCC 是 AI 唤醒', () { + expect(SmartcarProtocol.cmdGyroscopeSwitch, 0x11); + expect(SmartcarProtocol.notifyAiWake, 0x11); + final wake = SmartcarProtocol.parseFrame( + SmartcarProtocol.buildPacket(SmartcarProtocol.notifyAiWake, const [0xAA]) + .toList() + ..[0] = SmartcarProtocol.headerNotify); + // 帧头被改过,CRC 对不上,解析必须失败——这条顺带守住"CRC 覆盖帧头" + expect(wake, isNull); + }); + + test('AI 状态取值与协议文档一致', () { + expect(SmartcarProtocol.aiStateSpeakEnd, 0x00); + expect(SmartcarProtocol.aiStateThinking, 0x01); + expect(SmartcarProtocol.aiStateSpeakStart, 0x02); + expect(SmartcarProtocol.aiStateClose, 0x03); + expect(SmartcarProtocol.aiStateListening, 0x04); + }); + }); + + group('0x15 真机帧(2026-09-11 样机实测,金测试)', () { + // 同一次连接里单发 0x04 得到 3c(60)、单发 0x01 得到 02 0c 0c(2.12.12), + // 与这一帧的 [4] / [5..7] 完全一致 —— 偏移就是靠这两处交叉验证钉死的。 + const real = [ + 0x01, 0x00, 0x14, 0x0a, 0x3c, 0x02, 0x0c, 0x0c, + 0x00, 0x02, 0x01, 0x01, 0x04, 0x01, + ]; + + test('电量与版本与单发命令对得上', () { + final s = SmartcarAllSettings.parse(real)!; + expect(s.battery, 60, reason: '与 0x04 的应答 3c 一致'); + expect(s.firmwareVersion, '2.12.12', reason: '与 0x01 的应答 02 0c 0c 一致'); + }); + + test('其余字段按已钉死的偏移解出', () { + final s = SmartcarAllSettings.parse(real)!; + expect(s.brightness, 10); + expect(s.randomExprFreq, 20); + expect(s.volume, 0, reason: '实测就是 0(样机静音),改这条前先在真机上复核'); + expect(s.otaAbnormal, isTrue); + }); + }); + + group('应答期望', () { + test('这四条命令设备不回包,别等超时', () { + for (final c in [ + SmartcarProtocol.cmdMusicPlayState, + SmartcarProtocol.cmdControlEmotion, + SmartcarProtocol.cmdAiState, + SmartcarProtocol.cmdControlMusicBeat, + ]) { + expect(SmartcarProtocol.expectsResponse(c), isFalse, + reason: '0x${c.toRadixString(16)} 不该等应答'); + } + }); + + test('查询类命令要等应答', () { + expect(SmartcarProtocol.expectsResponse(SmartcarProtocol.cmdGetVersion), + isTrue); + expect(SmartcarProtocol.expectsResponse(SmartcarProtocol.cmdGetBattery), + isTrue); + expect(SmartcarProtocol.expectsResponse(SmartcarProtocol.cmdSyncSummary), + isTrue); + }); + }); +} diff --git a/apps/client/test/module_registry_test.dart b/apps/client/test/module_registry_test.dart new file mode 100644 index 00000000..a2190db0 --- /dev/null +++ b/apps/client/test/module_registry_test.dart @@ -0,0 +1,94 @@ +import 'package:eaimar/core/translations/language/en_us.dart'; +import 'package:eaimar/core/translations/language/zh_cn.dart'; +import 'package:eaimar/data/models/agent_module.dart'; +import 'package:eaimar/data/models/device_category.dart'; +import 'package:eaimar/modules/module_registry.dart'; +import 'package:eaimar/routes/app_pages.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// Agent 模块注册表卫生:新增模块只动 `lib/modules//` + 注册表一行, +/// 这里守住每条描述符都接完了线。 +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + test('模块 id 唯一', () { + final ids = ModuleRegistry.all.map((m) => m.id).toList(); + expect(ids.toSet().length, ids.length, reason: '重复 id: $ids'); + }); + + test('已实现的模块都有跳转方式;占位模块可以没有', () { + final broken = ModuleRegistry.all + .where((m) => !m.comingSoon && m.entryRoute == null && m.onLaunch == null) + .map((m) => m.id) + .toList(); + expect(broken, isEmpty, reason: '这些模块点了没反应: $broken'); + }); + + test('entryRoute 指向的页面已注册', () { + final registered = AppPages.pages.map((p) => p.name).toSet(); + final missing = ModuleRegistry.all + .where((m) => m.entryRoute != null && !registered.contains(m.entryRoute)) + .map((m) => '${m.id} -> ${m.entryRoute}') + .toList(); + expect(missing, isEmpty, reason: missing.join('\n')); + }); + + test('模块页面都进了总路由表,且 name 不与核心页面撞车', () { + final all = AppPages.pages.map((p) => p.name).toList(); + for (final p in ModuleRegistry.pages) { + expect(all.where((n) => n == p.name).length, 1, + reason: '${p.name} 注册了 ${all.where((n) => n == p.name).length} 次'); + } + }); + + test('标题/副标题的 i18n key 在 en_US 与 zh_CN 里有落点(或模块自带)', () { + final merged = ModuleRegistry.mergeTranslations({'en_US': enUS, 'zh_CN': zhCN}); + final missing = []; + for (final m in ModuleRegistry.all) { + for (final loc in ['en_US', 'zh_CN']) { + final table = merged[loc]!; + if (!table.containsKey(m.title)) missing.add('$loc:${m.title}'); + final sub = m.subtitle; + if (sub != null && !table.containsKey(sub)) missing.add('$loc:$sub'); + } + } + expect(missing, isEmpty, reason: '缺文案: $missing'); + }); + + test('注册表注入后 AgentModules.all 与 ModuleRegistry.all 同一份', () { + ModuleRegistry.install(); + expect(identical(AgentModules.all, ModuleRegistry.all), isTrue); + expect(AgentModules.byId('meeting'), isNotNull); + }); + + test('指令处理器同名不重复注册', () { + final names = []; + for (final m in ModuleRegistry.all) { + names.addAll(m.directives.keys); + } + expect(names.toSet().length, names.length, reason: '重复指令: $names'); + }); + + group('设备品类默认编排', () { + test('车载香薰连上后铺 Smartcar / 现场录音 / 语音纪要(按这个顺序)', () { + expect( + AgentModules.defaultsForCategory(DeviceCategories.carAroma), + [ + AgentModules.smartcarChat, + AgentModules.fieldRecording, + AgentModules.meeting, + ], + ); + }); + + test('这三个都不依赖设备能力,所以连上香薰不会灰', () { + ModuleRegistry.install(); + for (final id in AgentModules.defaultsForCategory(DeviceCategories.carAroma)) { + final m = ModuleRegistry.byId(id); + expect(m, isNotNull, reason: '$id 不在注册表里'); + expect(m!.requiredCapabilities, isEmpty, + reason: '$id 声明了 requiredCapabilities,车载香薰没有这些能力时会被置灰'); + } + }); + }); +} diff --git a/apps/client/test/ogg_opus_duration_test.dart b/apps/client/test/ogg_opus_duration_test.dart new file mode 100644 index 00000000..45c9b152 --- /dev/null +++ b/apps/client/test/ogg_opus_duration_test.dart @@ -0,0 +1,65 @@ +import 'package:eaimar/data/utils/ogg_opus_duration.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// Ogg Opus 时长解析的金测试。 +/// +/// 用例是 **EaiRec 支架真机 TF 卡上那条录音的原始字节**(2026-09-10 拉下来的 +/// `MIC0005.OGG`,38400 字节),不是构造出来的样本。改这里的解析逻辑前先看 +/// 这个测试为什么红。 +void main() { + // 文件头 48 字节:第一个 page(含 OpusHead) + const head = [ + 0x4F, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, // + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, + 0x30, 0x89, 0x00, 0x00, 0x00, 0x00, 0x21, 0x8B, + 0x55, 0x8A, 0x01, 0x13, 0x4F, 0x70, 0x75, 0x73, + 0x48, 0x65, 0x61, 0x64, 0x01, 0x01, 0x00, 0x00, + 0x80, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, + ]; + + // 最后一个 page 的头 27 字节:granulepos = 0x0006B580 = 439680 + const tail = [ + 0x4F, 0x67, 0x67, 0x53, 0x00, 0x04, 0x80, 0xB5, // + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, + 0x30, 0x89, 0x1E, 0x00, 0x00, 0x00, 0xF3, 0xEE, + 0x70, 0xEC, 0x0A, + ]; + + test('真机 MIC0005.OGG:granulepos 439680 → 9.16 秒', () { + final secs = oggOpusSecondsFrom(head, tail); + expect(secs, isNotNull); + // 439680 / 48000 = 9.16 + expect(secs!, closeTo(9.16, 0.01)); + }); + + test('⚠️ 除数必须是 48000 而不是音频的 16000', () { + // OpusHead 里写的输入采样率是 16000(head 偏移 40 起的 0x00003E80), + // 但 granulepos 恒以 48kHz 计。用 16000 去除会得到 27.48s —— 3 倍。 + final secs = oggOpusSecondsFrom(head, tail)!; + expect(secs, lessThan(10)); + }); + + test('pre-skip 要从 granulepos 里扣掉', () { + // 把 OpusHead 的 pre-skip 从 0 改成 48000(1 秒) + final h = List.from(head); + h[38] = 0x80; // pre-skip 低字节 + h[39] = 0xBB; // 0xBB80 = 48000 + final secs = oggOpusSecondsFrom(h, tail)!; + expect(secs, closeTo(8.16, 0.01)); + }); + + test('不是 Ogg 就返回 null,不猜', () { + // RIFF/WAV 头 + const wav = [0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00]; + expect(oggOpusSecondsFrom(wav, tail), isNull); + }); + + test('granulepos 不大于 pre-skip 时返回 null(空文件/只有头)', () { + // 最后一个 page 的 granulepos 置 0 + final t = List.from(tail); + for (var i = 6; i < 14; i++) { + t[i] = 0; + } + expect(oggOpusSecondsFrom(head, t), isNull); + }); +} diff --git a/apps/client/test/recording_time_test.dart b/apps/client/test/recording_time_test.dart new file mode 100644 index 00000000..62f769c0 --- /dev/null +++ b/apps/client/test/recording_time_test.dart @@ -0,0 +1,38 @@ +import 'package:eaimar/data/utils/recording_time.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// 「从设备同步进来的录音显示什么时间」的口径。 +/// +/// 用例里的 2018-08-10 不是编的:那是 2026-09-10 真机那张 TF 卡上一批文件的 +/// 真实 FAT 时间戳(设备 RTC 还没对时就录的)。 +void main() { + final now = DateTime(2026, 9, 10, 23, 43); + + test('设备时间合理时就用它', () { + final t = DateTime(2026, 8, 15, 14, 33, 4); + expect(resolveRecordingCreationTime(t, now: now), t.millisecondsSinceEpoch); + }); + + test('设备没给时间就用当前时刻', () { + expect(resolveRecordingCreationTime(null, now: now), + now.millisecondsSinceEpoch); + }); + + test('⚠️ RTC 没对时的垃圾时间戳(2018)要丢掉,否则记录沉到列表最底下', () { + expect(resolveRecordingCreationTime(DateTime(2018, 8, 10), now: now), + now.millisecondsSinceEpoch); + }); + + test('FAT 的 1980 纪元同样丢掉', () { + expect(resolveRecordingCreationTime(DateTime(1980, 1, 1), now: now), + now.millisecondsSinceEpoch); + }); + + test('未来时间也丢掉(设备时钟跑飞),但留一天容差给时区', () { + expect(resolveRecordingCreationTime(DateTime(2030, 1, 1), now: now), + now.millisecondsSinceEpoch); + final justAhead = now.add(const Duration(hours: 8)); + expect(resolveRecordingCreationTime(justAhead, now: now), + justAhead.millisecondsSinceEpoch); + }); +} diff --git a/apps/client/test/routes_test.dart b/apps/client/test/routes_test.dart new file mode 100644 index 00000000..57e83382 --- /dev/null +++ b/apps/client/test/routes_test.dart @@ -0,0 +1,50 @@ +import 'dart:io'; + +import 'package:eaimar/routes/app_pages.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// 路由表卫生:每条 Routes 常量都要在 AppPages 里注册,且至少有一处跳转; +/// 每个 GetPage 的 name 唯一。死路由曾经堆到 20 个,这里守住不再长回来。 +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + final routesSrc = File('lib/routes/app_routes.dart').readAsStringSync(); + final constRe = RegExp(r"static const (\w+) = '([^']+)';"); + final declared = { + for (final m in constRe.allMatches(routesSrc)) m.group(1)!: m.group(2)! + }; + + test('每条路由常量都在 AppPages 注册(initial 与 home 共用同一路径)', () { + final registered = AppPages.pages.map((p) => p.name).toSet(); + final missing = declared.entries + .where((e) => !registered.contains(e.value)) + .map((e) => e.key) + .toList(); + expect(missing, isEmpty, reason: '声明了但没注册: $missing'); + }); + + test('GetPage name 唯一(home/initial 例外,两个常量同一路径)', () { + final names = AppPages.pages.map((p) => p.name).toList(); + final dup = {}; + final seen = {}; + for (final n in names) { + if (!seen.add(n)) dup.add(n); + } + dup.remove('/home'); + expect(dup, isEmpty, reason: '重复注册: $dup'); + }); + + test('每条路由常量至少有一处跳转方(routes/ 目录之外)', () { + final files = Directory('lib') + .listSync(recursive: true) + .whereType() + .where((f) => f.path.endsWith('.dart') && !f.path.contains('lib/routes/')) + .map((f) => f.readAsStringSync()) + .join('\n'); + final unused = declared.keys + .where((k) => !RegExp('Routes\\.$k\\b').hasMatch(files)) + .where((k) => k != 'initial') // GetMaterialApp 的 initialRoute 在 main.dart 直接用 + .toList(); + expect(unused, isEmpty, reason: '没人跳转的死路由: $unused'); + }); +} diff --git a/apps/client/test/user_device_license_test.dart b/apps/client/test/user_device_license_test.dart new file mode 100644 index 00000000..4368fdcd --- /dev/null +++ b/apps/client/test/user_device_license_test.dart @@ -0,0 +1,52 @@ +import 'package:eaimar/data/models/user_Info.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// 「设备页显示了两个 MAC」这个 bug 的回归测试(2026-09-11)。 +/// +/// 真机上车载香薰绑定后,服务端回的是 +/// `"devicemac":"A9:1A:B3:21:E4:DD","license":"A9:1A:B3:21:E4:DD"` —— +/// 授权码就是 MAC 本身(后台「导入 MAC」模式建的记录,`code := devicemac`)。 +/// 界面照显示就会出现两行一模一样的串:一行钥匙图标(授权码)、一行 MAC, +/// 看着像同一个 MAC 显示了两遍。 +void main() { + UserDevice make({required String mac, required String license}) => UserDevice( + id: 1, + uid: '1', + productid: 45345, + devicetype: 0, + devicename: 'Smartcar', + devicemac: mac, + license: license, + cmei: '', + ); + + group('UserDevice.hasRealLicense', () { + test('授权码就是 MAC 本身 → 不展示(真机原始数据)', () { + expect( + make(mac: 'A9:1A:B3:21:E4:DD', license: 'A9:1A:B3:21:E4:DD') + .hasRealLicense, + isFalse, + ); + }); + + test('大小写与分隔符不同也算同一个值', () { + expect(make(mac: 'A9:1A:B3:21:E4:DD', license: 'a91ab321e4dd').hasRealLicense, + isFalse); + expect(make(mac: 'A9:1A:B3:21:E4:DD', license: 'A9-1A-B3-21-E4-DD') + .hasRealLicense, isFalse); + }); + + test('真授权码照常展示', () { + expect( + make(mac: 'A9:1A:B3:21:E4:DD', license: '71E5E5C3A797C043B5A7') + .hasRealLicense, + isTrue, + ); + }); + + test('空授权码不展示', () { + expect(make(mac: 'A9:1A:B3:21:E4:DD', license: ' ').hasRealLicense, + isFalse); + }); + }); +} diff --git a/apps/client/tools/i18n_fill_missing.py b/apps/client/tools/i18n_fill_missing.py new file mode 100644 index 00000000..708e9e6b --- /dev/null +++ b/apps/client/tools/i18n_fill_missing.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python3 +"""补齐语言文件里相对 en_us.dart 缺失的 key。 + +语言文件是 `const Map`,key 同时存在 `'key'` 与 `"key"` 两种引号写法, +所以查重必须两种引号都认——const map 重复键要到 build 阶段才炸,analyze 不报。 + +用法(都在 apps/client 下执行): + + python3 tools/i18n_fill_missing.py --report # 每个语言缺哪些 / 多哪些 key + python3 tools/i18n_fill_missing.py --dump-missing DIR # 把缺失 key 按语言写成 DIR/.json(key → 英文原文) + python3 tools/i18n_fill_missing.py --apply DIR # 读 DIR/.json(key → 译文)追加到各语言文件末尾 + python3 tools/i18n_fill_missing.py --apply DIR --fallback-en # 译文文件里没有的 key 用英文原文补上 + +--apply 只追加**真正缺失**的 key(两种引号都查过),已有的一律不动;多余 key(enUS 没有的)只打印清单,不删。 +译文里的占位符(@name / %s / {0} / \\n)会与英文原文比对,不一致的 key 会拒绝写入并列出来。 +""" + +from __future__ import annotations + +import argparse +import glob +import json +import os +import re +import sys + +LANG_DIR = os.path.join("lib", "core", "translations", "language") +BASELINE = "en_us.dart" + +# 一条 entry:key 字面量 + 冒号 + 一个或多个相邻字符串字面量(Dart 相邻字符串会拼接) +_STR = r"""(?:'(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*")""" +_ENTRY_RE = re.compile( + r"^[ \t]*(?P" + _STR + r")\s*:\s*(?P(?:" + _STR + r"\s*)+),", + re.M, +) +_KEY_RE = re.compile(r"^[ \t]*(['\"])((?:\\.|(?!\1).)*)\1\s*:", re.M) +_PLACEHOLDER_RE = re.compile(r"@\w+|%[sd]|\{\w+\}|\n") + + +def _unquote(lit: str) -> str: + """把一个 Dart 字符串字面量还原成值(处理 \\' \\" \\\\ \\n \\t \\$ \\uXXXX)。""" + body = lit[1:-1] + out: list[str] = [] + i = 0 + while i < len(body): + ch = body[i] + if ch == "\\" and i + 1 < len(body): + nxt = body[i + 1] + if nxt == "u": + # \uXXXX 或 \u{X...} + if i + 2 < len(body) and body[i + 2] == "{": + j = body.index("}", i + 3) + out.append(chr(int(body[i + 3 : j], 16))) + i = j + 1 + else: + out.append(chr(int(body[i + 2 : i + 6], 16))) + i += 6 + continue + out.append({"n": "\n", "t": "\t"}.get(nxt, nxt)) + i += 2 + continue + out.append(ch) + i += 1 + return "".join(out) + + +def _quote(value: str) -> str: + """把值写成单引号 Dart 字面量;`$` 要转义,否则被当成插值。""" + s = ( + value.replace("\\", "\\\\") + .replace("'", "\\'") + .replace("$", "\\$") + .replace("\n", "\\n") + .replace("\t", "\\t") + ) + return f"'{s}'" + + +def parse_file(path: str) -> tuple[dict[str, str], list[str]]: + """返回 (key → 值, 重复出现的 key 列表)。两种引号的 key 一起算。""" + with open(path, encoding="utf-8") as f: + text = f.read() + values: dict[str, str] = {} + seen: dict[str, int] = {} + for m in _ENTRY_RE.finditer(text): + key = _unquote(m.group("key")) + parts = re.findall(_STR, m.group("val")) + values[key] = "".join(_unquote(p) for p in parts) + seen[key] = seen.get(key, 0) + 1 + # _ENTRY_RE 只认值是字符串字面量的行;再用纯 key 正则兜一遍,防止漏掉写法怪异的行 + for m in _KEY_RE.finditer(text): + key = _unquote(m.group(1) + m.group(2) + m.group(1)) + if key not in seen: + seen[key] = 1 + values.setdefault(key, "") + dups = sorted(k for k, n in seen.items() if n > 1) + return values, dups + + +def placeholders(s: str) -> list[str]: + return sorted(_PLACEHOLDER_RE.findall(s)) + + +def lang_files() -> list[str]: + return sorted( + p for p in glob.glob(os.path.join(LANG_DIR, "*.dart")) if os.path.basename(p) != BASELINE + ) + + +def lang_name(path: str) -> str: + return os.path.splitext(os.path.basename(path))[0] + + +def append_entries(path: str, entries: list[tuple[str, str]]) -> None: + with open(path, encoding="utf-8") as f: + text = f.read() + end = text.rfind("};") + if end == -1: + raise SystemExit(f"{path}: 找不到 map 结尾 '}};'") + block = "".join(f" {_quote(k)}: {_quote(v)},\n" for k, v in entries) + before = text[:end] + if not before.endswith("\n"): + before += "\n" + with open(path, "w", encoding="utf-8") as f: + f.write(before + block + text[end:]) + + +def main() -> int: + ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument("--report", action="store_true", help="只输出每个语言缺失/多余 key 的统计") + ap.add_argument("--dump-missing", metavar="DIR", help="把缺失 key(key → 英文原文)按语言写到 DIR/.json") + ap.add_argument("--apply", metavar="DIR", help="读 DIR/.json(key → 译文)追加到语言文件") + ap.add_argument("--fallback-en", action="store_true", help="--apply 时译文缺的 key 用英文原文补上") + ap.add_argument("--only", nargs="*", help="只处理这些语言(如 es_es fr_fr)") + args = ap.parse_args() + + base_path = os.path.join(LANG_DIR, BASELINE) + base, base_dups = parse_file(base_path) + if base_dups: + print(f"[警告] {BASELINE} 自身有重复 key: {base_dups}") + print(f"{BASELINE}: {len(base)} keys") + + files = lang_files() + if args.only: + files = [p for p in files if lang_name(p) in set(args.only)] + + total_added = 0 + english_kept: dict[str, list[str]] = {} + rejected: dict[str, list[str]] = {} + extras_all: dict[str, list[str]] = {} + + for path in files: + lang = lang_name(path) + cur, dups = parse_file(path) + if dups: + print(f"[警告] {lang}: 文件内已有重复 key: {dups}") + missing = [k for k in base if k not in cur] + extra = [k for k in cur if k not in base] + if extra: + extras_all[lang] = extra + + if args.report or (not args.dump_missing and not args.apply): + print(f"{lang}: {len(cur)} keys, 缺 {len(missing)}, 多 {len(extra)}") + continue + + if args.dump_missing: + os.makedirs(args.dump_missing, exist_ok=True) + with open(os.path.join(args.dump_missing, f"{lang}.json"), "w", encoding="utf-8") as f: + json.dump({k: base[k] for k in missing}, f, ensure_ascii=False, indent=2) + print(f"{lang}: 写出 {len(missing)} 个缺失 key") + continue + + if args.apply: + tpath = os.path.join(args.apply, f"{lang}.json") + trans: dict[str, str] = {} + if os.path.exists(tpath): + with open(tpath, encoding="utf-8") as f: + trans = json.load(f) + entries: list[tuple[str, str]] = [] + for k in missing: + v = trans.get(k) + if v is None or not str(v).strip(): + if not args.fallback_en: + rejected.setdefault(lang, []).append(f"{k} (无译文)") + continue + v = base[k] + v = str(v) + if placeholders(v) != placeholders(base[k]): + rejected.setdefault(lang, []).append( + f"{k} (占位符不一致: {placeholders(v)} vs {placeholders(base[k])})" + ) + continue + if v == base[k] and re.search(r"[A-Za-z]{3,}", v): + english_kept.setdefault(lang, []).append(k) + entries.append((k, v)) + if entries: + append_entries(path, entries) + total_added += len(entries) + print(f"{lang}: 追加 {len(entries)} 个 key" + (f",跳过 {len(rejected.get(lang, []))}" if lang in rejected else "")) + + if extras_all: + print("\n== enUS 没有、语言文件多出来的 key(未删除,仅列出)==") + for lang, ks in extras_all.items(): + print(f"{lang} ({len(ks)}): {', '.join(ks)}") + if rejected: + print("\n== 未写入的 key ==") + for lang, ks in rejected.items(): + for k in ks: + print(f"{lang}: {k}") + if english_kept: + print("\n== 与英文原文相同(保留英文)的 key ==") + for lang, ks in english_kept.items(): + print(f"{lang} ({len(ks)}): {', '.join(ks)}") + if args.apply: + print(f"\n共追加 {total_added} 条") + return 1 if rejected else 0 + + +if __name__ == "__main__": + sys.exit(main())

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