Compare commits

...

68 Commits

Author SHA1 Message Date
279b329a1e Merge branch 'develop_sky_liyi' into 'develop_sky'
fix: 调整插件版本

See merge request StarlockTeam/app-starlock!285
2025-09-22 07:35:42 +00:00
30283fe513 fix: 调整插件版本 2025-09-22 15:35:15 +08:00
8728c4f697 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix: 调整插件版本

See merge request StarlockTeam/app-starlock!284
2025-09-22 07:29:21 +00:00
766dd88770 fix: 调整插件版本 2025-09-22 15:27:45 +08:00
5118aed3ca Merge branch 'develop_sky_liyi' into 'develop_sky'
fix: 调整开锁在同步数据完成之后断开连接

See merge request StarlockTeam/app-starlock!283
2025-09-22 07:03:09 +00:00
987fd4770a fix: 调整开锁在同步数据完成之后断开连接 2025-09-22 15:01:44 +08:00
3df6716abb Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!281
2025-09-19 03:03:14 +00:00
adf1cf3f1c fix: 修复已配对的设备还能搜索到的问题 2025-09-19 10:20:39 +08:00
cfde51c063 fix: 修复设置语音包后等待几秒后出现操作失败的问题 2025-09-19 10:20:23 +08:00
8fd1dac254 fix: 更新国际化文本 2025-09-17 09:43:26 +08:00
7feb282f13 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!277
2025-09-15 01:17:34 +00:00
1b611ca9de Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整mtu设置

See merge request StarlockTeam/app-starlock!273
2025-09-04 09:04:53 +00:00
fe13b0c2e0 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:兼容没有新增读取、设置语音包协议的锁板

See merge request StarlockTeam/app-starlock!270
2025-09-03 09:08:19 +00:00
2347ba871f Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:增加和读取锁板上的语音包设置

See merge request StarlockTeam/app-starlock!268
2025-09-01 06:31:07 +00:00
fbbf68c840 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整语音设置

See merge request StarlockTeam/app-starlock!266
2025-09-01 01:32:41 +00:00
e126dd60fc Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整录音时不播放声音

See merge request StarlockTeam/app-starlock!264
2025-08-29 05:41:20 +00:00
bfc6363957 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!262
2025-08-28 06:00:48 +00:00
6496741144 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整音频结束时继续发送为0的音频包,而不是立即中断

See merge request StarlockTeam/app-starlock!260
2025-08-26 07:29:32 +00:00
c4c82ea8f8 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!258
2025-08-26 03:34:52 +00:00
52f3ce64a4 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!256
2025-08-22 05:36:56 +00:00
832c72df4a Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!253
2025-08-20 06:29:43 +00:00
94b314ddc5 fix:调整依赖,为了修复ci的构建失败 2025-08-12 11:12:25 +08:00
7fe97666e5 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整依赖,为了修复ci的构建失败

See merge request StarlockTeam/app-starlock!250
2025-08-12 02:54:52 +00:00
5c209b985d 删除pubspec.lock 2025-08-12 02:48:23 +00:00
7048235138 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整依赖,为了修复ci的构建失败

See merge request StarlockTeam/app-starlock!249
2025-08-12 02:39:46 +00:00
4a80acf9e1 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整依赖,为了修复ci的构建失败

See merge request StarlockTeam/app-starlock!248
2025-08-12 02:25:20 +00:00
21fbf62a8f Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!247
2025-08-12 01:41:45 +00:00
84be5b7617 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!243
2025-08-08 01:59:52 +00:00
c954ee6918 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!240
2025-08-05 07:24:39 +00:00
3957701172 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!239
2025-08-04 03:00:37 +00:00
c80a5c8533 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整版本号

See merge request StarlockTeam/app-starlock!236
2025-07-30 03:25:11 +00:00
e0bd9a678c Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整版本号

See merge request StarlockTeam/app-starlock!233
2025-07-30 02:57:57 +00:00
8ce3952a64 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整版本号

See merge request StarlockTeam/app-starlock!230
2025-07-30 02:49:28 +00:00
917dfbba91 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!226
2025-07-29 06:00:53 +00:00
43c4e703b9 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!225
2025-07-29 05:51:07 +00:00
3b12069a01 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!222
2025-07-26 08:13:58 +00:00
92a2407fb4 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!219
2025-07-25 07:03:55 +00:00
41c4623876 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!216
2025-07-23 03:38:22 +00:00
768f7fd38f Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!213
2025-07-23 01:55:25 +00:00
f09e0bf329 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!198
2025-07-09 03:36:58 +00:00
5e14f217ea Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整VoIP上报的结构

See merge request StarlockTeam/app-starlock!194
2025-07-03 09:12:21 +00:00
41fdae21f8 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整ios编译宏

See merge request StarlockTeam/app-starlock!192
2025-07-03 07:23:14 +00:00
38391a4f12 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整ios编译宏

See merge request StarlockTeam/app-starlock!190
2025-07-03 06:43:12 +00:00
2956b25d54 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:增加国内环境下不上报VoIP;调整Fastlin中的环境

See merge request StarlockTeam/app-starlock!188
2025-07-03 03:31:52 +00:00
c7c1730cb0 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!186
2025-07-02 09:14:39 +00:00
822bf89a2c Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整ios解码流程

See merge request StarlockTeam/app-starlock!183
2025-06-26 01:41:33 +00:00
61b7041e71 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!182
2025-06-25 10:51:05 +00:00
a98fc0b905 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整解码插件版本、静态资源目录

See merge request StarlockTeam/app-starlock!178
2025-06-23 08:17:47 +00:00
c033cb9608 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整解码插件版本、静态资源目录

See merge request StarlockTeam/app-starlock!177
2025-06-23 08:11:42 +00:00
954cfc6276 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!176
2025-06-23 08:01:39 +00:00
dfccfa9089 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:将接收udp数据改为Isolate,主线程解耦udp数据接收

See merge request StarlockTeam/app-starlock!175
2025-06-18 10:03:04 +00:00
6385a2c7b9 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!174
2025-06-18 07:18:48 +00:00
9edb18deb5 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:(判断联网)调整判断网络状态方式调整

See merge request StarlockTeam/app-starlock!167
2025-06-13 06:17:43 +00:00
c9b5de847d Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!164
2025-06-12 09:53:14 +00:00
11958ea87c Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!163
2025-06-12 08:37:02 +00:00
002c8252d6 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:(密码)修复点击重置后不弹窗的问题

See merge request StarlockTeam/app-starlock!161
2025-06-12 01:39:06 +00:00
0ffde21dda Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!159
2025-06-11 01:19:37 +00:00
9623c542b5 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!157
2025-06-09 06:32:49 +00:00
17510c03ca Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!154
2025-06-06 05:56:51 +00:00
58e0bdeef4 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:切换rubygems镜像为阿里云镜像

See merge request StarlockTeam/app-starlock!153
2025-06-06 04:01:38 +00:00
7e992183f5 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:修复setup_fastlane_ios中使用了错误的目录位置

See merge request StarlockTeam/app-starlock!152
2025-06-06 01:46:51 +00:00
f6d6814e72 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:区分Android和ios的构建时的依赖目录

See merge request StarlockTeam/app-starlock!151
2025-06-06 01:39:46 +00:00
d9235bd81f Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整ci流程

See merge request StarlockTeam/app-starlock!150
2025-06-06 01:21:30 +00:00
16d62698c6 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整ci流程

See merge request StarlockTeam/app-starlock!149
2025-06-06 01:18:29 +00:00
12b29534f7 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整FCM版本

See merge request StarlockTeam/app-starlock!146
2025-06-06 01:05:11 +00:00
06a38603f7 Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:增加ci时的flutter依赖镜像源为国内镜像源

See merge request StarlockTeam/app-starlock!143
2025-06-05 03:27:03 +00:00
7d4e18f7b1 Merge branch 'develop_sky_liyi' into 'develop_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!142
2025-06-05 02:55:31 +00:00
c30c16897a Merge branch 'develop_sky_liyi' into 'develop_sky'
fix:调整ci流程,只保留sky的flavor构建

See merge request StarlockTeam/app-starlock!138
2025-06-04 07:02:50 +00:00
49 changed files with 307 additions and 2161 deletions

View File

@ -1166,5 +1166,6 @@
"云存会员": "عضوية التخزين السحابي", "云存会员": "عضوية التخزين السحابي",
"服务,图像视频信息随心存!": "معلومات الخدمة والصور والفيديو في قلبك!", "服务,图像视频信息随心存!": "معلومات الخدمة والصور والفيديو في قلبك!",
"图像": "صورة", "图像": "صورة",
"视频": "فيديو" "视频": "فيديو",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "حاليا ، لا تدعم الدولة تسجيل رمز التحقق من الهاتف المحمول ، يرجى استخدام عنوان بريدك الإلكتروني للتسجيل"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Членство в Cloud Storage", "云存会员": "Членство в Cloud Storage",
"服务,图像视频信息随心存!": "Информацията за обслужване, изображения и видео са във вашето сърце!", "服务,图像视频信息随心存!": "Информацията за обслужване, изображения и видео са във вашето сърце!",
"图像": "изображение", "图像": "изображение",
"视频": "Видео" "视频": "Видео",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "В момента страната не поддържа регистрация на код за потвърждение на мобилен телефон, моля, използвайте имейл адреса си, за да се регистрирате"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "ক্লাউড স্টোরেজ সদস্যতা", "云存会员": "ক্লাউড স্টোরেজ সদস্যতা",
"服务,图像视频信息随心存!": "পরিষেবা, চিত্র এবং ভিডিও তথ্য আপনার হৃদয়ে!", "服务,图像视频信息随心存!": "পরিষেবা, চিত্র এবং ভিডিও তথ্য আপনার হৃদয়ে!",
"图像": "প্রতিচ্ছবি", "图像": "প্রতিচ্ছবি",
"视频": "ভিডিও" "视频": "ভিডিও",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "বর্তমানে, দেশটি মোবাইল ফোন যাচাইকরণ কোড নিবন্ধন সমর্থন করে না, নিবন্ধন করতে দয়া করে আপনার ইমেল ঠিকানা ব্যবহার করুন"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Členství v cloudovém úložišti", "云存会员": "Členství v cloudovém úložišti",
"服务,图像视频信息随心存!": "Servis, obrazové a video informace jsou na prvním místě!", "服务,图像视频信息随心存!": "Servis, obrazové a video informace jsou na prvním místě!",
"图像": "obraz", "图像": "obraz",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "V současné době země nepodporuje registraci ověřovacího kódu mobilního telefonu, k registraci použijte prosím svou e-mailovou adresu"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Medlemskab af Cloud Storage", "云存会员": "Medlemskab af Cloud Storage",
"服务,图像视频信息随心存!": "Service-, billed- og videoinformation er i dit hjerte!", "服务,图像视频信息随心存!": "Service-, billed- og videoinformation er i dit hjerte!",
"图像": "billede", "图像": "billede",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "I øjeblikket understøtter landet ikke registrering af mobiltelefonbekræftelseskode, brug venligst din e-mailadresse til at tilmelde dig"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Cloud-Speicher-Mitgliedschaft", "云存会员": "Cloud-Speicher-Mitgliedschaft",
"服务,图像视频信息随心存!": "Service-, Bild- und Videoinformationen liegen Ihnen am Herzen!", "服务,图像视频信息随心存!": "Service-, Bild- und Videoinformationen liegen Ihnen am Herzen!",
"图像": "Bild", "图像": "Bild",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Derzeit unterstützt das Land die Registrierung von Verifizierungscodes für Mobiltelefone nicht, bitte verwenden Sie Ihre E-Mail-Adresse, um sich zu registrieren"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Συνδρομή Cloud Storage", "云存会员": "Συνδρομή Cloud Storage",
"服务,图像视频信息随心存!": "Οι πληροφορίες εξυπηρέτησης, εικόνας και βίντεο είναι στην καρδιά σας!", "服务,图像视频信息随心存!": "Οι πληροφορίες εξυπηρέτησης, εικόνας και βίντεο είναι στην καρδιά σας!",
"图像": "εικόνα", "图像": "εικόνα",
"视频": "Βίντεο" "视频": "Βίντεο",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Προς το παρόν, η χώρα δεν υποστηρίζει την εγγραφή κωδικού επαλήθευσης κινητού τηλεφώνου, χρησιμοποιήστε τη διεύθυνση email σας για να εγγραφείτε"
} }

View File

@ -1173,5 +1173,6 @@
"云存会员": "Cloud Storage Membership", "云存会员": "Cloud Storage Membership",
"服务,图像视频信息随心存!": "Service, image and video information are at your heart!", "服务,图像视频信息随心存!": "Service, image and video information are at your heart!",
"图像": "image", "图像": "image",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Currently, the country does not support mobile phone verification code registration, please use your email address to register"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Membresía de almacenamiento en la nube", "云存会员": "Membresía de almacenamiento en la nube",
"服务,图像视频信息随心存!": "¡La información de servicio, imagen y video está en su corazón!", "服务,图像视频信息随心存!": "¡La información de servicio, imagen y video está en su corazón!",
"图像": "imagen", "图像": "imagen",
"视频": "Vídeo" "视频": "Vídeo",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Actualmente, el país no admite el registro de códigos de verificación de teléfonos móviles, utilice su dirección de correo electrónico para registrarse"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Pilvesalvestuse liikmelisus", "云存会员": "Pilvesalvestuse liikmelisus",
"服务,图像视频信息随心存!": "Teenindus-, pildi- ja videoteave on teie südames!", "服务,图像视频信息随心存!": "Teenindus-, pildi- ja videoteave on teie südames!",
"图像": "Piltide", "图像": "Piltide",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Praegu ei toeta riik mobiiltelefoni kinnituskoodi registreerimist, palun kasutage registreerumiseks oma e-posti aadressi"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Pilvitallennustilan jäsenyys", "云存会员": "Pilvitallennustilan jäsenyys",
"服务,图像视频信息随心存!": "Palvelu-, kuva- ja videotiedot ovat sydämessäsi!", "服务,图像视频信息随心存!": "Palvelu-, kuva- ja videotiedot ovat sydämessäsi!",
"图像": "kuva", "图像": "kuva",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Tällä hetkellä maa ei tue matkapuhelimen vahvistuskoodin rekisteröintiä, käytä rekisteröitymiseen sähköpostiosoitettasi"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Adhésion au stockage dans le cloud", "云存会员": "Adhésion au stockage dans le cloud",
"服务,图像视频信息随心存!": "Le service, limage et les informations vidéo sont au cœur de vos préoccupations !", "服务,图像视频信息随心存!": "Le service, limage et les informations vidéo sont au cœur de vos préoccupations !",
"图像": "image", "图像": "image",
"视频": "Vidéo" "视频": "Vidéo",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Actuellement, le pays ne prend pas en charge lenregistrement du code de vérification du téléphone portable, veuillez utiliser votre adresse e-mail pour vous inscrire"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "חברות באחסון בענן", "云存会员": "חברות באחסון בענן",
"服务,图像视频信息随心存!": "מידע על שירות, תמונה ווידאו נמצאים בלב שלך!", "服务,图像视频信息随心存!": "מידע על שירות, תמונה ווידאו נמצאים בלב שלך!",
"图像": "תמונה", "图像": "תמונה",
"视频": "וידאו" "视频": "וידאו",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "נכון לעכשיו, המדינה אינה תומכת ברישום קוד אימות טלפון נייד, אנא השתמש בכתובת הדוא\"ל שלך כדי להירשם"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "क्लाउड स्टोरेज सदस्यता", "云存会员": "क्लाउड स्टोरेज सदस्यता",
"服务,图像视频信息随心存!": "सेवा, छवि और वीडियो जानकारी आपके दिल में हैं!", "服务,图像视频信息随心存!": "सेवा, छवि और वीडियो जानकारी आपके दिल में हैं!",
"图像": "प्रतिबिंब", "图像": "प्रतिबिंब",
"视频": "वीडियो" "视频": "वीडियो",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "वर्तमान में, देश मोबाइल फोन सत्यापन कोड पंजीकरण का समर्थन नहीं करता है, कृपया पंजीकरण करने के लिए अपने ईमेल पते का उपयोग करें"
} }

View File

@ -1168,5 +1168,6 @@
"云存会员": "雲存會員", "云存会员": "雲存會員",
"服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!", "服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!",
"图像": "圖像", "图像": "圖像",
"视频": "視頻" "视频": "視頻",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "當前國家不支援手機驗證碼註冊,請使用郵箱進行註冊"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Članstvo u pohrani u oblaku", "云存会员": "Članstvo u pohrani u oblaku",
"服务,图像视频信息随心存!": "Informacije o usluzi, slikama i videozapisima su vam u srcu!", "服务,图像视频信息随心存!": "Informacije o usluzi, slikama i videozapisima su vam u srcu!",
"图像": "slika", "图像": "slika",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Trenutno zemlja ne podržava registraciju koda za provjeru mobilnog telefona, za registraciju koristite svoju adresu e-pošte"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Felhőalapú tárolási tagság", "云存会员": "Felhőalapú tárolási tagság",
"服务,图像视频信息随心存!": "A szolgáltatás, a képi és videós információk a szívedben vannak!", "服务,图像视频信息随心存!": "A szolgáltatás, a képi és videós információk a szívedben vannak!",
"图像": "kép", "图像": "kép",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Jelenleg az ország nem támogatja a mobiltelefonos ellenőrző kód regisztrációját, kérjük, használja e-mail címét a regisztrációhoz"
} }

View File

@ -1173,5 +1173,6 @@
"云存会员": "Cloud Storage Membership", "云存会员": "Cloud Storage Membership",
"服务,图像视频信息随心存!": "Ծառայությունը, պատկերը եւ վիդեո տեղեկատվությունը ձեր սրտում են:", "服务,图像视频信息随心存!": "Ծառայությունը, պատկերը եւ վիդեո տեղեկատվությունը ձեր սրտում են:",
"图像": "Պատկերասրահ", "图像": "Պատկերասրահ",
"视频": "Տեսանյութ" "视频": "Տեսանյութ",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Ներկայումս երկիրը չի աջակցում բջջային հեռախոսի ստուգման կոդի գրանցմանը, խնդրում ենք գրանցվելու համար օգտագործել ձեր էլ. փոստի հասցեն"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Keanggotaan Cloud Storage", "云存会员": "Keanggotaan Cloud Storage",
"服务,图像视频信息随心存!": "Informasi layanan, gambar, dan video adalah inti Anda!", "服务,图像视频信息随心存!": "Informasi layanan, gambar, dan video adalah inti Anda!",
"图像": "citra", "图像": "citra",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Saat ini, negara tersebut tidak mendukung pendaftaran kode verifikasi ponsel, silakan gunakan alamat email Anda untuk mendaftar"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Iscrizione al cloud storage", "云存会员": "Iscrizione al cloud storage",
"服务,图像视频信息随心存!": "Le informazioni sul servizio, le immagini e i video sono al tuo centro!", "服务,图像视频信息随心存!": "Le informazioni sul servizio, le immagini e i video sono al tuo centro!",
"图像": "immagine", "图像": "immagine",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Attualmente, il paese non supporta la registrazione del codice di verifica del telefono cellulare, si prega di utilizzare il proprio indirizzo e-mail per registrarsi"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "クラウドストレージメンバーシップ", "云存会员": "クラウドストレージメンバーシップ",
"服务,图像视频信息随心存!": "サービス、画像、ビデオ情報があなたの中心にあります!", "服务,图像视频信息随心存!": "サービス、画像、ビデオ情報があなたの中心にあります!",
"图像": "画像", "图像": "画像",
"视频": "ビデオ" "视频": "ビデオ",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "現在、この国は携帯電話の認証コード登録をサポートしていませんので、メールアドレスを使用して登録してください"
} }

View File

@ -1173,5 +1173,6 @@
"云存会员": "Cloud Storage წევრობა", "云存会员": "Cloud Storage წევრობა",
"服务,图像视频信息随心存!": "მომსახურება, სურათი და ვიდეო ინფორმაცია თქვენს გულშია!", "服务,图像视频信息随心存!": "მომსახურება, სურათი და ვიდეო ინფორმაცია თქვენს გულშია!",
"图像": "სურათი", "图像": "სურათი",
"视频": "ვიდეო" "视频": "ვიდეო",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "ამჟამად, ქვეყანა არ უჭერს მხარს მობილური ტელეფონის დამადასტურებელი კოდის რეგისტრაციას, გთხოვთ გამოიყენოთ თქვენი ელექტრონული ფოსტის მისამართი რეგისტრაციისთვის"
} }

View File

@ -1178,5 +1178,6 @@
"云存会员": "云存会员", "云存会员": "云存会员",
"服务,图像视频信息随心存!": "服务,图像视频信息随心存!", "服务,图像视频信息随心存!": "服务,图像视频信息随心存!",
"图像": "图像", "图像": "图像",
"视频": "视频" "视频": "视频",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "当前国家不支持手机验证码注册,请使用邮箱进行注册"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Бұлтты сақтауға мүшелік", "云存会员": "Бұлтты сақтауға мүшелік",
"服务,图像视频信息随心存!": "Қызмет, бейне және бейне ақпарат сіздің жүрегіңізде жатыр!", "服务,图像视频信息随心存!": "Қызмет, бейне және бейне ақпарат сіздің жүрегіңізде жатыр!",
"图像": "кескіні", "图像": "кескіні",
"视频": "Бейне" "视频": "Бейне",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Қазіргі уақытта елде ұялы телефонды растау кодын тіркеуді қолдамайды, тіркелу үшін электрондық пошта мекенжайыңызды пайдаланыңыз"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "클라우드 스토리지 멤버십", "云存会员": "클라우드 스토리지 멤버십",
"服务,图像视频信息随心存!": "서비스, 이미지 및 비디오 정보가 당신의 중심에 있습니다!", "服务,图像视频信息随心存!": "서비스, 이미지 및 비디오 정보가 당신의 중심에 있습니다!",
"图像": "이미지", "图像": "이미지",
"视频": "비디오" "视频": "비디오",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "현재 해당 국가는 휴대폰 인증코드 등록을 지원하지 않으니 이메일 주소를 사용하여 등록하세요."
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Debesies saugyklos narystė", "云存会员": "Debesies saugyklos narystė",
"服务,图像视频信息随心存!": "Aptarnavimas, vaizdas ir video informacija yra jūsų širdis!", "服务,图像视频信息随心存!": "Aptarnavimas, vaizdas ir video informacija yra jūsų širdis!",
"图像": "vaizdas", "图像": "vaizdas",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Šiuo metu šalis nepalaiko mobiliojo telefono patvirtinimo kodo registracijos, registruodamiesi naudokite savo el. pašto adresą"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Keahlian Storan Awan", "云存会员": "Keahlian Storan Awan",
"服务,图像视频信息随心存!": "Maklumat perkhidmatan, imej dan video adalah di hati anda!", "服务,图像视频信息随心存!": "Maklumat perkhidmatan, imej dan video adalah di hati anda!",
"图像": "Imej", "图像": "Imej",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Pada masa ini, negara ini tidak menyokong pendaftaran kod pengesahan telefon bimbit, sila gunakan alamat e-mel anda untuk mendaftar"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Lidmaatschap voor cloudopslag", "云存会员": "Lidmaatschap voor cloudopslag",
"服务,图像视频信息随心存!": "Service-, beeld- en video-informatie staan bij u centraal!", "服务,图像视频信息随心存!": "Service-, beeld- en video-informatie staan bij u centraal!",
"图像": "beeld", "图像": "beeld",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Momenteel ondersteunt het land de registratie van de verificatiecode voor mobiele telefoons niet, gebruik uw e-mailadres om u te registreren"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Członkostwo w usłudze Cloud Storage", "云存会员": "Członkostwo w usłudze Cloud Storage",
"服务,图像视频信息随心存!": "Informacje o serwisie, obrazie i wideo są w Twoim sercu!", "服务,图像视频信息随心存!": "Informacje o serwisie, obrazie i wideo są w Twoim sercu!",
"图像": "obraz", "图像": "obraz",
"视频": "Wideo" "视频": "Wideo",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Obecnie kraj nie obsługuje rejestracji kodem weryfikacyjnym telefonu komórkowego, użyj swojego adresu e-mail, aby się zarejestrować"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Associação de armazenamento em nuvem", "云存会员": "Associação de armazenamento em nuvem",
"服务,图像视频信息随心存!": "Informações de serviço, imagem e vídeo estão no seu coração!", "服务,图像视频信息随心存!": "Informações de serviço, imagem e vídeo estão no seu coração!",
"图像": "imagem", "图像": "imagem",
"视频": "Vídeo" "视频": "Vídeo",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Atualmente, o país não suporta o registro do código de verificação do telefone celular, use seu endereço de e-mail para se registrar"
} }

View File

@ -1172,5 +1172,6 @@
"云存会员": "Associação de armazenamento em nuvem", "云存会员": "Associação de armazenamento em nuvem",
"服务,图像视频信息随心存!": "Informações de serviço, imagem e vídeo estão no seu coração!", "服务,图像视频信息随心存!": "Informações de serviço, imagem e vídeo estão no seu coração!",
"图像": "imagem", "图像": "imagem",
"视频": "Vídeo" "视频": "Vídeo",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Atualmente, o país não suporta o registro do código de verificação do telefone celular, use seu endereço de e-mail para se registrar"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Abonament de stocare în cloud", "云存会员": "Abonament de stocare în cloud",
"服务,图像视频信息随心存!": "Serviciile, imaginile și informațiile video sunt în centrul dumneavoastră!", "服务,图像视频信息随心存!": "Serviciile, imaginile și informațiile video sunt în centrul dumneavoastră!",
"图像": "imagine", "图像": "imagine",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "În prezent, țara nu acceptă înregistrarea codului de verificare a telefonului mobil, vă rugăm să utilizați adresa de e-mail pentru a vă înregistra"
} }

View File

@ -1171,5 +1171,6 @@
"云存会员": "Членство в облачном хранилище", "云存会员": "Членство в облачном хранилище",
"服务,图像视频信息随心存!": "Сервисная, имиджевая и видеоинформация в Вашем сердце!", "服务,图像视频信息随心存!": "Сервисная, имиджевая и видеоинформация в Вашем сердце!",
"图像": "образ", "图像": "образ",
"视频": "Видео" "视频": "Видео",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "В настоящее время страна не поддерживает регистрацию кода верификации мобильного телефона, пожалуйста, используйте свой адрес электронной почты для регистрации"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Členstvo v cloudovom úložisku", "云存会员": "Členstvo v cloudovom úložisku",
"服务,图像视频信息随心存!": "Informácie o službách, obrázkoch a videách sú vo vašom srdci!", "服务,图像视频信息随心存!": "Informácie o službách, obrázkoch a videách sú vo vašom srdci!",
"图像": "obraz", "图像": "obraz",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "V súčasnosti krajina nepodporuje registráciu overovacieho kódu mobilného telefónu, na registráciu použite svoju e-mailovú adresu"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Чланство у облаку за складиштење", "云存会员": "Чланство у облаку за складиштење",
"服务,图像视频信息随心存!": "Сервис , слике и видео информације су у вашем срцу!", "服务,图像视频信息随心存!": "Сервис , слике и видео информације су у вашем срцу!",
"图像": "Слика", "图像": "Слика",
"视频": "Пријава" "视频": "Пријава",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Тренутно , земља не подржава регистрацију кода за верификацију мобилног телефона, молимо вас да користите своју адресу е-поште за регистрацију"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Medlemskap i molnlagring", "云存会员": "Medlemskap i molnlagring",
"服务,图像视频信息随心存!": "Service, bild- och videoinformation finns i ditt hjärta!", "服务,图像视频信息随心存!": "Service, bild- och videoinformation finns i ditt hjärta!",
"图像": "bild", "图像": "bild",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "För närvarande stöder landet inte registrering av verifieringskoder för mobiltelefoner, använd din e-postadress för att registrera dig"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "สมาชิกที่เก็บข้อมูลบนคลาวด์", "云存会员": "สมาชิกที่เก็บข้อมูลบนคลาวด์",
"服务,图像视频信息随心存!": "ข้อมูลบริการ รูปภาพ และวิดีโออยู่ที่หัวใจของคุณ!", "服务,图像视频信息随心存!": "ข้อมูลบริการ รูปภาพ และวิดีโออยู่ที่หัวใจของคุณ!",
"图像": "ภาพ", "图像": "ภาพ",
"视频": "วีดิทัศน์" "视频": "วีดิทัศน์",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "ปัจจุบันประเทศไม่รองรับการลงทะเบียนรหัสยืนยันโทรศัพท์มือถือ โปรดใช้ที่อยู่อีเมลของคุณในการลงทะเบียน"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Bulut Depolama Üyeliği", "云存会员": "Bulut Depolama Üyeliği",
"服务,图像视频信息随心存!": "Servis, görüntü ve video bilgileri kalbinizde!", "服务,图像视频信息随心存!": "Servis, görüntü ve video bilgileri kalbinizde!",
"图像": "resim", "图像": "resim",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Şu anda ülke cep telefonu doğrulama kodu kaydını desteklememektedir, lütfen kaydolmak için e-posta adresinizi kullanın"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "雲存會員", "云存会员": "雲存會員",
"服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!", "服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!",
"图像": "圖像", "图像": "圖像",
"视频": "視頻" "视频": "視頻",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "當前國家不支援手機驗證碼註冊,請使用郵箱進行註冊"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Членство в хмарних сховищах", "云存会员": "Членство в хмарних сховищах",
"服务,图像视频信息随心存!": "Сервіс, зображення та відео інформація у вашому серці!", "服务,图像视频信息随心存!": "Сервіс, зображення та відео інформація у вашому серці!",
"图像": "образ", "图像": "образ",
"视频": "Відео" "视频": "Відео",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Наразі країна не підтримує реєстрацію коду підтвердження на мобільному телефоні, будь ласка, використовуйте свою адресу електронної пошти для реєстрації"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Cloud Storage Membership", "云存会员": "Cloud Storage Membership",
"服务,图像视频信息随心存!": "خدمت، تصویر اور ویڈیو کی معلومات آپ کے دل میں ہیں!", "服务,图像视频信息随心存!": "خدمت، تصویر اور ویڈیو کی معلومات آپ کے دل میں ہیں!",
"图像": "روپ", "图像": "روپ",
"视频": "ویڈیو" "视频": "ویڈیو",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "فی الحال، ملک موبائل فون کی توثیقی کوڈ رجسٹریشن کی حمایت نہیں کرتا ہے، براہ کرم رجسٹر کرنے کے لئے اپنا ای میل ایڈریس استعمال کریں"
} }

View File

@ -1167,5 +1167,6 @@
"云存会员": "Tư cách thành viên lưu trữ đám mây", "云存会员": "Tư cách thành viên lưu trữ đám mây",
"服务,图像视频信息随心存!": "Thông tin dịch vụ, hình ảnh và video là trọng tâm của bạn!", "服务,图像视频信息随心存!": "Thông tin dịch vụ, hình ảnh và video là trọng tâm của bạn!",
"图像": "ảnh", "图像": "ảnh",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Hiện tại, quốc gia này không hỗ trợ đăng ký mã xác minh điện thoại di động, vui lòng sử dụng địa chỉ email của bạn để đăng ký"
} }

View File

@ -1179,5 +1179,6 @@
"云存会员": "云存会员", "云存会员": "云存会员",
"服务,图像视频信息随心存!": "服务,图像视频信息随心存!", "服务,图像视频信息随心存!": "服务,图像视频信息随心存!",
"图像": "图像", "图像": "图像",
"视频": "视频" "视频": "视频",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "当前国家不支持手机验证码注册,请使用邮箱进行注册"
} }

View File

@ -16,8 +16,7 @@ import 'io_type.dart';
import 'reciver_data.dart'; import 'reciver_data.dart';
// //
typedef ConnectStateCallBack = Function( typedef ConnectStateCallBack = Function(BluetoothConnectionState connectionState);
BluetoothConnectionState connectionState);
typedef ScanDevicesCallBack = Function(List<ScanResult>); typedef ScanDevicesCallBack = Function(List<ScanResult>);
class BlueManage { class BlueManage {
@ -62,8 +61,7 @@ class BlueManage {
ScanResult? scanResult; ScanResult? scanResult;
// //
BluetoothConnectionState? bluetoothConnectionState = BluetoothConnectionState? bluetoothConnectionState = BluetoothConnectionState.disconnected;
BluetoothConnectionState.disconnected;
BluetoothAdapterState? _adapterState = BluetoothAdapterState.on; BluetoothAdapterState? _adapterState = BluetoothAdapterState.on;
StreamSubscription<BluetoothAdapterState>? _adapterStateStateSubscription; StreamSubscription<BluetoothAdapterState>? _adapterStateStateSubscription;
@ -103,7 +101,7 @@ class BlueManage {
// //
_mtuSubscription?.cancel(); _mtuSubscription?.cancel();
_mtuSubscription = null; _mtuSubscription = null;
_mtuSubscription = bluetoothConnectDevice!.mtu.listen((int value) { _mtuSubscription = bluetoothConnectDevice!.mtu.listen((int value) {
_mtuSize = value - 3; _mtuSize = value - 3;
AppLog.log('设备MTU变化 - 原始值:$value 计算后MTU:$_mtuSize 设备:${bluetoothConnectDevice?.remoteId.str}'); AppLog.log('设备MTU变化 - 原始值:$value 计算后MTU:$_mtuSize 设备:${bluetoothConnectDevice?.remoteId.str}');
@ -111,8 +109,7 @@ class BlueManage {
} }
void _initAdapterStateStateSubscription() { void _initAdapterStateStateSubscription() {
_adapterStateStateSubscription ??= _adapterStateStateSubscription ??= FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) {
FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) {
AppLog.log('蓝牙状态:$state'); AppLog.log('蓝牙状态:$state');
_adapterState = state; _adapterState = state;
}); });
@ -122,18 +119,15 @@ class BlueManage {
_connectionStateSubscription?.cancel(); _connectionStateSubscription?.cancel();
_connectionStateSubscription = null; _connectionStateSubscription = null;
_connectionStateSubscription = bluetoothConnectDevice!.connectionState _connectionStateSubscription =
.listen((BluetoothConnectionState state) async { bluetoothConnectDevice!.connectionState.listen((BluetoothConnectionState state) async {
bluetoothConnectionState = state; bluetoothConnectionState = state;
AppLog.log('蓝牙连接回调状态:$state'); AppLog.log('蓝牙连接回调状态:$state');
}); });
} }
void _initSendStreamSubscription() { void _initSendStreamSubscription() {
_sendStreamSubscription ??= EventBusManager() _sendStreamSubscription ??= EventBusManager().eventBus!.on<EventSendModel>().listen((EventSendModel model) {
.eventBus!
.on<EventSendModel>()
.listen((EventSendModel model) {
AppLog.log('eventBus接收发送数据:${model}'); AppLog.log('eventBus接收发送数据:${model}');
if (model.sendChannel == DataChannel.ble) { if (model.sendChannel == DataChannel.ble) {
FlutterBluePlus.isSupported.then((bool isAvailable) async { FlutterBluePlus.isSupported.then((bool isAvailable) async {
@ -158,8 +152,7 @@ class BlueManage {
} }
/// ///
Future<void> startScanSingle(String deviceName, int timeout, Future<void> startScanSingle(String deviceName, int timeout, ScanDevicesCallBack scanDevicesCallBack) async {
ScanDevicesCallBack scanDevicesCallBack) async {
final DateTime start = DateTime.now(); final DateTime start = DateTime.now();
FlutterBluePlus.isSupported.then((bool isAvailable) async { FlutterBluePlus.isSupported.then((bool isAvailable) async {
if (isAvailable) { if (isAvailable) {
@ -167,9 +160,7 @@ class BlueManage {
if (_adapterState == BluetoothAdapterState.on) { if (_adapterState == BluetoothAdapterState.on) {
try { try {
BuglyTool.uploadException( BuglyTool.uploadException(
message: '开始指定设备名称的扫描蓝牙设备', message: '开始指定设备名称的扫描蓝牙设备', detail: '调用方法是:startScanSingle 指定设备名称是:$deviceName', upload: false);
detail: '调用方法是:startScanSingle 指定设备名称是:$deviceName',
upload: false);
//android 3 //android 3
final int divisor = Platform.isAndroid ? 3 : 1; final int divisor = Platform.isAndroid ? 3 : 1;
FlutterBluePlus.startScan( FlutterBluePlus.startScan(
@ -181,12 +172,9 @@ class BlueManage {
final StreamSubscription<List<ScanResult>> subscription = final StreamSubscription<List<ScanResult>> subscription =
FlutterBluePlus.scanResults.listen((List<ScanResult> results) { FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
final bool isExit = results.any((ScanResult element) => final bool isExit = results.any((ScanResult element) =>
(element.device.platformName == deviceName) || (element.device.platformName == deviceName) || (element.advertisementData.advName == deviceName));
(element.advertisementData.advName == deviceName)); final int milliseconds = DateTime.now().millisecondsSinceEpoch - start.millisecondsSinceEpoch;
final int milliseconds = DateTime.now().millisecondsSinceEpoch - AppLog.log('扫描到的设备数:${results.length} 是否查找到 $isExit 以查找$milliseconds毫秒');
start.millisecondsSinceEpoch;
AppLog.log(
'扫描到的设备数:${results.length} 是否查找到 $isExit 以查找$milliseconds毫秒');
BuglyTool.uploadException( BuglyTool.uploadException(
message: '指定设备名称的扫描蓝牙设备 监听扫描结果', message: '指定设备名称的扫描蓝牙设备 监听扫描结果',
detail: detail:
@ -202,20 +190,15 @@ class BlueManage {
} }
final isMatch = _isMatch( final isMatch = _isMatch(
scanResult.advertisementData.serviceUuids scanResult.advertisementData.serviceUuids.map((e) => e.uuid).toList(),
.map((e) => e.uuid)
.toList(),
isSingle: true, isSingle: true,
); );
if (isMatch && (scanResult.rssi >= -100)) { if (isMatch && (scanResult.rssi >= -100)) {
// id相同的元素 // id相同的元素
final int knownDeviceIndex = scanDevices.indexWhere( final int knownDeviceIndex = scanDevices.indexWhere((ScanResult d) =>
(ScanResult d) => (d.device.platformName == scanResult.device.platformName) ||
(d.device.platformName == (d.advertisementData.advName == scanResult.advertisementData.advName));
scanResult.device.platformName) ||
(d.advertisementData.advName ==
scanResult.advertisementData.advName));
// -1 // -1
if (knownDeviceIndex >= 0) { if (knownDeviceIndex >= 0) {
scanDevices[knownDeviceIndex] = scanResult; scanDevices[knownDeviceIndex] = scanResult;
@ -224,8 +207,7 @@ class BlueManage {
} }
BuglyTool.uploadException( BuglyTool.uploadException(
message: '遍历扫描到的结果跟缓存的结果对比,如果有最新的就更新缓存', message: '遍历扫描到的结果跟缓存的结果对比,如果有最新的就更新缓存',
detail: detail: 'startScanSingle deviceName:$deviceName 查询到的结果scanResult:$scanResult',
'startScanSingle deviceName:$deviceName 查询到的结果scanResult:$scanResult',
upload: false); upload: false);
} }
} }
@ -234,9 +216,7 @@ class BlueManage {
} }
}, onError: (e) { }, onError: (e) {
BuglyTool.uploadException( BuglyTool.uploadException(
message: '指定设备名称的扫描蓝牙设备 监听扫描结果失败', message: '指定设备名称的扫描蓝牙设备 监听扫描结果失败', detail: '打印失败问题 e${e.toString()}', upload: false);
detail: '打印失败问题 e${e.toString()}',
upload: false);
AppLog.log('扫描失败:$e'); AppLog.log('扫描失败:$e');
}); });
FlutterBluePlus.cancelWhenScanComplete(subscription); FlutterBluePlus.cancelWhenScanComplete(subscription);
@ -245,9 +225,7 @@ class BlueManage {
subscription.cancel(); subscription.cancel();
} catch (e) { } catch (e) {
BuglyTool.uploadException( BuglyTool.uploadException(
message: '指定设备名称的扫描蓝牙设备 内部逻辑整形失败', message: '指定设备名称的扫描蓝牙设备 内部逻辑整形失败', detail: 'tartScanSingle内部逻辑整形失败 e:${e.toString()}', upload: false);
detail: 'tartScanSingle内部逻辑整形失败 e:${e.toString()}',
upload: false);
AppLog.log('扫描失败'); AppLog.log('扫描失败');
} }
} else { } else {
@ -264,12 +242,11 @@ class BlueManage {
} }
/// ///
Future<void> startScan(int timeout, DeviceType deviceType, Future<void> startScan(int timeout, DeviceType deviceType, ScanDevicesCallBack scanDevicesCallBack,
ScanDevicesCallBack scanDevicesCallBack,
{List<Guid>? idList}) async { {List<Guid>? idList}) async {
FlutterBluePlus.isSupported.then((bool isAvailable) async { FlutterBluePlus.isSupported.then((bool isAvailable) async {
if (isAvailable) { if (isAvailable) {
// AppLog.log('startScan 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState'); AppLog.log('startScan 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
if (_adapterState == BluetoothAdapterState.on) { if (_adapterState == BluetoothAdapterState.on) {
try { try {
FlutterBluePlus.startScan(timeout: Duration(seconds: timeout)); FlutterBluePlus.startScan(timeout: Duration(seconds: timeout));
@ -278,28 +255,23 @@ class BlueManage {
scanDevices.clear(); scanDevices.clear();
for (final ScanResult scanResult in results) { for (final ScanResult scanResult in results) {
if (scanResult.advertisementData.serviceUuids.isNotEmpty) { if (scanResult.advertisementData.serviceUuids.isNotEmpty) {
// AppLog.log( AppLog.log(
// '扫描到的设备:${scanResult.advertisementData.serviceUuids[0].toString()}====${scanResult.advertisementData.advName}'); '扫描到的设备:${scanResult.advertisementData.serviceUuids[0].toString()}====${scanResult.advertisementData.advName}');
} else { } else {
continue; continue;
} }
final isMatch = _isMatch( final isMatch = _isMatch(
scanResult.advertisementData.serviceUuids scanResult.advertisementData.serviceUuids.map((e) => e.uuid).toList(),
.map((e) => e.uuid)
.toList(),
deviceType: deviceType, deviceType: deviceType,
isSingle: false, isSingle: false,
); );
// //
if (isMatch && (scanResult.rssi >= -100)) { if (isMatch && (scanResult.rssi >= -100)) {
// id相同的元素 // id相同的元素
final int knownDeviceIndex = scanDevices.indexWhere( final int knownDeviceIndex = scanDevices.indexWhere((ScanResult d) =>
(ScanResult d) => (d.device.platformName == scanResult.device.platformName) ||
(d.device.platformName == (d.advertisementData.advName == scanResult.advertisementData.advName));
scanResult.device.platformName) ||
(d.advertisementData.advName ==
scanResult.advertisementData.advName));
// -1 // -1
if (knownDeviceIndex >= 0) { if (knownDeviceIndex >= 0) {
scanDevices[knownDeviceIndex] = scanResult; scanDevices[knownDeviceIndex] = scanResult;
@ -333,10 +305,8 @@ class BlueManage {
} }
/// uuid /// uuid
bool _isMatch(List<String> serviceUuids, bool _isMatch(List<String> serviceUuids, {DeviceType deviceType = DeviceType.blue, required bool isSingle}) {
{DeviceType deviceType = DeviceType.blue, required bool isSingle}) { final List<String> prefixes = getDeviceType(deviceType).map((e) => e.toLowerCase()).toList();
final List<String> prefixes =
getDeviceType(deviceType).map((e) => e.toLowerCase()).toList();
for (String uuid in serviceUuids) { for (String uuid in serviceUuids) {
final String cleanUuid = uuid.toLowerCase(); final String cleanUuid = uuid.toLowerCase();
if (cleanUuid.length == 8) { if (cleanUuid.length == 8) {
@ -367,8 +337,7 @@ class BlueManage {
} else { } else {
// UUID的第31321 // UUID的第31321
if (cleanUuid.length >= 32) { if (cleanUuid.length >= 32) {
String pairStatus = String pairStatus = cleanUuid.substring(30, 32); // 31321
cleanUuid.substring(30, 32); // 31321
// 00=01= // 00=01=
if (pairStatus == '00') { if (pairStatus == '00') {
return true; // true return true; // true
@ -386,12 +355,11 @@ class BlueManage {
// //
bool hasNewEvent = (byte1 == 1); bool hasNewEvent = (byte1 == 1);
// //
if (isPaired) { if (!isPaired) {
return true; // false return true; // true
} else { } else {
return false; // true return false; // false
} }
} }
// 01trueuuid // 01trueuuid
@ -408,8 +376,7 @@ class BlueManage {
} else { } else {
// UUID的第31321 // UUID的第31321
if (cleanUuid.length >= 32) { if (cleanUuid.length >= 32) {
String pairStatus = String pairStatus = cleanUuid.substring(30, 32); // 31321
cleanUuid.substring(30, 32); // 31321
// 00=01= // 00=01=
if (pairStatus == '00') { if (pairStatus == '00') {
return true; // true return true; // true
@ -428,8 +395,10 @@ class BlueManage {
/// List senderData, /// List senderData,
Future<void> blueSendData( Future<void> blueSendData(
String deviceName, ConnectStateCallBack stateCallBack, String deviceName,
{bool isAddEquipment = false}) async { ConnectStateCallBack stateCallBack, {
bool isAddEquipment = false,
}) async {
FlutterBluePlus.isSupported.then((bool isAvailable) async { FlutterBluePlus.isSupported.then((bool isAvailable) async {
if (isAvailable) { if (isAvailable) {
// AppLog.log('蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState'); // AppLog.log('蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
@ -438,12 +407,16 @@ class BlueManage {
if (bluetoothConnectionState != BluetoothConnectionState.connected) { if (bluetoothConnectionState != BluetoothConnectionState.connected) {
BuglyTool.uploadException( BuglyTool.uploadException(
message: '点击按钮 蓝牙未连接 下一步扫描连接蓝牙', message: '点击按钮 蓝牙未连接 下一步扫描连接蓝牙',
detail: detail: 'blueSendData 蓝牙连接状态 bluetoothConnectionState$bluetoothConnectionState deviceName:$deviceName',
'blueSendData 蓝牙连接状态 bluetoothConnectionState$bluetoothConnectionState deviceName:$deviceName',
upload: false); upload: false);
_connect(deviceName, (BluetoothConnectionState state) { //
stateCallBack(bluetoothConnectionState!); _connect(
}, isAddEquipment: isAddEquipment); deviceName,
(BluetoothConnectionState state) {
stateCallBack(bluetoothConnectionState!);
},
isAddEquipment: isAddEquipment,
);
} else { } else {
BuglyTool.uploadException( BuglyTool.uploadException(
message: '点击按钮 蓝牙已经连接 下一步扫描连接蓝牙', message: '点击按钮 蓝牙已经连接 下一步扫描连接蓝牙',
@ -455,8 +428,7 @@ class BlueManage {
} else { } else {
BuglyTool.uploadException( BuglyTool.uploadException(
message: '点击按钮 蓝牙未打开', message: '点击按钮 蓝牙未打开',
detail: detail: 'blueSendData 蓝牙未打开--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName',
'blueSendData 蓝牙未打开--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName',
upload: false); upload: false);
try { try {
stateCallBack(BluetoothConnectionState.disconnected); stateCallBack(BluetoothConnectionState.disconnected);
@ -465,16 +437,13 @@ class BlueManage {
AppLog.log('蓝牙打开失败'); AppLog.log('蓝牙打开失败');
BuglyTool.uploadException( BuglyTool.uploadException(
message: '点击按钮 蓝牙未打开 然后蓝牙打开失败', message: '点击按钮 蓝牙未打开 然后蓝牙打开失败',
detail: detail: 'blueSendData 蓝牙打开失败--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName',
'blueSendData 蓝牙打开失败--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName',
upload: false); upload: false);
} }
} }
} else { } else {
BuglyTool.uploadException( BuglyTool.uploadException(
message: '点击按钮 蓝牙状态不可用', message: '点击按钮 蓝牙状态不可用', detail: 'blueSendData 蓝牙状态不可用--isAvailable:$isAvailable', upload: false);
detail: 'blueSendData 蓝牙状态不可用--isAvailable:$isAvailable',
upload: false);
stateCallBack(BluetoothConnectionState.disconnected); stateCallBack(BluetoothConnectionState.disconnected);
AppLog.log('开始扫描 蓝牙不可用,不能进行蓝牙操作'); AppLog.log('开始扫描 蓝牙不可用,不能进行蓝牙操作');
} }
@ -482,8 +451,7 @@ class BlueManage {
} }
/// ///
Future<void> _connect( Future<void> _connect(String deviceName, ConnectStateCallBack connectStateCallBack,
String deviceName, ConnectStateCallBack connectStateCallBack,
{bool isAddEquipment = false}) async { {bool isAddEquipment = false}) async {
connectDeviceName = deviceName; connectDeviceName = deviceName;
// //
@ -491,16 +459,12 @@ class BlueManage {
// true是有缓存设备 // true是有缓存设备
final bool isExistDevice = isExistScanDevices(connectDeviceName); final bool isExistDevice = isExistScanDevices(connectDeviceName);
// //
final bool isCurrentDevice = final bool isCurrentDevice = CommonDataManage().currentKeyInfo.lockName == deviceName;
CommonDataManage().currentKeyInfo.lockName == deviceName;
// mac地址 // mac地址
final String? mac = CommonDataManage().currentKeyInfo.mac; final String? mac = CommonDataManage().currentKeyInfo.mac;
AppLog.log('开始连接 是否存在缓存:$isExistDevice 是否是当前设备:$isCurrentDevice mac$mac'); AppLog.log('开始连接 是否存在缓存:$isExistDevice 是否是当前设备:$isCurrentDevice mac$mac');
if (GetPlatform.isAndroid && if (GetPlatform.isAndroid && !isExistDevice && isCurrentDevice && mac != null) {
!isExistDevice &&
isCurrentDevice &&
mac != null) {
// mac地址不为空 // mac地址不为空
BuglyTool.uploadException( BuglyTool.uploadException(
message: '开始连接 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空 上传记录当前方法是_connect', message: '开始连接 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空 上传记录当前方法是_connect',
@ -512,22 +476,17 @@ class BlueManage {
try { try {
if (!needScanSingle) { if (!needScanSingle) {
BuglyTool.uploadException( BuglyTool.uploadException(
message: message: '开始连接 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空 上传记录当前方法是_connect',
'开始连接 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空 上传记录当前方法是_connect',
detail: '调用方法doNotSearchBLE直接连接,needScanSingle$needScanSingle', detail: '调用方法doNotSearchBLE直接连接,needScanSingle$needScanSingle',
upload: false); upload: false);
await doNotSearchBLE(mac, connectStateCallBack, await doNotSearchBLE(mac, connectStateCallBack, isAddEquipment: isAddEquipment);
isAddEquipment: isAddEquipment);
} else { } else {
BuglyTool.uploadException( BuglyTool.uploadException(
message: message: '开始连接 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空 上传记录当前方法是_connect',
'开始连接 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空 上传记录当前方法是_connect', detail: '调用方法startScanSingle执行扫描函数,needScanSingle$needScanSingle',
detail:
'调用方法startScanSingle执行扫描函数,needScanSingle$needScanSingle',
upload: false); upload: false);
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) { startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
_connectDevice(scanDevices, deviceName, connectStateCallBack, _connectDevice(scanDevices, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment);
isAddEquipment: isAddEquipment);
}); });
} }
} catch (e) { } catch (e) {
@ -536,8 +495,7 @@ class BlueManage {
detail: '调用方法doNotSearchBLE发生异常执行扫描函数 startScanSingle异常信息$e', detail: '调用方法doNotSearchBLE发生异常执行扫描函数 startScanSingle异常信息$e',
upload: false); upload: false);
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) { startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
_connectDevice(scanDevices, deviceName, connectStateCallBack, _connectDevice(scanDevices, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment);
isAddEquipment: isAddEquipment);
}); });
} }
// //
@ -554,16 +512,13 @@ class BlueManage {
} else if (isAddEquipment == false && isExistDevice == false) { } else if (isAddEquipment == false && isExistDevice == false) {
// 使 // 使
BuglyTool.uploadException( BuglyTool.uploadException(
message: message: '取消缓存直接使用,存在配对场景设备信息会更变 然后开始指定设备名称的扫描蓝牙设备 上传记录当前方法是_connect',
'取消缓存直接使用,存在配对场景设备信息会更变 然后开始指定设备名称的扫描蓝牙设备 上传记录当前方法是_connect', detail: '符合条件(isAddEquipment == false && isExistDevice == false) 下一步调用startScanSingle',
detail:
'符合条件(isAddEquipment == false && isExistDevice == false) 下一步调用startScanSingle',
upload: false); upload: false);
// AppLog.log('无存在设备需要扫描 deviceName:$deviceName isAddEquipment:$isAddEquipment'); // AppLog.log('无存在设备需要扫描 deviceName:$deviceName isAddEquipment:$isAddEquipment');
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) { startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
_connectDevice(scanDevices, deviceName, connectStateCallBack, _connectDevice(scanDevices, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment);
isAddEquipment: isAddEquipment);
}); });
} else { } else {
BuglyTool.uploadException( BuglyTool.uploadException(
@ -572,16 +527,14 @@ class BlueManage {
'走这个方法是有缓存或者添加设备的时候以及不符合(GetPlatform.isAndroid && !isExistDevice && isCurrentDevice && mac != null) deviceName:$deviceName 直接调用_connectDevice', '走这个方法是有缓存或者添加设备的时候以及不符合(GetPlatform.isAndroid && !isExistDevice && isCurrentDevice && mac != null) deviceName:$deviceName 直接调用_connectDevice',
upload: false); upload: false);
// AppLog.log('安卓或者iOS 存在设备不需要扫描 deviceName:$deviceName isAddEquipment:$isAddEquipment'); // AppLog.log('安卓或者iOS 存在设备不需要扫描 deviceName:$deviceName isAddEquipment:$isAddEquipment');
_connectDevice(devicesList, deviceName, connectStateCallBack, _connectDevice(devicesList, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment);
isAddEquipment: isAddEquipment);
} }
} }
// //
bool isExistScanDevices(String connectDeviceName) { bool isExistScanDevices(String connectDeviceName) {
final bool isExistDevice = scanDevices.any((ScanResult element) => final bool isExistDevice = scanDevices.any((ScanResult element) =>
element.device.platformName == connectDeviceName || element.device.platformName == connectDeviceName || element.advertisementData.advName == connectDeviceName);
element.advertisementData.advName == connectDeviceName);
return isExistDevice; return isExistDevice;
} }
@ -595,17 +548,15 @@ class BlueManage {
// //
// AppLog.log("devicesList:$devicesList"); // AppLog.log("devicesList:$devicesList");
final int knownDeviceIndex = devicesList.indexWhere((ScanResult d) => final int knownDeviceIndex = devicesList.indexWhere(
(d.device.platformName == deviceName) || (ScanResult d) => (d.device.platformName == deviceName) || (d.advertisementData.advName == deviceName));
(d.advertisementData.advName == deviceName));
ScanResult? scanResult; //使 ScanResult? scanResult; //使
if (knownDeviceIndex >= 0) { if (knownDeviceIndex >= 0) {
// //
connectDeviceMacAddress = connectDeviceMacAddress = devicesList[knownDeviceIndex].advertisementData.advName.isNotEmpty
devicesList[knownDeviceIndex].advertisementData.advName.isNotEmpty ? devicesList[knownDeviceIndex].advertisementData.advName
? devicesList[knownDeviceIndex].advertisementData.advName : devicesList[knownDeviceIndex].device.platformName;
: devicesList[knownDeviceIndex].device.platformName;
bluetoothConnectDevice = devicesList[knownDeviceIndex].device; bluetoothConnectDevice = devicesList[knownDeviceIndex].device;
scanResult = devicesList[knownDeviceIndex]; scanResult = devicesList[knownDeviceIndex];
@ -616,10 +567,8 @@ class BlueManage {
} }
if (scanResult == null || connectDeviceMacAddress.isEmpty) { if (scanResult == null || connectDeviceMacAddress.isEmpty) {
BuglyTool.uploadException( BuglyTool.uploadException(
message: message: '扫描结果scanResult == null || connectDeviceMacAddress.isEmpty不往下执行 return 上传记录当前方法是_connectDevice',
'扫描结果scanResult == null || connectDeviceMacAddress.isEmpty不往下执行 return 上传记录当前方法是_connectDevice', detail: 'scanResult:$scanResult connectDeviceMacAddress$connectDeviceMacAddress',
detail:
'scanResult:$scanResult connectDeviceMacAddress$connectDeviceMacAddress',
upload: false); upload: false);
return; return;
} }
@ -653,8 +602,7 @@ class BlueManage {
BuglyTool.uploadException( BuglyTool.uploadException(
message: '提示该锁已被重置, 回调断开连接, 清除缓存上传记录当前方法是_connectDevice', message: '提示该锁已被重置, 回调断开连接, 清除缓存上传记录当前方法是_connectDevice',
detail: detail: 'isReconnect:$isReconnect serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
'isReconnect:$isReconnect serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
upload: false); upload: false);
} }
return; return;
@ -686,8 +634,7 @@ class BlueManage {
BuglyTool.uploadException( BuglyTool.uploadException(
message: '提示该锁已被重置, 回调断开连接, 清除缓存上传记录当前方法是_connectDevice', message: '提示该锁已被重置, 回调断开连接, 清除缓存上传记录当前方法是_connectDevice',
detail: detail: 'isReconnect:$isReconnect serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
'isReconnect:$isReconnect serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
upload: false); upload: false);
} }
return; return;
@ -704,13 +651,11 @@ class BlueManage {
} }
// //
Future<void> doNotSearchBLE( Future<void> doNotSearchBLE(String masAdds, ConnectStateCallBack connectStateCallBack,
String masAdds, ConnectStateCallBack connectStateCallBack,
{bool isAddEquipment = false}) async { {bool isAddEquipment = false}) async {
await FlutterBluePlus.stopScan(); await FlutterBluePlus.stopScan();
if (bluetoothConnectDevice == null || if (bluetoothConnectDevice == null || bluetoothConnectDevice?.remoteId.str != masAdds) {
bluetoothConnectDevice?.remoteId.str != masAdds) {
bluetoothConnectDevice = BluetoothDevice.fromId(masAdds); bluetoothConnectDevice = BluetoothDevice.fromId(masAdds);
_initGetMtuSubscription(); _initGetMtuSubscription();
_initListenConnectionState(); _initListenConnectionState();
@ -721,25 +666,24 @@ class BlueManage {
} else { } else {
BuglyTool.uploadException( BuglyTool.uploadException(
message: '直接给蓝牙设备写入 上传记录当前方法是doNotSearchBLE', message: '直接给蓝牙设备写入 上传记录当前方法是doNotSearchBLE',
detail: detail: '直接给蓝牙设备写入 用传入的bluetoothConnectDevice${bluetoothConnectDevice.toString()}连接 masAdds:$masAdds',
'直接给蓝牙设备写入 用传入的bluetoothConnectDevice${bluetoothConnectDevice.toString()}连接 masAdds:$masAdds',
upload: false); upload: false);
} }
// //
await bluetoothDeviceConnect(bluetoothConnectDevice!, connectStateCallBack, await bluetoothDeviceConnect(bluetoothConnectDevice!, connectStateCallBack, isAddEquipment: isAddEquipment);
isAddEquipment: isAddEquipment);
} }
// //
Future<void> bluetoothDeviceConnect(BluetoothDevice bluetoothConnectDevice, Future<void> bluetoothDeviceConnect(BluetoothDevice bluetoothConnectDevice, ConnectStateCallBack connectStateCallBack,
ConnectStateCallBack connectStateCallBack,
{bool isAddEquipment = false}) async { {bool isAddEquipment = false}) async {
// //
const int maxAttempts = 3; const int maxAttempts = 3;
int attempt = 0; int attempt = 0;
while (attempt < maxAttempts) { while (attempt < maxAttempts) {
try { try {
await bluetoothConnectDevice.connect(timeout: 5.seconds); await bluetoothConnectDevice.connect(
timeout: 5.seconds,
);
break; // If the connection is successful, break the loop break; // If the connection is successful, break the loop
} catch (e) { } catch (e) {
AppLog.log('连接失败 重连了: $e'); AppLog.log('连接失败 重连了: $e');
@ -754,8 +698,7 @@ class BlueManage {
AppLog.log('$maxAttempts次后尝试连接失败'); AppLog.log('$maxAttempts次后尝试连接失败');
BuglyTool.uploadException( BuglyTool.uploadException(
message: '连接三次超时断开连接 回调断开连接 上传记录当前方法是bluetoothDeviceConnect', message: '连接三次超时断开连接 回调断开连接 上传记录当前方法是bluetoothDeviceConnect',
detail: detail: 'bluetoothDeviceConnect:${bluetoothConnectDevice.toString()} $maxAttempts次后尝试连接失败',
'bluetoothDeviceConnect:${bluetoothConnectDevice.toString()} $maxAttempts次后尝试连接失败',
upload: false); upload: false);
needScanSingle = true; needScanSingle = true;
connectStateCallBack(BluetoothConnectionState.disconnected); connectStateCallBack(BluetoothConnectionState.disconnected);
@ -764,22 +707,18 @@ class BlueManage {
if (bluetoothConnectionState == BluetoothConnectionState.connected) { if (bluetoothConnectionState == BluetoothConnectionState.connected) {
try { try {
needScanSingle = false; needScanSingle = false;
final List<BluetoothService> services = final List<BluetoothService> services = await bluetoothConnectDevice.discoverServices();
await bluetoothConnectDevice.discoverServices();
// //
for (final BluetoothService service in services) { for (final BluetoothService service in services) {
if (service.uuid == _serviceIdConnect) { if (service.uuid == _serviceIdConnect) {
for (final BluetoothCharacteristic characteristic for (final BluetoothCharacteristic characteristic in service.characteristics) {
in service.characteristics) { if (characteristic.characteristicUuid == _characteristicIdSubscription) {
if (characteristic.characteristicUuid ==
_characteristicIdSubscription) {
_subScribeToCharacteristic(characteristic); _subScribeToCharacteristic(characteristic);
bluetoothConnectionState = BluetoothConnectionState.connected; bluetoothConnectionState = BluetoothConnectionState.connected;
connectStateCallBack(bluetoothConnectionState!); connectStateCallBack(bluetoothConnectionState!);
BuglyTool.uploadException( BuglyTool.uploadException(
message: '订阅成功 上传记录当前方法是bluetoothDeviceConnect', message: '订阅成功 上传记录当前方法是bluetoothDeviceConnect',
detail: detail: '发现服务,连接成功,订阅数据 bluetoothDeviceConnect:${bluetoothConnectDevice.toString()} ',
'发现服务,连接成功,订阅数据 bluetoothDeviceConnect:${bluetoothConnectDevice.toString()} ',
upload: false); upload: false);
} else { } else {
BuglyTool.uploadException( BuglyTool.uploadException(
@ -801,22 +740,18 @@ class BlueManage {
needScanSingle = true; needScanSingle = true;
bluetoothConnectionState = BluetoothConnectionState.disconnected; bluetoothConnectionState = BluetoothConnectionState.disconnected;
connectStateCallBack(bluetoothConnectionState!); connectStateCallBack(bluetoothConnectionState!);
AppLog.log( AppLog.log('发现设备时失败 e:$e bluetoothConnectionState:$bluetoothConnectionState');
'发现设备时失败 e:$e bluetoothConnectionState:$bluetoothConnectionState');
BuglyTool.uploadException( BuglyTool.uploadException(
message: '发现服务时失败', message: '发现服务时失败',
detail: detail: '发现服务时报错原因e$e bluetoothDeviceConnect:${bluetoothConnectDevice.toString()}',
'发现服务时报错原因e$e bluetoothDeviceConnect:${bluetoothConnectDevice.toString()}',
upload: false); upload: false);
rethrow; rethrow;
} }
} }
} }
Future<void> _subScribeToCharacteristic( Future<void> _subScribeToCharacteristic(BluetoothCharacteristic characteristic) async {
BluetoothCharacteristic characteristic) async { final StreamSubscription<List<int>> subscription = characteristic.onValueReceived.listen((List<int> data) {
final StreamSubscription<List<int>> subscription =
characteristic.onValueReceived.listen((List<int> data) {
AppLog.log('订阅获取的数据: $data '); AppLog.log('订阅获取的数据: $data ');
if (data == lastTimeData || data.isEmpty) { if (data == lastTimeData || data.isEmpty) {
return; return;
@ -864,10 +799,7 @@ class BlueManage {
return false; return false;
} }
//239, 1, 238, 2, //239, 1, 238, 2,
if ((data[0] == 0xEF) && if ((data[0] == 0xEF) && (data[1] == 0x01) && (data[2] == 0xEE) && (data[3] == 0x02)) {
(data[1] == 0x01) &&
(data[2] == 0xEE) &&
(data[3] == 0x02)) {
return true; return true;
} else { } else {
return false; return false;
@ -876,12 +808,10 @@ class BlueManage {
/// ///
Future<void> writeCharacteristicWithResponse(List<int> value) async { Future<void> writeCharacteristicWithResponse(List<int> value) async {
final List<BluetoothService> services = final List<BluetoothService> services = await bluetoothConnectDevice!.discoverServices();
await bluetoothConnectDevice!.discoverServices();
for (final BluetoothService service in services) { for (final BluetoothService service in services) {
if (service.uuid == _serviceIdConnect) { if (service.uuid == _serviceIdConnect) {
for (final BluetoothCharacteristic characteristic for (final BluetoothCharacteristic characteristic in service.characteristics) {
in service.characteristics) {
if (characteristic.characteristicUuid == _characteristicIdWrite) { if (characteristic.characteristicUuid == _characteristicIdWrite) {
try { try {
// //
@ -900,27 +830,22 @@ class BlueManage {
while (!packetSent && retryCount < maxRetries) { while (!packetSent && retryCount < maxRetries) {
try { try {
if (characteristic.properties.writeWithoutResponse) { if (characteristic.properties.writeWithoutResponse) {
await characteristic.write(subData[i], await characteristic.write(subData[i], withoutResponse: true);
withoutResponse: true);
} else if (characteristic.properties.write) { } else if (characteristic.properties.write) {
await characteristic.write(subData[i]); await characteristic.write(subData[i]);
} else { } else {
// //
throw Exception( throw Exception('This characteristic does not support writing.');
'This characteristic does not support writing.');
} }
// //
packetSent = true; packetSent = true;
} catch (e) { } catch (e) {
if (e.toString().contains('UNKNOWN_GATT_ERROR (133)') && if (e.toString().contains('UNKNOWN_GATT_ERROR (133)') && retryCount < maxRetries - 1) {
retryCount < maxRetries - 1) {
// GATT错误133 // GATT错误133
retryCount++; retryCount++;
AppLog.log( AppLog.log('蓝牙写入失败(GATT 133),数据包 ${i + 1}/${subData.length} 正在重试 $retryCount/$maxRetries...');
'蓝牙写入失败(GATT 133),数据包 ${i + 1}/${subData.length} 正在重试 $retryCount/$maxRetries...'); await Future.delayed(Duration(milliseconds: retryDelayMs));
await Future.delayed(
Duration(milliseconds: retryDelayMs));
continue; continue;
} else { } else {
// //
@ -931,8 +856,7 @@ class BlueManage {
} }
if (!packetSent) { if (!packetSent) {
throw Exception( throw Exception('蓝牙写入失败,数据包 ${i + 1}/${subData.length} 已达到最大重试次数');
'蓝牙写入失败,数据包 ${i + 1}/${subData.length} 已达到最大重试次数');
} }
} }
@ -964,21 +888,19 @@ class BlueManage {
Future<void> disconnect() async { Future<void> disconnect() async {
try { try {
connectDeviceMacAddress = ''; connectDeviceMacAddress = '';
// MTU监听 // MTU监听
_mtuSubscription?.cancel(); _mtuSubscription?.cancel();
_mtuSubscription = null; _mtuSubscription = null;
_mtuSize = 20; // MTU为默认值 _mtuSize = 20; // MTU为默认值
if (bluetoothConnectionState == BluetoothConnectionState.connected) { if (bluetoothConnectionState == BluetoothConnectionState.connected) {
AppLog.log('请求断开蓝牙连接');
// //
await bluetoothConnectDevice!.disconnect(timeout: 3); await bluetoothConnectDevice!.disconnect(timeout: 1);
AppLog.log('断开连接成功');
} }
} on Exception catch (e, _) { } on Exception catch (e, _) {
AppLog.log('断开连接失败: $e'); AppLog.log('断开连接失败: $e');
} finally {
bluetoothConnectionState = BluetoothConnectionState.disconnected;
} }
} }
@ -1006,7 +928,7 @@ class BlueManage {
_mtuSubscription?.cancel(); _mtuSubscription?.cancel();
_adapterStateStateSubscription?.cancel(); _adapterStateStateSubscription?.cancel();
_connectionStateSubscription?.cancel(); _connectionStateSubscription?.cancel();
// //
_mtuSize = 20; _mtuSize = 20;
connectDeviceName = ''; connectDeviceName = '';

View File

@ -165,6 +165,7 @@ class LockDetailLogic extends BaseGetXController {
} }
_handleSynchronizeUploadLockData(); _handleSynchronizeUploadLockData();
break; break;
case 0x06: case 0x06:
// //
@ -928,28 +929,31 @@ class LockDetailLogic extends BaseGetXController {
} }
void _handleGetLockPasswordData() { void _handleGetLockPasswordData() {
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(
if (connectionState == BluetoothConnectionState.connected) { BlueManage().connectDeviceName,
final List<String>? token = await Storage.getStringList(saveBlueToken); (BluetoothConnectionState connectionState) async {
final List<int> getTokenList = changeStringListToIntList(token!); if (connectionState == BluetoothConnectionState.connected) {
final List<String>? token = await Storage.getStringList(saveBlueToken);
final List<int> getTokenList = changeStringListToIntList(token!);
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!); final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
final List<String>? signKey = await Storage.getStringList(saveBlueSignKey); final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
final List<int> signKeyDataList = changeStringListToIntList(signKey!); final List<int> signKeyDataList = changeStringListToIntList(signKey!);
IoSenderManage.updataLockPasswordListCommand( IoSenderManage.updataLockPasswordListCommand(
lockID: BlueManage().connectDeviceName, lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(), userID: await Storage.getUid(),
page: state.uploadPasswordPage, page: state.uploadPasswordPage,
countReq: state.countReq, countReq: state.countReq,
token: getTokenList, token: getTokenList,
needAuthor: 1, needAuthor: 1,
signKey: signKeyDataList, signKey: signKeyDataList,
privateKey: getPrivateKeyList); privateKey: getPrivateKeyList);
} }
}); },
);
} }
// //
@ -963,7 +967,7 @@ class LockDetailLogic extends BaseGetXController {
// 10 // 10
state.uploadPasswordPage = state.uploadPasswordPage + 1; state.uploadPasswordPage = state.uploadPasswordPage + 1;
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1067,7 +1071,6 @@ class LockDetailLogic extends BaseGetXController {
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1171,7 +1174,6 @@ class LockDetailLogic extends BaseGetXController {
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1325,7 +1327,6 @@ class LockDetailLogic extends BaseGetXController {
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1402,7 +1403,6 @@ class LockDetailLogic extends BaseGetXController {
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1479,7 +1479,6 @@ class LockDetailLogic extends BaseGetXController {
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1503,6 +1502,8 @@ class LockDetailLogic extends BaseGetXController {
} else { } else {
state.indexCount.value = state.indexCount.value + 1; state.indexCount.value = state.indexCount.value + 1;
_lockDataUpload(uploadType: 2, recordType: 7, records: state.uploadRemoteControlDataList); _lockDataUpload(uploadType: 2, recordType: 7, records: state.uploadRemoteControlDataList);
AppLog.log('需要执行断开操作');
BlueManage().disconnect();
} }
break; break;
case 0x06: case 0x06:

View File

@ -45,8 +45,7 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
@override @override
void onInit() async { void onInit() async {
super.onInit(); super.onInit();
_replySubscription = _replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
if (reply is VoicePackageConfigureReply) { if (reply is VoicePackageConfigureReply) {
// //
_handlerStartVoicePackageConfigure(reply); _handlerStartVoicePackageConfigure(reply);
@ -72,8 +71,7 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
final vendor = state.lockSetInfoData.value.lockBasicInfo?.vendor; final vendor = state.lockSetInfoData.value.lockBasicInfo?.vendor;
final model = state.lockSetInfoData.value.lockBasicInfo?.model; final model = state.lockSetInfoData.value.lockBasicInfo?.model;
final PassthroughListResponse entity = final PassthroughListResponse entity = await ApiRepository.to.getPassthroughList(data: {
await ApiRepository.to.getPassthroughList(data: {
'vendor': vendor!, 'vendor': vendor!,
'model': model!, 'model': model!,
}); });
@ -110,18 +108,15 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
final passthroughItem = PassthroughItem( final passthroughItem = PassthroughItem(
lang: element.lang, lang: element.lang,
timbres: element.timbres, timbres: element.timbres,
langText: langText: ExtensionLanguageType.fromLocale(locales[indexOf]).lanTitle,
ExtensionLanguageType.fromLocale(locales[indexOf]).lanTitle,
name: element.name, name: element.name,
); );
state.languages.add(passthroughItem); state.languages.add(passthroughItem);
} }
}); });
state.languages.refresh(); state.languages.refresh();
final lang = state final lang = state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang;
.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang; final timbre = state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.timbre;
final timbre = state
.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.timbre;
// for 访 // for 访
for (int i = 0; i < state.languages.length; i++) { for (int i = 0; i < state.languages.length; i++) {
final language = state.languages[i]; // final language = state.languages[i]; //
@ -156,8 +151,7 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
// APP层的语言 // APP层的语言
Locale? currentLocale = Get.locale; // Locale? currentLocale = Get.locale; //
if (currentLocale != null) { if (currentLocale != null) {
final indexWhere = state.languages final indexWhere = state.languages.indexWhere((element) => element.lang == currentLocale.toString());
.indexWhere((element) => element.lang == currentLocale.toString());
state.selectPassthroughListIndex.value = indexWhere; state.selectPassthroughListIndex.value = indexWhere;
} }
} }
@ -192,15 +186,11 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
showBlueConnetctToastTimer(action: () { showBlueConnetctToastTimer(action: () {
dismissEasyLoading(); dismissEasyLoading();
}); });
BlueManage().blueSendData(BlueManage().connectDeviceName, BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async {
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
await Storage.getStringList(saveBluePrivateKey); final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
final List<int> getPrivateKeyList = final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
changeStringListToIntList(privateKey!);
final List<String>? signKey =
await Storage.getStringList(saveBlueSignKey);
final List<int> signKeyDataList = changeStringListToIntList(signKey!); final List<int> signKeyDataList = changeStringListToIntList(signKey!);
final String uid = await Storage.getUid() ?? ''; final String uid = await Storage.getUid() ?? '';
final String md5Str = md5.convert(data).toString().toUpperCase(); final String md5Str = md5.convert(data).toString().toUpperCase();
@ -219,8 +209,7 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
privateKey: getPrivateKeyList) privateKey: getPrivateKeyList)
.packageData(), .packageData(),
); );
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
} }
@ -233,16 +222,14 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
showBlueConnetctToastTimer(action: () { showBlueConnetctToastTimer(action: () {
dismissEasyLoading(); dismissEasyLoading();
}); });
BlueManage().blueSendData(BlueManage().connectDeviceName, BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async {
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
BlueManage().writeCharacteristicWithResponse( BlueManage().writeCharacteristicWithResponse(
GetDeviceModelCommand( GetDeviceModelCommand(
lockID: BlueManage().connectDeviceName, lockID: BlueManage().connectDeviceName,
).packageData(), ).packageData(),
); );
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
showBlueConnetctToast(); showBlueConnetctToast();
@ -251,8 +238,7 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
} }
// //
void _handlerStartVoicePackageConfigure( void _handlerStartVoicePackageConfigure(VoicePackageConfigureReply reply) async {
VoicePackageConfigureReply reply) async {
final int status = reply.data[6]; final int status = reply.data[6];
switch (status) { switch (status) {
case 0x00: case 0x00:
@ -280,8 +266,7 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
if (state.data == null) return; if (state.data == null) return;
state.voiceSubcontractingIndex = 0; state.voiceSubcontractingIndex = 0;
state.voiceSubcontractingCount = state.voiceSubcontractingCount =
(state.data!.length + state.voiceSubcontractingSize - 1) ~/ (state.data!.length + state.voiceSubcontractingSize - 1) ~/ state.voiceSubcontractingSize;
state.voiceSubcontractingSize;
state.progress.value = 0.0; // state.progress.value = 0.0; //
_sendNextPackage(); _sendNextPackage();
} }
@ -332,8 +317,7 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
Uint8List packageData = state.data!.sublist(start, end); Uint8List packageData = state.data!.sublist(start, end);
// //
state.progress.value = state.progress.value = (state.voiceSubcontractingIndex + 1) / state.voiceSubcontractingCount;
(state.voiceSubcontractingIndex + 1) / state.voiceSubcontractingCount;
EasyLoading.showProgress(state.progress.value, EasyLoading.showProgress(state.progress.value,
status: '正在发送数据 ${(state.progress.value * 100).toStringAsFixed(0)}%'); status: '正在发送数据 ${(state.progress.value * 100).toStringAsFixed(0)}%');
await _sendLanguageFileBleMessage( await _sendLanguageFileBleMessage(
@ -342,8 +326,7 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
); );
} }
_sendLanguageFileBleMessage( _sendLanguageFileBleMessage({required int index, required Uint8List data}) async {
{required int index, required Uint8List data}) async {
await BlueManage().blueSendData(BlueManage().connectDeviceName, await BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async { (BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
@ -354,17 +337,15 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
data: data, data: data,
).packageData(), ).packageData(),
); );
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
showBlueConnetctToast(); // showBlueConnetctToast();
} }
}); });
} }
void _handlerVoicePackageConfigureProcess( void _handlerVoicePackageConfigureProcess(VoicePackageConfigureProcessReply reply) {
VoicePackageConfigureProcessReply reply) {
// //
_sendTimeoutTimer?.cancel(); _sendTimeoutTimer?.cancel();
_isTimeout = false; // _isTimeout = false; //
@ -431,8 +412,7 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
}); });
} }
Future<void> _executeLogic( Future<void> _executeLogic(VoicePackageConfigureConfirmationReply reply) async {
VoicePackageConfigureConfirmationReply reply) async {
await _handlerVoicePackageConfigureConfirmation(reply); await _handlerVoicePackageConfigureConfirmation(reply);
} }
@ -440,9 +420,12 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
VoicePackageConfigureConfirmationReply reply, VoicePackageConfigureConfirmationReply reply,
) async { ) async {
showEasyLoading(); showEasyLoading();
showBlueConnetctToastTimer(action: () { showBlueConnetctToastTimer(
dismissEasyLoading(); action: () {
}); dismissEasyLoading();
},
isShowBlueConnetctToast: false,
);
final LoginEntity entity = await ApiRepository.to.settingCurrentVoiceTimbre( final LoginEntity entity = await ApiRepository.to.settingCurrentVoiceTimbre(
data: { data: {
'lang': state.tempLangStr.value, 'lang': state.tempLangStr.value,
@ -452,10 +435,8 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
); );
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
showSuccess('设置成功'.tr, something: () async { showSuccess('设置成功'.tr, something: () async {
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang = state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang = state.tempLangStr.value;
state.tempLangStr.value; state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.timbre = state.tempTimbreStr.value;
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
?.timbre = state.tempTimbreStr.value;
await BlueManage().blueSendData(BlueManage().connectDeviceName, await BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async { (BluetoothConnectionState deviceConnectionState) async {
@ -466,11 +447,10 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
languageCode: state.tempLangStr.value, languageCode: state.tempLangStr.value,
).packageData(), ).packageData(),
); );
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
showBlueConnetctToast(); // showBlueConnetctToast();
} }
}); });
await Future.delayed(Duration(seconds: 1)); await Future.delayed(Duration(seconds: 1));
@ -491,8 +471,7 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
} }
} }
void handleLockCurrentVoicePacketResult( void handleLockCurrentVoicePacketResult(ReadLockCurrentVoicePacketReply reply) {
ReadLockCurrentVoicePacketReply reply) {
final int status = reply.data[2]; final int status = reply.data[2];
switch (status) { switch (status) {
case 0x00: case 0x00:
@ -501,25 +480,21 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
const int languageCodeStartIndex = 3; const int languageCodeStartIndex = 3;
const int languageCodeLength = 20; const int languageCodeLength = 20;
const int languageCodeEndIndex = const int languageCodeEndIndex = languageCodeStartIndex + languageCodeLength; // 23
languageCodeStartIndex + languageCodeLength; // 23
if (reply.data.length < languageCodeEndIndex) { if (reply.data.length < languageCodeEndIndex) {
throw Exception( throw Exception(
'Reply data is too short to contain LanguageCode. Expected at least $languageCodeEndIndex bytes, got ${reply.data.length}'); 'Reply data is too short to contain LanguageCode. Expected at least $languageCodeEndIndex bytes, got ${reply.data.length}');
} }
List<int> languageCodeBytes = List<int> languageCodeBytes = reply.data.sublist(languageCodeStartIndex, languageCodeEndIndex);
reply.data.sublist(languageCodeStartIndex, languageCodeEndIndex);
String languageCode = String.fromCharCodes(languageCodeBytes); String languageCode = String.fromCharCodes(languageCodeBytes);
languageCode = languageCode.trim(); // languageCode = languageCode.trim(); //
languageCode = languageCode = languageCode.replaceAll('\u0000', ''); // (null bytes)
languageCode.replaceAll('\u0000', ''); // (null bytes)
if (languageCode != null && languageCode != '') { if (languageCode != null && languageCode != '') {
final indexWhere = state.languages final indexWhere = state.languages.indexWhere((element) => element.lang == languageCode);
.indexWhere((element) => element.lang == languageCode);
if (indexWhere != -1) { if (indexWhere != -1) {
print('锁板上的语言是:$languageCode,下标是:$indexWhere'); print('锁板上的语言是:$languageCode,下标是:$indexWhere');
state.selectPassthroughListIndex.value = indexWhere; state.selectPassthroughListIndex.value = indexWhere;
@ -541,9 +516,11 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
void readLockLanguage() async { void readLockLanguage() async {
showEasyLoading(); showEasyLoading();
showBlueConnetctToastTimer(action: () { showBlueConnetctToastTimer(
dismissEasyLoading(); isShowBlueConnetctToast: false,
}); action: () {
dismissEasyLoading();
});
await BlueManage().blueSendData(BlueManage().connectDeviceName, await BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async { (BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
@ -552,11 +529,10 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
lockID: BlueManage().connectDeviceName, lockID: BlueManage().connectDeviceName,
).packageData(), ).packageData(),
); );
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
showBlueConnetctToast(); // showBlueConnetctToast();
} }
}); });
} }

View File

@ -43,8 +43,7 @@ class LockVoiceSettingLogic extends BaseGetXController {
@override @override
void onInit() async { void onInit() async {
super.onInit(); super.onInit();
_replySubscription = _replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
if (reply is VoicePackageConfigureReply) { if (reply is VoicePackageConfigureReply) {
// //
_handlerStartVoicePackageConfigure(reply); _handlerStartVoicePackageConfigure(reply);
@ -78,12 +77,14 @@ class LockVoiceSettingLogic extends BaseGetXController {
}); });
} }
Future<void> _executeLogic( Future<void> _executeLogic(VoicePackageConfigureConfirmationReply reply) async {
VoicePackageConfigureConfirmationReply reply) async {
showEasyLoading(); showEasyLoading();
showBlueConnetctToastTimer(action: () { showBlueConnetctToastTimer(
dismissEasyLoading(); action: () {
}); dismissEasyLoading();
},
isShowBlueConnetctToast: false,
);
final LoginEntity entity = await ApiRepository.to.settingCurrentVoiceTimbre( final LoginEntity entity = await ApiRepository.to.settingCurrentVoiceTimbre(
data: { data: {
'lang': state.tempLangStr.value, 'lang': state.tempLangStr.value,
@ -93,10 +94,8 @@ class LockVoiceSettingLogic extends BaseGetXController {
); );
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
showSuccess('设置成功'.tr, something: () async { showSuccess('设置成功'.tr, something: () async {
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang = state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang = state.tempLangStr.value;
state.tempLangStr.value; state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.timbre = state.tempTimbreStr.value;
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
?.timbre = state.tempTimbreStr.value;
await BlueManage().blueSendData(BlueManage().connectDeviceName, await BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async { (BluetoothConnectionState deviceConnectionState) async {
@ -107,16 +106,14 @@ class LockVoiceSettingLogic extends BaseGetXController {
languageCode: state.tempLangStr.value, languageCode: state.tempLangStr.value,
).packageData(), ).packageData(),
); );
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
showBlueConnetctToast(); // showBlueConnetctToast();
} }
}); });
await Future.delayed(Duration(seconds: 1)); await Future.delayed(Duration(seconds: 1));
eventBus eventBus.fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value));
.fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value));
Get.offAllNamed(Routers.starLockMain); Get.offAllNamed(Routers.starLockMain);
}); });
} }
@ -145,8 +142,7 @@ class LockVoiceSettingLogic extends BaseGetXController {
// APP层的语言 // APP层的语言
Locale? currentLocale = Get.locale; // Locale? currentLocale = Get.locale; //
if (currentLocale != null) { if (currentLocale != null) {
final indexWhere = state.languages final indexWhere = state.languages.indexWhere((element) => element.lang == currentLocale.toString());
.indexWhere((element) => element.lang == currentLocale.toString());
state.selectPassthroughListIndex.value = indexWhere; state.selectPassthroughListIndex.value = indexWhere;
} }
} }
@ -176,15 +172,11 @@ class LockVoiceSettingLogic extends BaseGetXController {
showBlueConnetctToastTimer(action: () { showBlueConnetctToastTimer(action: () {
dismissEasyLoading(); dismissEasyLoading();
}); });
BlueManage().blueSendData(BlueManage().connectDeviceName, BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async {
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
await Storage.getStringList(saveBluePrivateKey); final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
final List<int> getPrivateKeyList = final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
changeStringListToIntList(privateKey!);
final List<String>? signKey =
await Storage.getStringList(saveBlueSignKey);
final List<int> signKeyDataList = changeStringListToIntList(signKey!); final List<int> signKeyDataList = changeStringListToIntList(signKey!);
final String uid = await Storage.getUid() ?? ''; final String uid = await Storage.getUid() ?? '';
final String md5Str = md5.convert(data).toString().toUpperCase(); final String md5Str = md5.convert(data).toString().toUpperCase();
@ -203,8 +195,7 @@ class LockVoiceSettingLogic extends BaseGetXController {
privateKey: getPrivateKeyList) privateKey: getPrivateKeyList)
.packageData(), .packageData(),
); );
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
@ -216,8 +207,7 @@ class LockVoiceSettingLogic extends BaseGetXController {
}); });
} }
void _handlerVoicePackageConfigureProcess( void _handlerVoicePackageConfigureProcess(VoicePackageConfigureProcessReply reply) {
VoicePackageConfigureProcessReply reply) {
// //
_sendTimeoutTimer?.cancel(); _sendTimeoutTimer?.cancel();
_isTimeout = false; // _isTimeout = false; //
@ -235,8 +225,7 @@ class LockVoiceSettingLogic extends BaseGetXController {
} }
// //
void _handlerStartVoicePackageConfigure( void _handlerStartVoicePackageConfigure(VoicePackageConfigureReply reply) async {
VoicePackageConfigureReply reply) async {
final int status = reply.data[6]; final int status = reply.data[6];
switch (status) { switch (status) {
case 0x00: case 0x00:
@ -265,8 +254,7 @@ class LockVoiceSettingLogic extends BaseGetXController {
final vendor = state.lockSetInfoData.value.lockBasicInfo?.vendor; final vendor = state.lockSetInfoData.value.lockBasicInfo?.vendor;
final model = state.lockSetInfoData.value.lockBasicInfo?.model; final model = state.lockSetInfoData.value.lockBasicInfo?.model;
final PassthroughListResponse entity = final PassthroughListResponse entity = await ApiRepository.to.getPassthroughList(data: {
await ApiRepository.to.getPassthroughList(data: {
'vendor': vendor!, 'vendor': vendor!,
'model': model!, 'model': model!,
}); });
@ -302,8 +290,7 @@ class LockVoiceSettingLogic extends BaseGetXController {
final passthroughItem = PassthroughItem( final passthroughItem = PassthroughItem(
lang: element.lang, lang: element.lang,
timbres: element.timbres, timbres: element.timbres,
langText: langText: ExtensionLanguageType.fromLocale(locales[indexOf]).lanTitle,
ExtensionLanguageType.fromLocale(locales[indexOf]).lanTitle,
name: element.name, name: element.name,
); );
@ -311,10 +298,8 @@ class LockVoiceSettingLogic extends BaseGetXController {
} }
}); });
state.languages.refresh(); state.languages.refresh();
final lang = state final lang = state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang;
.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang; final timbre = state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.timbre;
final timbre = state
.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.timbre;
state.languages.value.forEach((element) { state.languages.value.forEach((element) {
final timbres = element.timbres; final timbres = element.timbres;
timbres.forEach((item) { timbres.forEach((item) {
@ -335,8 +320,7 @@ class LockVoiceSettingLogic extends BaseGetXController {
if (state.data == null) return; if (state.data == null) return;
state.voiceSubcontractingIndex = 0; state.voiceSubcontractingIndex = 0;
state.voiceSubcontractingCount = state.voiceSubcontractingCount =
(state.data!.length + state.voiceSubcontractingSize - 1) ~/ (state.data!.length + state.voiceSubcontractingSize - 1) ~/ state.voiceSubcontractingSize;
state.voiceSubcontractingSize;
state.progress.value = 0.0; // state.progress.value = 0.0; //
_sendNextPackage(); _sendNextPackage();
} }
@ -380,8 +364,7 @@ class LockVoiceSettingLogic extends BaseGetXController {
Uint8List packageData = state.data!.sublist(start, end); Uint8List packageData = state.data!.sublist(start, end);
// //
state.progress.value = state.progress.value = (state.voiceSubcontractingIndex + 1) / state.voiceSubcontractingCount;
(state.voiceSubcontractingIndex + 1) / state.voiceSubcontractingCount;
EasyLoading.showProgress(state.progress.value, EasyLoading.showProgress(state.progress.value,
status: '正在发送数据 ${(state.progress.value * 100).toStringAsFixed(0)}%'); status: '正在发送数据 ${(state.progress.value * 100).toStringAsFixed(0)}%');
_sendLanguageFileBleMessage( _sendLanguageFileBleMessage(
@ -391,8 +374,7 @@ class LockVoiceSettingLogic extends BaseGetXController {
} }
_sendLanguageFileBleMessage({required int index, required Uint8List data}) { _sendLanguageFileBleMessage({required int index, required Uint8List data}) {
BlueManage().blueSendData(BlueManage().connectDeviceName, BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async {
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
BlueManage().writeCharacteristicWithResponse( BlueManage().writeCharacteristicWithResponse(
VoicePackageConfigureProcess( VoicePackageConfigureProcess(
@ -401,8 +383,7 @@ class LockVoiceSettingLogic extends BaseGetXController {
data: data, data: data,
).packageData(), ).packageData(),
); );
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
// showBlueConnetctToast(); // showBlueConnetctToast();
@ -445,9 +426,12 @@ class LockVoiceSettingLogic extends BaseGetXController {
void readLockLanguage() async { void readLockLanguage() async {
showEasyLoading(); showEasyLoading();
showBlueConnetctToastTimer(action: () { showBlueConnetctToastTimer(
dismissEasyLoading(); action: () {
}); dismissEasyLoading();
},
isShowBlueConnetctToast: false,
);
await BlueManage().blueSendData(BlueManage().connectDeviceName, await BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async { (BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
@ -456,17 +440,15 @@ class LockVoiceSettingLogic extends BaseGetXController {
lockID: BlueManage().connectDeviceName, lockID: BlueManage().connectDeviceName,
).packageData(), ).packageData(),
); );
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
showBlueConnetctToast(); // showBlueConnetctToast();
} }
}); });
} }
void handleLockCurrentVoicePacketResult( void handleLockCurrentVoicePacketResult(ReadLockCurrentVoicePacketReply reply) {
ReadLockCurrentVoicePacketReply reply) {
final int status = reply.data[2]; final int status = reply.data[2];
switch (status) { switch (status) {
case 0x00: case 0x00:
@ -475,28 +457,24 @@ class LockVoiceSettingLogic extends BaseGetXController {
const int languageCodeStartIndex = 3; const int languageCodeStartIndex = 3;
const int languageCodeLength = 20; const int languageCodeLength = 20;
const int languageCodeEndIndex = const int languageCodeEndIndex = languageCodeStartIndex + languageCodeLength; // 23
languageCodeStartIndex + languageCodeLength; // 23
if (reply.data.length < languageCodeEndIndex) { if (reply.data.length < languageCodeEndIndex) {
throw Exception( throw Exception(
'Reply data is too short to contain LanguageCode. Expected at least $languageCodeEndIndex bytes, got ${reply.data.length}'); 'Reply data is too short to contain LanguageCode. Expected at least $languageCodeEndIndex bytes, got ${reply.data.length}');
} }
List<int> languageCodeBytes = List<int> languageCodeBytes = reply.data.sublist(languageCodeStartIndex, languageCodeEndIndex);
reply.data.sublist(languageCodeStartIndex, languageCodeEndIndex);
String languageCode = String.fromCharCodes(languageCodeBytes); String languageCode = String.fromCharCodes(languageCodeBytes);
languageCode = languageCode.trim(); // languageCode = languageCode.trim(); //
languageCode = languageCode = languageCode.replaceAll('\u0000', ''); // (null bytes)
languageCode.replaceAll('\u0000', ''); // (null bytes)
print('LanguageCode: $languageCode'); // : zh_CN, en_US print('LanguageCode: $languageCode'); // : zh_CN, en_US
if (languageCode != null && languageCode != '') { if (languageCode != null && languageCode != '') {
final indexWhere = state.languages final indexWhere = state.languages.indexWhere((element) => element.lang == languageCode);
.indexWhere((element) => element.lang == languageCode);
if (indexWhere != -1) { if (indexWhere != -1) {
print('锁板上的语言是:$languageCode,下标是:$indexWhere'); print('锁板上的语言是:$languageCode,下标是:$indexWhere');
state.selectPassthroughListIndex.value = indexWhere; state.selectPassthroughListIndex.value = indexWhere;

File diff suppressed because it is too large Load Diff

View File

@ -176,12 +176,12 @@ dependencies:
url_launcher: ^6.1.10 url_launcher: ^6.1.10
#蓝牙 #蓝牙
# flutter_reactive_ble: ^5.1.1 # flutter_reactive_ble: ^5.1.1
flutter_blue_plus: 1.32.7 flutter_blue_plus: 1.33.0
# #
event_bus: ^2.0.0 event_bus: ^2.0.0
#菊花 #菊花
flutter_easyloading: 3.0.4 flutter_easyloading: 3.0.5
flutter_spinkit: 5.2.1
#图形验证码 #图形验证码
# aj_captcha_flutter: ^0.0.1 # aj_captcha_flutter: ^0.0.1
asn1lib: ^1.6.5 asn1lib: ^1.6.5
@ -218,7 +218,7 @@ dependencies:
jpush_flutter: jpush_flutter:
git: git:
url: git@code-internal.star-lock.cn:StarlockTeam/jpush_flutter.git url: git@code.star-lock.cn:StarlockTeam/jpush_flutter.git
ref: 656df9ee91b1ec8b96aa1208a6b0df27a4516067 ref: 656df9ee91b1ec8b96aa1208a6b0df27a4516067
#视频播放器 #视频播放器
@ -235,6 +235,7 @@ dependencies:
# ffmpeg_kit_flutter: 5.1.0-LTS # ffmpeg_kit_flutter: 5.1.0-LTS
fast_gbk: ^1.0.0 fast_gbk: ^1.0.0
flutter_pcm_sound: ^1.1.0 flutter_pcm_sound: ^1.1.0
intl: ^0.18.0 intl: ^0.18.0
# flutter_audio_capture: <1.1.5 # flutter_audio_capture: <1.1.5
@ -246,7 +247,7 @@ dependencies:
#侧滑删除 #侧滑删除
flutter_slidable: ^3.0.1 flutter_slidable: ^3.0.1
# audio_service: ^0.18.12 # audio_service: ^0.18.12
app_settings: ^5.1.1 app_settings: ^6.1.1
flutter_local_notifications: ^17.0.0 flutter_local_notifications: ^17.0.0
fluwx: 4.5.5 fluwx: 4.5.5
system_settings: ^2.0.0 system_settings: ^2.0.0