Compare commits

...

146 Commits

Author SHA1 Message Date
513607e1ef fix: 增加日志 2025-11-07 18:03:11 +08:00
6cc00ca348 fix: 增加调试页面 2025-10-29 18:02:55 +08:00
21aa3adf7b fix: 调整页面是默认选中为锁通通 2025-10-27 17:35:41 +08:00
f6e900aaad fix: 增加日志 2025-10-27 09:27:37 +08:00
41aea1d1bf fix: 增加调试页面 2025-10-24 09:17:22 +08:00
5ed7e4013e fix: 调整列表左滑无法删除的问题 2025-10-23 09:49:21 +08:00
a4892633a3 fix: 增加日志 2025-10-22 15:52:53 +08:00
f73943785f fix: 修复添加完锁之后立马蓝牙开锁无法打开的问题 2025-10-22 14:38:55 +08:00
baeb3c139a fix: 修复在列表无法直接删除锁的问题 2025-10-22 09:59:55 +08:00
e1011688de fix: 调整第三方平台设置 2025-10-22 09:37:26 +08:00
4f1b1dd02f fix: 恢复分支 2025-10-20 15:29:28 +08:00
ae176ffb6c fix: 增加网关配网时的参数 2025-10-20 14:48:13 +08:00
2bfbac52fa fix: 停用友盟,格式化部分代码 2025-10-15 16:52:04 +08:00
10c9b896aa fix: 停用友盟,格式化部分代码 2025-10-09 11:38:47 +08:00
ddb71668c4 fix: 增加网络信号信息 2025-10-09 11:37:38 +08:00
d3cd4adce8 fix: 增加ai助理、调整第三方协议 2025-10-09 11:37:24 +08:00
b5dfd10baa fix: 调整注册账户时国外用户默认使用邮箱,并给出提示 2025-09-28 09:31:13 +08:00
2e85975c41 fix: 调整蓝牙开锁时出现重复响应,增加防抖处理。调整动画控制器在初始化之前进行赋值 2025-09-26 18:49:41 +08:00
8a5de7d442 fix: 调整蓝牙开锁时出现重复响应,增加防抖处理。调整动画控制器在初始化之前进行赋值 2025-09-25 18:23:35 +08:00
8fd0a5243e fix: 测试ci
Some checks failed
Flutter CI - Basic Setup / 🏗️ Build Flutter Artifacts (pull_request) Failing after 3m45s
Flutter CI - Basic Setup / 🔧 Basic Setup (pull_request) Successful in 1m31s
2025-09-25 10:57:01 +08:00
bdaad63b11 fix: 测试ci
Some checks failed
Flutter CI - Basic Setup / 🔧 Basic Setup (pull_request) Successful in 3m21s
Flutter CI - Basic Setup / 🏗️ Build Flutter Artifacts (pull_request) Failing after 5m34s
2025-09-25 10:38:36 +08:00
0ee37e8fda fix: 测试ci
Some checks failed
Flutter CI - Basic Setup / 🔧 Basic Setup (pull_request) Successful in 3m13s
Flutter CI - Basic Setup / 🏗️ Build Flutter Artifacts (pull_request) Failing after 7m9s
2025-09-25 10:18:11 +08:00
670e6e8b26 fix: 测试ci 2025-09-25 10:16:02 +08:00
68b244a527 fix: 测试ci 2025-09-25 09:56:28 +08:00
47b5e7b06e fix: 测试ci(增加构建制品) 2025-09-25 09:55:37 +08:00
736854c959 fix: 测试ci(增加构建制品) 2025-09-25 09:55:10 +08:00
7aef630e1b fix: 测试ci(增加构建制品) 2025-09-25 09:54:04 +08:00
3eee6d663a fix: 测试ci(增加构建制品)
Some checks failed
Flutter CI - Basic Setup / 🔧 Basic Setup (push) Successful in 3m38s
Flutter CI - Basic Setup / 🏗️ Build Flutter Artifacts (push) Has been cancelled
2025-09-25 09:43:46 +08:00
fc4429d828 fix: 测试ci
Some checks failed
Flutter CI - Basic Setup / 🔧 Basic Setup (push) Failing after 1m30s
2025-09-25 09:41:33 +08:00
9c14338c53 fix: 测试ci(计算下一位版本号)
All checks were successful
Flutter CI - Basic Setup / 🔧 Basic Setup (push) Successful in 3m11s
2025-09-25 09:32:03 +08:00
9b69c65bf8 fix: 测试ci
All checks were successful
Flutter CI - Basic Setup / 🔧 Basic Setup (push) Successful in 3m14s
2025-09-25 09:22:12 +08:00
398c45ade1 fix: 测试ci
Some checks failed
Flutter CI - Basic Setup / 🔧 Basic Setup (push) Failing after 3m32s
2025-09-25 09:12:47 +08:00
ac157e8b93 fix: 测试ci
Some checks failed
Flutter Build - Sky Develop / 📦 Build AAB (Develop) (push) Failing after 2m30s
Flutter Build - Sky Develop / 🍎 Build iOS (Develop) (push) Failing after 1m31s
Flutter Build - Sky Develop / 🏷️ Create Tag & Notify (push) Has been skipped
Flutter Build - Sky Develop / 🧮 Determine Version (push) Successful in 4m11s
Flutter Build - Sky Develop / 📦 Build APK (Develop) (push) Failing after 2m35s
2025-09-23 11:07:09 +08:00
d49359bdf7 fix: 测试ci
Some checks failed
Flutter Build - Sky Develop / 🧮 Determine Version (push) Successful in 3m24s
Flutter Build - Sky Develop / 📦 Build APK (Develop) (push) Failing after 3m11s
Flutter Build - Sky Develop / 📦 Build AAB (Develop) (push) Failing after 2m39s
Flutter Build - Sky Develop / 🍎 Build iOS (Develop) (push) Failing after 5m28s
Flutter Build - Sky Develop / 🏷️ Create Tag & Notify (push) Has been skipped
2025-09-23 10:43:51 +08:00
2ab18a1425 fix: 测试ci
Some checks failed
Flutter Build - Sky Develop / 🧮 Determine Version (push) Has been cancelled
Flutter Build - Sky Develop / 📦 Build APK (Develop) (push) Has been cancelled
Flutter Build - Sky Develop / 📦 Build AAB (Develop) (push) Has been cancelled
Flutter Build - Sky Develop / 🍎 Build iOS (Develop) (push) Has been cancelled
Flutter Build - Sky Develop / 🏷️ Create Tag & Notify (push) Has been cancelled
2025-09-23 10:42:47 +08:00
c41e1ebd9d fix: 测试ci
Some checks failed
Flutter Build - Sky / 🧮 Determine Version (push) Failing after 1m30s
Flutter Build - Sky / 📦 Build APK (push) Has been skipped
Flutter Build - Sky / 📦 Build AAB (push) Has been skipped
Flutter Build - Sky / 🍎 Build iOS (push) Has been skipped
Flutter Build - Sky / 🏷️ Create Tag & Notify (push) Has been skipped
2025-09-23 10:27:05 +08:00
13af3c02a2 fix: 测试ci
Some checks failed
Flutter Build - Sky Dev / Build Android for Sky (dev) (push) Failing after 8m47s
2025-09-23 10:11:29 +08:00
2674cf2554 fix: 测试ci
Some checks failed
Flutter Build - Sky Dev / Build Android for Sky (dev) (push) Failing after 6m16s
2025-09-23 09:42:50 +08:00
1f107b4be7 fix: 测试ci
Some checks failed
Flutter Build - Sky Dev / Build Android for Sky (dev) (push) Failing after 1m48s
2025-09-23 09:16:36 +08:00
74826b9acb fix: 测试ci
Some checks failed
Flutter Build - Sky Dev / Build Android for Sky (dev) (push) Failing after 2m23s
2025-09-23 09:11:59 +08:00
c122bfa637 fix: 测试ci
Some checks failed
Flutter Build - Sky Dev / Build Android for Sky (dev) (push) Failing after 1m46s
2025-09-22 18:37:42 +08:00
462e464f8a fix: 测试ci
Some checks failed
Flutter Build - Sky Dev / Build Android for Sky (dev) (push) Failing after 1m51s
2025-09-22 18:32:24 +08:00
7c346a118e fix: 测试ci
Some checks failed
Flutter Build - Sky Dev / Build Android for Sky (dev) (push) Has been cancelled
2025-09-22 18:31:50 +08:00
01d60d2d49 fix: 测试ci
Some checks failed
Flutter CI - Build iOS & Android / Build Flutter App (push) Failing after 2m53s
2025-09-22 18:25:50 +08:00
73548e45b6 fix: 测试ci
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 1m32s
2025-09-22 18:23:59 +08:00
004a0b89a9 fix: 测试ci
Some checks are pending
Flutter CI - Develop Sky / Build iOS & Android (push) Waiting to run
2025-09-22 18:07:29 +08:00
4cbaa92593 fix: 测试ci
Some checks are pending
Flutter CI - Develop Sky / Build iOS & Android (push) Waiting to run
2025-09-22 18:03:43 +08:00
47a1bfb914 Merge pull request 'develop_sky_liyi' (#2) from develop_sky_liyi into develop_sky
Some checks are pending
Flutter CI/CD Pipeline / Print Environment (push) Waiting to run
Flutter CI/CD Pipeline / Generate Git Tag (push) Blocked by required conditions
Flutter CI/CD Pipeline / Generate Next Version (push) Blocked by required conditions
Flutter CI/CD Pipeline / Build Android APK/AAB (push) Blocked by required conditions
Flutter CI/CD Pipeline / Build iOS IPA (push) Blocked by required conditions
Flutter CI/CD Pipeline / Create Release & Upload Assets (push) Blocked by required conditions
Flutter CI/CD Pipeline / Notify on Success (push) Blocked by required conditions
Flutter CI/CD Pipeline / Notify on Failure (push) Blocked by required conditions
Flutter CI/CD Pipeline / Clean Workspace (push) Blocked by required conditions
Reviewed-on: #2
2025-09-22 17:49:44 +08:00
7759267d0b Merge pull request 'develop_sky' (#1) from develop_sky into develop_sky_liyi
Some checks failed
Flutter CI/CD Pipeline / Print Environment (pull_request) Has been cancelled
Flutter CI/CD Pipeline / Generate Git Tag (pull_request) Has been cancelled
Flutter CI/CD Pipeline / Generate Next Version (pull_request) Has been cancelled
Flutter CI/CD Pipeline / Build Android APK/AAB (pull_request) Has been cancelled
Flutter CI/CD Pipeline / Build iOS IPA (pull_request) Has been cancelled
Flutter CI/CD Pipeline / Create Release & Upload Assets (pull_request) Has been cancelled
Flutter CI/CD Pipeline / Notify on Success (pull_request) Has been cancelled
Flutter CI/CD Pipeline / Notify on Failure (pull_request) Has been cancelled
Flutter CI/CD Pipeline / Clean Workspace (pull_request) Has been cancelled
Reviewed-on: #1
2025-09-22 17:48:19 +08:00
a8cc945d61 fix: 测试ci 2025-09-22 17:46:41 +08:00
725ef31640 fix: 测试ci
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 1m40s
2025-09-22 17:38:39 +08:00
1b70bd8b92 fix: 测试ci
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2025-09-22 17:33:51 +08:00
31123e503a fix: 测试ci 2025-09-22 17:28:58 +08:00
e8b2cf4660 fix: 调整插件版本 2025-09-22 17:17:00 +08:00
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
13bf53e964 fix: 增加注册账户时使用国外手机号获取验证码时进行提示 2025-09-17 09:34:33 +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
4d60ea4535 fix: 调整蓝牙开锁后直接同步上传卡片、密码、指纹人脸 2025-09-12 10:21:07 +08:00
393ee9d2bc fix: 增加注册页面点击后收起键盘 2025-09-10 09:17:38 +08:00
fac3c060e6 fix: 增加蓝牙开锁后同步密码、卡、指纹、人脸、遥控的钥匙信息 2025-09-06 14:50:32 +08:00
694df0282f fix: 调整操作记录中id和昵称的兼容显示 2025-09-06 14:50:08 +08:00
6b65661384 fix:语言包设置逻辑 2025-09-05 15:11:07 +08: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
1d0366414c fix:调整mtu设置 2025-09-04 17:01:56 +08: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
de297682bd fix:兼容没有新增读取、设置语音包协议的锁板 2025-09-03 17:07:25 +08: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
d18cd9645e fix:增加和读取锁板上的语音包设置 2025-09-01 14:30:26 +08: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
ca8b26d48b fix:调整语音设置 2025-09-01 09:31:34 +08: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
b2697eef17 fix:调整录音时不播放声音 2025-08-29 13:40:17 +08: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
1aea41026d fix:调整国际化内容 2025-08-28 13:59:22 +08:00
cafe132afc fix:调整录音时不播放声音 2025-08-28 13:41:53 +08: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
22887310c0 fix:调整音频结束时继续发送为0的音频包,而不是立即中断 2025-08-26 15:28:18 +08: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
d0b8f76303 fix:增加操作记录中的云存视频图像失效提示;国际化文本内容 2025-08-26 11:16:50 +08:00
4bbbac11a3 fix:调整音频增益逻辑 2025-08-26 11:14:19 +08:00
404ecf724f fix:调整猫眼切换工作模式时的loading状态 2025-08-22 14:26:23 +08: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
3e15966c64 fix:调整对讲音频发送速率 2025-08-22 13:35:42 +08:00
8a5e997262 Merge remote-tracking branch 'origin/develop_sky_liyi' into develop_sky_liyi 2025-08-22 09:57:07 +08:00
9a0a407022 fix:去除实时画面、取出异常告警设置 2025-08-22 09:57:03 +08: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
6e853024dc fix:调整对讲命令时使用实际款高度 2025-08-20 14:22:09 +08:00
103737cec0 fix:增加读取锁语音包命令 2025-08-20 14:20:06 +08:00
026e06a79f fix:调整云存页面内容 2025-08-20 10:06:03 +08:00
9fdf8377ee fix:调整视频缩略图、调整操作记录查询逻辑 2025-08-19 10:16:20 +08:00
335f66a0b5 fix:调整登录页面键盘无法收起的问题 2025-08-18 18:18:02 +08:00
f48e7c8274 fix:调整操作记录中UI(未完成) 2025-08-18 18:17:41 +08:00
c32f052cb0 fix:调整操作记录中UI(未完成) 2025-08-18 14:48:24 +08:00
477f4f21be fix:增加第三方协议的选项、增加多语言选项的英文名显示 2025-08-18 09:19:41 +08:00
1a6b44ece9 Merge remote-tracking branch 'origin/develop_sky_liyi' into develop_sky_liyi 2025-08-15 17:22:49 +08:00
f4e8b5e5ef fix:增加英文描述 2025-08-15 17:22:36 +08:00
f23eff1c09 fix:取消循环指纹的写死逻辑 2025-08-15 14:12:13 +08:00
fc3f27e951 fix:调整ios的录音发送逻辑 2025-08-15 13:55:39 +08:00
47ddb9b72a fix:调整ios的录音发送逻辑 2025-08-15 13:52:13 +08:00
88db0e850b fix:调整ios收到对讲后找到推送的消息并设置为已读 2025-08-15 13:51:11 +08: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
5ca0ba4a12 fix:调整依赖,为了修复ci的构建失败 2025-08-12 10:54:11 +08: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
b099c6101e fix:调整依赖,为了修复ci的构建失败 2025-08-12 10:39:12 +08: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
8667b4017f fix:调整依赖,为了修复ci的构建失败 2025-08-12 10:22:36 +08: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
9769501387 fix:调整依赖,为了修复ci的构建失败 2025-08-12 09:40:43 +08:00
0b1a9b69a3 fix:调整targetSdkVersion为google适配 2025-08-12 09:32:51 +08: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
9df1c3243b fix:调整操作记录中的显示文本 2025-08-08 09:55:16 +08:00
21ede72014 fix:增加巴西葡萄牙语 2025-08-08 09:54:54 +08:00
493fc19033 fix:调整循环密码的失效时间问题 2025-08-08 09:54:42 +08:00
f17a7feb9c fix:增加第三方协议平台设置的查询ttp接口 2025-08-08 09:54:23 +08:00
b0bd6515ac fix:增加第三方协议平台设置的查询ttp接口 2025-08-08 09:54:20 +08:00
2bfc84e428 fix:增加离线密码开锁的事件上报时增加密码字段 2025-08-07 14:19:50 +08:00
a5dcaae5a8 fix:增加巴西葡萄牙语 2025-08-07 10:47:08 +08:00
395e967abe fix:调整添加指纹时的步骤图片 2025-08-06 12:01:54 +08: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
46303ce2b9 fix:调整添加指纹时发送命令的阶段 2025-08-05 15:20:16 +08:00
8752c8dc41 fix:调整当添加完锁的锁出现已被重置逻辑的进行连接时将isReconnect设置为true 2025-08-05 15:19:42 +08:00
23a4008d2d fix:调整报警事件的文本为红色显示 2025-08-05 14:46:11 +08:00
c6e43651e1 fix:调整希腊语显示 2025-08-05 09:31:39 +08:00
c67db6e324 fix:调整操作记录中的id显示内容 2025-08-04 18:02:14 +08:00
0ab9b5f03a fix:调整ios和android页面不一致的问题 2025-08-04 15:54:19 +08:00
79948ff405 fix:调整新增指纹时的图片显示问题 2025-08-04 15:25:40 +08:00
862b87d5d1 fix:修复进入设置后还有loading的问题 2025-08-04 15:25:20 +08:00
295ce15fc4 fix:增加128bit的绑定状态判断改为位判断 2025-08-04 15:25:00 +08:00
5de4d4de57 fix:增加事件昵称中的id为录入时的记录姓名 2025-08-04 15:24:40 +08:00
aec0bc2b18 fix:增加首次发蓝牙端口后直接重发 2025-08-04 15:24:20 +08:00
93ce93bdd4 fix:修复进入设置后还有loading的问题 2025-08-04 15:23:58 +08: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
5a12e2acb4 fix:修复国际化翻译后出现name后缀的问题 2025-08-04 09:26:14 +08:00
adb7a25d1c fix:修复添加锁时台湾显示为繁体中文的问题 2025-07-31 17:08:46 +08:00
2583396e83 fix:修复备用电池显示0的问题 2025-07-31 15:24:27 +08:00
150 changed files with 11644 additions and 9591 deletions

251
.gitea/workflows/ci.yml Normal file
View File

@ -0,0 +1,251 @@
name: Flutter CI - Basic Setup
on:
push:
branches:
- master_sky
pull_request:
branches:
- master_sky
jobs:
# 基础设置任务:检出代码、提取版本号
basic-setup:
name: 🔧 Basic Setup
runs-on: sky
steps:
# 1. 检出代码
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 1
# 2. 提取版本号
- name: Extract Version
id: version
run: |
# 获取最新的tag按版本号排序匹配vX.X.X_sky格式
LATEST_TAG=$(git tag --list "v*.*.*_sky" --sort=-version:refname | head -1)
# 如果没有找到tag使用默认值
if [ -z "$LATEST_TAG" ]; then
LATEST_TAG="v1.0.0_sky"
echo "📌 No tags found, using default: $LATEST_TAG"
else
echo "📌 Latest tag found: $LATEST_TAG"
fi
# 提取基础版本号去除_sky后缀
BASE_VERSION=$(echo "$LATEST_TAG" | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1)
[ -z "$BASE_VERSION" ] && BASE_VERSION="v1.0.0"
echo "📌 Base version: $BASE_VERSION"
# 解析版本号各部分
MAJOR=$(echo $BASE_VERSION | cut -d'.' -f1 | sed 's/v//')
MINOR=$(echo $BASE_VERSION | cut -d'.' -f2)
PATCH=$(echo $BASE_VERSION | cut -d'.' -f3)
echo "📌 Version components: Major=$MAJOR, Minor=$MINOR, Patch=$PATCH"
# 计算下一个版本号
echo "📊 Calculating next version..."
# 获取当前提交与最新tag之间的所有提交消息
COMMIT_MESSAGES=$(git log --oneline --format=%s $LATEST_TAG..HEAD 2>/dev/null || echo "")
# 统计需要递增的提交次数(过滤重复的提交消息)
INCREMENT_COUNT=0
if [ -n "$COMMIT_MESSAGES" ]; then
# 使用awk过滤重复的提交消息并计数
UNIQUE_MESSAGES=$(echo "$COMMIT_MESSAGES" | awk '!seen[$0]++')
INCREMENT_COUNT=$(echo "$UNIQUE_MESSAGES" | wc -l)
echo "📝 Found $INCREMENT_COUNT unique commit(s) since last tag"
else
echo "📝 No new commits since last tag"
fi
# 计算新的版本号
NEW_PATCH=$((PATCH + INCREMENT_COUNT))
NEW_MINOR=$MINOR
NEW_MAJOR=$MAJOR
# 处理版本号进位逻辑
if [ $NEW_PATCH -ge 1000 ]; then
NEW_MINOR=$((NEW_MINOR + NEW_PATCH / 1000))
NEW_PATCH=$((NEW_PATCH % 1000))
echo "🔄 Patch version overflow, incrementing minor version"
fi
if [ $NEW_MINOR -ge 10 ]; then
NEW_MAJOR=$((NEW_MAJOR + NEW_MINOR / 10))
NEW_MINOR=$((NEW_MINOR % 10))
echo "🔄 Minor version overflow, incrementing major version"
fi
# 生成下一个版本号
NEXT_VERSION="v${NEW_MAJOR}.${NEW_MINOR}.${NEW_PATCH}"
NEXT_TAG="${NEXT_VERSION}_sky"
echo "🚀 Next version: $NEXT_VERSION"
echo "🏷️ Next tag: $NEXT_TAG"
echo "📈 Increment count: $INCREMENT_COUNT"
# 设置输出变量供后续任务使用Gitea Actions格式
echo "NEXT_VERSION=$NEXT_VERSION" >> $GITEA_OUTPUT
echo "NEXT_TAG=$NEXT_TAG" >> $GITEA_OUTPUT
echo "INCREMENT_COUNT=$INCREMENT_COUNT" >> $GITEA_OUTPUT
# 输出版本信息
echo "✅ Version extraction completed"
# 5. 任务完成通知
- name: Task Completion
run: |
echo "🎉 Basic CI setup completed successfully!"
echo ""
echo "📋 Tasks executed:"
echo " ✅ Code checkout"
echo " ✅ Version extraction"
echo ""
echo "🚀 Next steps: Building Flutter artifacts..."
# 构建Flutter制品任务
build-artifacts:
name: 🏗️ Build Flutter Artifacts
runs-on: sky
needs: basic-setup
steps:
# 1. 检出代码
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 1
# 4. 构建APK文件
- name: Build APK
run: |
echo "🏗️ Building APK artifact..."
# 生成当前时间作为build-number格式YYYYMMDDHH
BUILD_NUMBER=$(date +%Y%m%d%H)
echo "📅 Build number: $BUILD_NUMBER"
# 获取版本信息从basic-setup任务传递
echo "🔍 Getting version info from basic-setup job..."
# 设置默认版本号,如果环境变量为空
if [ -z "${{ needs.basic-setup.outputs.NEXT_VERSION }}" ]; then
VERSION_FOR_FILENAME="1-0-0"
echo "⚠️ Version not found, using default: $VERSION_FOR_FILENAME"
else
# 格式化版本号用于文件名
VERSION_FOR_FILENAME=$(echo "${{ needs.basic-setup.outputs.NEXT_VERSION }}" | sed 's/v//g' | sed 's/\./-/g')
echo "✅ Version found: $VERSION_FOR_FILENAME"
fi
# 设置APK文件名
APK_FILENAME="sky-star-lock-release-$VERSION_FOR_FILENAME.apk"
echo "📁 APK filename: $APK_FILENAME"
# 构建APK使用新的构建参数
flutter build apk --no-tree-shake-icons --release --flavor sky -t lib/main_sky_full.dart --build-number=$BUILD_NUMBER --build-name="sky-star-lock-release-$VERSION_FOR_FILENAME.apk"
# 重命名APK文件
mv build/app/outputs/flutter-apk/app-sky-release.apk "$APK_FILENAME"
echo "✅ APK build completed: $APK_FILENAME"
# 5. 构建AAB文件
- name: Build AAB
run: |
echo "🏗️ Building AAB artifact..."
# 生成当前时间作为build-number格式YYYYMMDDHH
BUILD_NUMBER=$(date +%Y%m%d%H)
echo "📅 Build number: $BUILD_NUMBER"
# 获取版本信息从basic-setup任务传递
echo "🔍 Getting version info from basic-setup job..."
# 设置默认版本号,如果环境变量为空
if [ -z "${{ needs.basic-setup.outputs.NEXT_VERSION }}" ]; then
VERSION_FOR_FILENAME="1-0-0"
echo "⚠️ Version not found, using default: $VERSION_FOR_FILENAME"
else
# 格式化版本号用于文件名
VERSION_FOR_FILENAME=$(echo "${{ needs.basic-setup.outputs.NEXT_VERSION }}" | sed 's/v//g' | sed 's/\./-/g')
echo "✅ Version found: $VERSION_FOR_FILENAME"
fi
# 设置AAB文件名
AAB_FILENAME="sky-star-lock-release-$VERSION_FOR_FILENAME.aab"
echo "📁 AAB filename: $AAB_FILENAME"
# 构建AAB使用新的构建参数
flutter build appbundle --no-tree-shake-icons --release --flavor sky -t lib/main_sky_full.dart --build-number=$BUILD_NUMBER --build-name="sky-star-lock-release-$VERSION_FOR_FILENAME.aab"
# 重命名AAB文件
mv build/app/outputs/bundle/skyRelease/app-sky-release.aab "$AAB_FILENAME"
echo "✅ AAB build completed: $AAB_FILENAME"
# 6. 构建iOS IPA文件如果支持iOS构建
- name: Build iOS IPA
if: runner.os == 'macos'
run: |
echo "🏗️ Building iOS IPA artifact..."
# 生成当前时间作为build-number格式YYYYMMDDHH
BUILD_NUMBER=$(date +%Y%m%d%H)
echo "📅 Build number: $BUILD_NUMBER"
# 获取版本信息从basic-setup任务传递
echo "🔍 Getting version info from basic-setup job..."
# 设置默认版本号,如果环境变量为空
if [ -z "${{ needs.basic-setup.outputs.NEXT_VERSION }}" ]; then
VERSION_FOR_FILENAME="1-0-0"
echo "⚠️ Version not found, using default: $VERSION_FOR_FILENAME"
else
# 格式化版本号用于文件名
VERSION_FOR_FILENAME=$(echo "${{ needs.basic-setup.outputs.NEXT_VERSION }}" | sed 's/v//g' | sed 's/\./-/g')
echo "✅ Version found: $VERSION_FOR_FILENAME"
fi
# 设置IPA文件名
IPA_FILENAME="sky-star-lock-release-$VERSION_FOR_FILENAME.ipa"
echo "📁 IPA filename: $IPA_FILENAME"
# 配置iOS自动签名CI环境使用自动签名
echo "🔧 Configuring iOS automatic code signing for CI environment..."
# 构建iOS IPA使用自动签名模式
flutter build ipa --no-tree-shake-icons --release --flavor sky -t lib/main_sky_full.dart --build-number=$BUILD_NUMBER --build-name="sky-star-lock-release-$VERSION_FOR_FILENAME.ipa" --codesign
# 重命名IPA文件
mv build/ios/ipa/*.ipa "$IPA_FILENAME"
echo "✅ iOS IPA build completed: $IPA_FILENAME"
# 7. 上传制品
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: flutter-artifacts-release
path: |
sky-star-lock-release-*.apk
sky-star-lock-release-*.aab
sky-star-lock-release-*.ipa
retention-days: 30
# 8. 构建完成通知
- name: Build Completion
run: |
echo "🎉 Flutter artifacts build completed successfully!"
echo ""
echo "📦 Artifacts generated:"
echo " ✅ APK: sky-star-lock-release-*.apk"
echo " ✅ AAB: sky-star-lock-release-*.aab"
if [ "${{ runner.os }}" == "macos" ]; then
echo " ✅ IPA: sky-star-lock-release-*.ipa"
fi
echo ""
echo "🏷️ Version: ${{ needs.basic-setup.outputs.NEXT_VERSION }}"
echo "📁 Files available in artifacts section"

View File

@ -73,6 +73,7 @@ variables:
- gem env - gem env
- bundle config mirror.https://rubygems.org https://mirrors.aliyun.com/rubygems/ - bundle config mirror.https://rubygems.org https://mirrors.aliyun.com/rubygems/
- bundle install --gemfile android/Gemfile --path vendor/bundle_android --quiet - bundle install --gemfile android/Gemfile --path vendor/bundle_android --quiet
- flutter clean
cache: cache:
paths: paths:
- app_new.version - app_new.version
@ -92,6 +93,7 @@ variables:
- gem env - gem env
- bundle config mirror.https://rubygems.org https://mirrors.aliyun.com/rubygems/ - bundle config mirror.https://rubygems.org https://mirrors.aliyun.com/rubygems/
- bundle install --gemfile ios/Gemfile --path vendor/bundle_ios --quiet - bundle install --gemfile ios/Gemfile --path vendor/bundle_ios --quiet
- flutter clean
cache: cache:
paths: paths:
- app_new.version - app_new.version

View File

@ -61,7 +61,7 @@ keytool -list -v -keystore android/app/sky.jks
``` ```
输入密码在android/app/build.gradle:38可以看到 输入密码在android/app/build.gradle:38可以看到
测试ci
一般需要的是:证书指纹-SHA1 看起来像 95:6B:***********共59个字符 一般需要的是:证书指纹-SHA1 看起来像 95:6B:***********共59个字符
## 编译 ## 编译

View File

@ -226,7 +226,7 @@ android {
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 25 minSdkVersion 25
targetSdkVersion 34 targetSdkVersion 35
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

View File

@ -63,6 +63,7 @@ platform :android do
print_log "last_git_commit_short_hash #{short_hash}" print_log "last_git_commit_short_hash #{short_hash}"
remove_zone_pre_build(zone:"com") remove_zone_pre_build(zone:"com")
Dir.chdir "../.." do Dir.chdir "../.." do
sh("flutter","clean")
sh("flutter","pub","get") sh("flutter","pub","get")
sh("flutter", "build", "apk", "--no-tree-shake-icons", "--release", "--flavor", "sky_#{env}", "-t", "lib/main_sky_#{env}.dart", "--build-number=#{build_number}", "--build-name=#{build_version}") sh("flutter", "build", "apk", "--no-tree-shake-icons", "--release", "--flavor", "sky_#{env}", "-t", "lib/main_sky_#{env}.dart", "--build-number=#{build_number}", "--build-name=#{build_version}")
end end

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
images/other/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
images/other/ai.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
images/other/matter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
images/other/tuya.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -75,6 +75,7 @@ platform :ios do
print_log "last_git_commit_short_hash #{short_hash}" print_log "last_git_commit_short_hash #{short_hash}"
remove_zone_pre_build(zone:"com") remove_zone_pre_build(zone:"com")
Dir.chdir "../.." do Dir.chdir "../.." do
sh("flutter","clean")
sh("flutter","pub","get") sh("flutter","pub","get")
end end
Dir.chdir ".." do Dir.chdir ".." do

File diff suppressed because it is too large Load Diff

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "След нулиране, метакарпалните вени на ключалката ще бъдат изтрити. Сигурен ли сте, че искате да се възстанови?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "След нулиране, метакарпалните вени на ключалката ще бъдат изтрити. Сигурен ли сте, че искате да се възстанови?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Заключване на настройките на гласовия пакет", "锁语音包设置": "Заключване на настройките на гласовия пакет",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Мъжки глас", "男声": "Мъжки глас",
"女声": "Женски глас" "女声": "Женски глас",
"您的图像和视频数据仅保留": "Данните ви за изображения и видеоклипове се запазват само",
"后图像和视频数据将会失效,开通": "След това данните за изображението и видеото ще бъдат невалидни и активирани",
"云存会员": "Членство в Cloud Storage",
"服务,图像视频信息随心存!": "Информацията за обслужване, изображения и видео са във вашето сърце!",
"图像": "изображение",
"视频": "Видео",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "В момента страната не поддържа регистрация на код за потвърждение на мобилен телефон, моля, използвайте имейл адреса си, за да се регистрирате",
"注:": "примечание:",
"必需在开始时间24小时内使用一次否则将失效": "Его необходимо использовать один раз в течение 24 часов с момента начала, иначе он будет недействительным.",
"这是单次密码,只能使用一次": "Это однократный пароль, который можно использовать только один раз.",
"您好": "Здравствуйте",
"您的开门密码是": "Ваш пароль",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "При открытии замка сначала активируйте клавиатуру замка, затем введите пароль, чтобы закончить #, # клавиша в правом нижнем углу клавиатуры, возможно, другие значки"
} }

View File

@ -83,8 +83,8 @@
"上班时间": "সিস্টেম", "上班时间": "সিস্টেম",
"下班时间": "ক্লাসিং", "下班时间": "ক্লাসিং",
"本周": "ইঙ্গোনেক", "本周": "ইঙ্গোনেক",
"单休": "এক-ডে-ওয়েওয়েন্ডName", "单休": "এক-ডে-ওয়েওয়েন্ড",
"双休": "টেটো-ডেওওয়েলেন্ডName", "双休": "টেটো-ডেওওয়েলেন্ড",
"单双休": "এক-টেটো-ডে-ওওয়েডেন্ড", "单双休": "এক-টেটো-ডে-ওওয়েডেন্ড",
"年": "ইয়ার", "年": "ইয়ার",
"月": "থ", "月": "থ",
@ -104,7 +104,7 @@
"门磁": "ডোরনেসিসর", "门磁": "ডোরনেসিসর",
"自动闭锁": "স্বয়ংক্রিয় লক", "自动闭锁": "স্বয়ংক্রিয় লক",
"锁声音": "লক", "锁声音": "লক",
"防撬报警": "ওয়েটperalertGenericName", "防撬报警": "ওয়েটperalertGeneric",
"重置键": "ইউনিটন", "重置键": "ইউনিটন",
"锁时间": "লকক", "锁时间": "লকক",
"诊断": "অ্যারিওনস", "诊断": "অ্যারিওনস",
@ -237,7 +237,7 @@
"搜索所有类型的锁": "স্যাকানাল্ডসপিসফক্স", "搜索所有类型的锁": "স্যাকানাল্ডসপিসফক্স",
"门锁": "ডোর-লক", "门锁": "ডোর-লক",
"挂锁": "আনলক", "挂锁": "আনলক",
"保险箱锁": "মাইন্টfelockGenericName", "保险箱锁": "মাইন্টfelockGeneric",
"智能门禁": "লিজেন্টেসেস কন্ট্রোল", "智能门禁": "লিজেন্টেসেস কন্ট্রোল",
"车位锁": "কিকিংলক", "车位锁": "কিকিংলক",
"摸亮触摸屏": "টুকরাইকিউট্ট", "摸亮触摸屏": "টুকরাইকিউট্ট",
@ -343,7 +343,7 @@
"卡": "বিকশিত", "卡": "বিকশিত",
"指纹": "ডিগ্রিমপ্রিন", "指纹": "ডিগ্রিমপ্রিন",
"人脸": "ফেস", "人脸": "ফেস",
"配件商城": "লককName", "配件商城": "লকক",
"公司名称": "অ্যাকম্পেনিনাম", "公司名称": "অ্যাকম্পেনিনাম",
"请输入公司名字": "কনস্টার অ্যাকম্পেনিনাম", "请输入公司名字": "কনস্টার অ্যাকম্পেনিনাম",
"提示": "চিন্ট", "提示": "চিন্ট",
@ -579,7 +579,7 @@
"请输入wifi名称": "ক্যাপিলাইজ", "请输入wifi名称": "ক্যাপিলাইজ",
"虹膜": "নিয়", "虹膜": "নিয়",
"手掌": "Pp", "手掌": "Pp",
"商城": "XmallName", "商城": "Xmall",
"我的": "My", "我的": "My",
"微信公众号推送": "ইয়াক", "微信公众号推送": "ইয়াক",
"蓝牙": "নিকট্রিয়াথ", "蓝牙": "নিকট্রিয়াথ",
@ -710,7 +710,7 @@
"传输期间请勿离开当前页面": "নির্দিষ্ট নেতৃত্বাধীন", "传输期间请勿离开当前页面": "নির্দিষ্ট নেতৃত্বাধীন",
"机型": "ডাইলস", "机型": "ডাইলস",
"硬件版本": "ডার্ওয়ারভেন্স", "硬件版本": "ডার্ওয়ারভেন্স",
"固件版本": "FmwareversionName", "固件版本": "Fmwareversion",
"手动升级": "ধুয়াল ফলাগ্রাড", "手动升级": "ধুয়াল ফলাগ্রাড",
"设备连接中...": "প্রাচীন...", "设备连接中...": "প্রাচীন...",
"未避免异常情况,请在门打开时升级": "সাউন oidযোগ্য exceptionstionsণনশনস, ক্যাপিলাইস", "未避免异常情况,请在门打开时升级": "সাউন oidযোগ্য exceptionstionsণনশনস, ক্যাপিলাইস",
@ -897,7 +897,7 @@
"配网成功": "নকর্ক ওয়ার্ক", "配网成功": "নকর্ক ওয়ার্ক",
"配网失败": "নবক ওয়ার্ক", "配网失败": "নবক ওয়ার্ক",
"该锁的无线键盘都将被删除": "অলসবিহীন", "该锁的无线键盘都将被删除": "অলসবিহীন",
"实时画面": "রিয়েল-টাইমপেসিচারName", "实时画面": "রিয়েল-টাইমপেসিচার",
"适合门口较为安全的环境。": "ভিডিওটেবল ফরফরাসী ইলেই মাইউইভেনমেন্টের দরজা।", "适合门口较为安全的环境。": "ভিডিওটেবল ফরফরাসী ইলেই মাইউইভেনমেন্টের দরজা।",
"仅发生特定事件才录像,并可查看实时画面。": "কেবলমাত্র আলোচনার কোর্সডন্ডথের রিয়েল-টাইমপিসিচার হয়ত।", "仅发生特定事件才录像,并可查看实时画面。": "কেবলমাত্র আলোচনার কোর্সডন্ডথের রিয়েল-টাইমপিসিচার হয়ত।",
"一般情况下满电可使用7-8个月": "আন্ডারমালবিক", "一般情况下满电可使用7-8个月": "আন্ডারমালবিক",
@ -996,7 +996,7 @@
"类型:自定义-永久": "টাইপ:", "类型:自定义-永久": "টাইপ:",
"实时播放": "রিয়েল-টাইমপিপ্লেব্যাক", "实时播放": "রিয়েল-টাইমপিপ্লেব্যাক",
"点击对讲": "ক্লিক্টোকম", "点击对讲": "ক্লিক্টোকম",
"长按开锁": "লংপ্রেসtocunlockGenericName", "长按开锁": "লংপ্রেসtocunlockGeneric",
"接听失败": "ডিফাইরেডটুআনসাইওয়ার", "接听失败": "ডিফাইরেডটুআনসাইওয়ার",
"请在锁设置中开启远程开锁": "ক্যাপিলাইজ এসব... ...সংকলকিং", "请在锁设置中开启远程开锁": "ক্যাপিলাইজ এসব... ...সংকলকিং",
"接听": "অ্যানসাওয়ার", "接听": "অ্যানসাওয়ার",
@ -1015,7 +1015,7 @@
"呼叫提醒": "ক্যান্সাল", "呼叫提醒": "ক্যান্সাল",
"收到来自": "আইভেদ্রোম", "收到来自": "আইভেদ্রোম",
"锁的呼叫": "লোককল", "锁的呼叫": "লোককল",
"加载数据中": "ব্লুডিং-ডাটাName", "加载数据中": "ব্লুডিং-ডাটা",
"搜索所有锁类型": "কোআরসার্লককপিস", "搜索所有锁类型": "কোআরসার্লককপিস",
"锁电量更新时间": "লক", "锁电量更新时间": "লক",
"1月": "জিনা", "1月": "জিনা",
@ -1031,7 +1031,7 @@
"11月": "নভ", "11月": "নভ",
"12月": "ব্লিক", "12月": "ব্লিক",
"热门城市": "আই", "热门城市": "আই",
"导出锁数据": "পোর্টlockdataName", "导出锁数据": "পোর্টlockdata",
"一键开锁": "এক-চ্যাক্লাক", "一键开锁": "এক-চ্যাক্লাক",
"已开通": "উত্স", "已开通": "উত্স",
"编辑员工": "এডিটওফ", "编辑员工": "এডিটওফ",
@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "ব্যান্ডোটারআইসেট, হাসিপাল রিরিইনস্ফথেলকবইল্ডজেডড।?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "ব্যান্ডোটারআইসেট, হাসিপাল রিরিইনস্ফথেলকবইল্ডজেডড।?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "ভয়েস প্যাকেজ সেটিংস লক করুন", "锁语音包设置": "ভয়েস প্যাকেজ সেটিংস লক করুন",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "পুরুষের কণ্ঠ", "男声": "পুরুষের কণ্ঠ",
"女声": "নারী কণ্ঠ" "女声": "নারী কণ্ঠ",
"您的图像和视频数据仅保留": "আপনার চিত্র এবং ভিডিও ডেটা কেবল ধরে রাখা হয়",
"后图像和视频数据将会失效,开通": "এর পরে, চিত্র এবং ভিডিও ডেটা অবৈধ এবং সক্রিয় হবে",
"云存会员": "ক্লাউড স্টোরেজ সদস্যতা",
"服务,图像视频信息随心存!": "পরিষেবা, চিত্র এবং ভিডিও তথ্য আপনার হৃদয়ে!",
"图像": "প্রতিচ্ছবি",
"视频": "ভিডিও",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "বর্তমানে, দেশটি মোবাইল ফোন যাচাইকরণ কোড নিবন্ধন সমর্থন করে না, নিবন্ধন করতে দয়া করে আপনার ইমেল ঠিকানা ব্যবহার করুন",
"注:": "নোট:",
"必需在开始时间24小时内使用一次否则将失效": "শুরু করার সময় 24 ঘন্টার মধ্যে একবার ব্যবহার করা প্রয়োজন, অন্যথায় এটি শেষ হবে",
"这是单次密码,只能使用一次": "এটি একক পাসওয়ার্ড, শুধুমাত্র একবার ব্যবহার করা যায়।",
"您好": "হ্যালো!",
"您的开门密码是": "আপনার দরজা খোলার পাসওয়ার্ড",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "লক খোলার সময়, প্রথমে লক কীবোর্ড সক্রিয় করুন, তারপর পাসওয়ার্ড টাইপ করুন, যা # সংখ্যা দিয়ে শেষ হয়, # সংখ্যা কী কীবোর্ডের নিচের"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Po resetování budou metakarpální žíly zámku odstraněny. Jste si jistý, že chcete resetovat?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Po resetování budou metakarpální žíly zámku odstraněny. Jste si jistý, že chcete resetovat?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Zamknout nastavení hlasového balíčku", "锁语音包设置": "Zamknout nastavení hlasového balíčku",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Mužský hlas", "男声": "Mužský hlas",
"女声": "Ženský hlas" "女声": "Ženský hlas",
"您的图像和视频数据仅保留": "Uchovávají se pouze vaše obrazová data a data videí",
"后图像和视频数据将会失效,开通": "Poté budou obrazová a video data neplatná a aktivovaná",
"云存会员": "Členství v cloudovém úložišti",
"服务,图像视频信息随心存!": "Servis, obrazové a video informace jsou na prvním místě!",
"图像": "obraz",
"视频": "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",
"注:": "Poznámka",
"必需在开始时间24小时内使用一次否则将失效": "Je nutné použít jednou do 24 hodin od začátku, jinak vyprší.",
"这是单次密码,只能使用一次": "Jedná se o jednorázové heslo, které lze použít pouze jednou.",
"您好": "Dobrý den.",
"您的开门密码是": "Vaše otevírací heslo je",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Při odemknutí nejprve aktivujte klávesnici pro zamyknutí a potom zadejte heslo, které končí číslem # a číslo # je v pravém dolním rohu klávesnice, může být další ikona"
} }

View File

@ -63,7 +63,7 @@
"授权管理员拥有操作这把锁的重要权限,请确保只发给我你信任的人": "Den autoriserede administrator har flertal tilladelse til at betjene denne lås.", "授权管理员拥有操作这把锁的重要权限,请确保只发给我你信任的人": "Den autoriserede administrator har flertal tilladelse til at betjene denne lås.",
"功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。": "Denne funktion giver dig mulighed for at låse Smart Lock fjernbetjening via en Gateway. Denne funktion kan kun slås til eller fra via Bluetooth.", "功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。": "Denne funktion giver dig mulighed for at låse Smart Lock fjernbetjening via en Gateway. Denne funktion kan kun slås til eller fra via Bluetooth.",
"排列方式": "Listetype", "排列方式": "Listetype",
"早到榜": "Tidlig listeName", "早到榜": "Tidlig liste",
"迟到榜": "Forsinkede lister", "迟到榜": "Forsinkede lister",
"当前模式": "Nuværende tilstand", "当前模式": "Nuværende tilstand",
"勤奋榜": "Arbejdshård liste:", "勤奋榜": "Arbejdshård liste:",
@ -116,7 +116,7 @@
"微信二维码": "Lås op QR- kode", "微信二维码": "Lås op QR- kode",
"拥有电子钥匙的人,通过微信扫一扫这个二维码,即可开门。每把锁的二维码都不相同,你可以将其打印出来贴在对应的锁旁边": "Folk med elektroniske nøgler kan åbne døren ved at scanne denne QR-kode gennem WeChat. QR-koden for hver lås er anderledes. Du kan udskrive det ud og indsætte det ved siden af den tilsvarende lås", "拥有电子钥匙的人,通过微信扫一扫这个二维码,即可开门。每把锁的二维码都不相同,你可以将其打印出来贴在对应的锁旁边": "Folk med elektroniske nøgler kan åbne døren ved at scanne denne QR-kode gennem WeChat. QR-koden for hver lås er anderledes. Du kan udskrive det ud og indsætte det ved siden af den tilsvarende lås",
"锁编号": "Låsnummer", "锁编号": "Låsnummer",
"电量": "BatteriName", "电量": "Batteri",
"锁分组": "Lås gruppen", "锁分组": "Lås gruppen",
"选择分组": "Vælg gruppe", "选择分组": "Vælg gruppe",
"创建新分组": "Opret en gruppe", "创建新分组": "Opret en gruppe",
@ -157,7 +157,7 @@
"选择锁类型": "Vælg låstype", "选择锁类型": "Vælg låstype",
"NFC无源锁": "NFC Passiv lås", "NFC无源锁": "NFC Passiv lås",
"添加设备": "Tilføj enhed", "添加设备": "Tilføj enhed",
"网关": "GatewayName", "网关": "Gateway",
"客服": "Kundeservice:", "客服": "Kundeservice:",
"设置": "Indstillinger", "设置": "Indstillinger",
"更多设置": "Mere sæt", "更多设置": "Mere sæt",
@ -185,7 +185,7 @@
"删除账号": "Slet konto", "删除账号": "Slet konto",
"个人信息": "Kontoinformation", "个人信息": "Kontoinformation",
"头像": "Avatar", "头像": "Avatar",
"昵称": "NickNameName", "昵称": "NickName",
"请输入昵称": "Indtast venligst dit kaldenavn", "请输入昵称": "Indtast venligst dit kaldenavn",
"修改昵称": "Omdøb", "修改昵称": "Omdøb",
"修改账号": "Redigér konto", "修改账号": "Redigér konto",
@ -213,10 +213,10 @@
"网关连接的锁": "Lås forbundet til denne Gateway", "网关连接的锁": "Lås forbundet til denne Gateway",
"信号强": "Stærk", "信号强": "Stærk",
"选择网关类型": "Vælg gateway- type", "选择网关类型": "Vælg gateway- type",
"添加网关": "Tilføj gatewayName", "添加网关": "Tilføj gateway",
"重新通电": "Tilslut kraften", "重新通电": "Tilslut kraften",
"指示灯": "Indikator Lys", "指示灯": "Indikator Lys",
"选择网关": "Vælg gatewayName", "选择网关": "Vælg gateway",
"不支持5G WiFi网络请选择2.4G WiFi网络进行配置": "5G understøttes ikke, Vælg et WiFi på 2.4G.", "不支持5G WiFi网络请选择2.4G WiFi网络进行配置": "5G understøttes ikke, Vælg et WiFi på 2.4G.",
"WiFi密码": "WiFi- adgangskort", "WiFi密码": "WiFi- adgangskort",
"请输入WiFi密码": "Indtast WiFi- adgangskode", "请输入WiFi密码": "Indtast WiFi- adgangskode",
@ -245,7 +245,7 @@
"附近的锁": "Nærlig låse", "附近的锁": "Nærlig låse",
"如需修改名字请重新命名,点击确定添加锁": "Hvis du vil ændre navnet, skal du omdøbe, klikke på OK for at tilføje låse", "如需修改名字请重新命名,点击确定添加锁": "Hvis du vil ændre navnet, skal du omdøbe, klikke på OK for at tilføje låse",
"添加锁时,手机必须在锁旁边": "Når du tilføjer en lås, skal telefonen være ved siden af låsen", "添加锁时,手机必须在锁旁边": "Når du tilføjer en lås, skal telefonen være ved siden af låsen",
"登录": "LoginName", "登录": "Login",
"注册": "Registrer", "注册": "Registrer",
"我已阅读并同意": "Jeg har læst og indvilliget", "我已阅读并同意": "Jeg har læst og indvilliget",
"验证码": "Kode", "验证码": "Kode",
@ -305,7 +305,7 @@
"胁迫卡": "Stresskort", "胁迫卡": "Stresskort",
"员工是否有密码": "Har allerede adgangskode", "员工是否有密码": "Har allerede adgangskode",
"员工是否有卡": "Har allerede kort", "员工是否有卡": "Har allerede kort",
"员工是否有指纹": "Sæt fingeraftrykket alleredeName", "员工是否有指纹": "Sæt fingeraftrykket allerede",
"获取钥匙": "Hent nøgle", "获取钥匙": "Hent nøgle",
"获取卡": "Hent kort", "获取卡": "Hent kort",
"获取指纹": "Hent fingeraftryk", "获取指纹": "Hent fingeraftryk",
@ -316,11 +316,11 @@
"开门器": "Døråbnere", "开门器": "Døråbnere",
"面容开锁": "Ansigt åbnes", "面容开锁": "Ansigt åbnes",
"开门方向设置": "Åbningsvejssæt", "开门方向设置": "Åbningsvejssæt",
"电机功率设置": "Indstilling af MotorPowerName", "电机功率设置": "Indstilling af MotorPower",
"开锁时是否需联网": "Hvis Internet er påkrævet ved oplåsning", "开锁时是否需联网": "Hvis Internet er påkrævet ved oplåsning",
"选择要加入分组的锁": "Vælg lockS der skal tilføjes til denne gruppe.", "选择要加入分组的锁": "Vælg lockS der skal tilføjes til denne gruppe.",
"锁数量": "Låstællinger", "锁数量": "Låstællinger",
"小米IOT平台": "Xiaomi IOT-platformName", "小米IOT平台": "Xiaomi IOT-platform",
"面容开锁设置": "Ansigtet låser op sæt", "面容开锁设置": "Ansigtet låser op sæt",
"感应距离": "Følelsesafstand", "感应距离": "Følelsesafstand",
"防误开": "Forhindre forkert åbning", "防误开": "Forhindre forkert åbning",
@ -365,7 +365,7 @@
"员工是否有人脸": "Om medarbejderen har et ansigt", "员工是否有人脸": "Om medarbejderen har et ansigt",
"同时删除员工钥匙": "Slet hans/ hendes ekey", "同时删除员工钥匙": "Slet hans/ hendes ekey",
"删除": "Slet", "删除": "Slet",
"确定要删除员工吗?": "Slet denne medarbejderName", "确定要删除员工吗?": "Slet denne medarbejder",
"月统计": "Månedlig statistik", "月统计": "Månedlig statistik",
"迟到": "Forsinker", "迟到": "Forsinker",
"早退": "Forsvind tidligt", "早退": "Forsvind tidligt",
@ -519,7 +519,7 @@
"网络访问失败,请检查网络是否正常": "Forespørgsel mislykkedes.Netværk utilgængelig, Kontroller og tilslut din enhed til 3G/4G/WIFI", "网络访问失败,请检查网络是否正常": "Forespørgsel mislykkedes.Netværk utilgængelig, Kontroller og tilslut din enhed til 3G/4G/WIFI",
"清空": "Ryd", "清空": "Ryd",
"是否清空?": "Forstået?", "是否清空?": "Forstået?",
"消息详情": "Brev- infoName", "消息详情": "Brev- info",
"创建时间": "Oprettelsestid", "创建时间": "Oprettelsestid",
"管理员详情": "Oplysninger om administrator", "管理员详情": "Oplysninger om administrator",
"当被胁迫要求强行开锁时,使用胁迫卡会触发报警,报警信息会推送给管理员,该功能需要锁联网。": "Hvis nogen tvinger dig til at åbne døren, kan du bruge dette kort. Alarmen vil blive sendt til administratorerne. For at bruge denne funktion, skal du sørge for din lås er online.", "当被胁迫要求强行开锁时,使用胁迫卡会触发报警,报警信息会推送给管理员,该功能需要锁联网。": "Hvis nogen tvinger dig til at åbne døren, kan du bruge dette kort. Alarmen vil blive sendt til administratorerne. For at bruge denne funktion, skal du sørge for din lås er online.",
@ -691,7 +691,7 @@
"请输入身份证号和真实姓名": "Indtast venligst dit ID- nummer og rigtige navn.", "请输入身份证号和真实姓名": "Indtast venligst dit ID- nummer og rigtige navn.",
"点击返回设备配对": "Tryk på Tilbage til enhedsparing", "点击返回设备配对": "Tryk på Tilbage til enhedsparing",
"无法连接?尝试升级": "Kan ikke forbinde?", "无法连接?尝试升级": "Kan ikke forbinde?",
"固件升级提示": "Prompt for opgradering af FirmwareName", "固件升级提示": "Prompt for opgradering af Firmware",
"请先获取固件文件到手机本地,再选择升级": "Få venligst firmware-filen til den lokale telefon først, og vælg derefter Opgrader", "请先获取固件文件到手机本地,再选择升级": "Få venligst firmware-filen til den lokale telefon først, og vælg derefter Opgrader",
"固件升级中": "Firmwaren bliver opgraderet", "固件升级中": "Firmwaren bliver opgraderet",
"取消升级": "Annullér opgraderingen", "取消升级": "Annullér opgraderingen",
@ -703,7 +703,7 @@
"传输中": "I transit", "传输中": "I transit",
"发送人": "Udstedt af:", "发送人": "Udstedt af:",
"发送时间": "Udstedt tid", "发送时间": "Udstedt tid",
"钥匙详情": "Ekey- infoName", "钥匙详情": "Ekey- info",
"姓名": "Navn", "姓名": "Navn",
"发送": "Send", "发送": "Send",
"请确认姓名全名和身份证号码是否正确": "Bekræft venligst, at det fulde navn og ID-nummer er korrekt.", "请确认姓名全名和身份证号码是否正确": "Bekræft venligst, at det fulde navn og ID-nummer er korrekt.",
@ -834,7 +834,7 @@
"微信": "WeChat", "微信": "WeChat",
"朋友圈": "Øjeblikker", "朋友圈": "Øjeblikker",
"QQ": "QQ", "QQ": "QQ",
"QQ空间": "QQZoneName", "QQ空间": "QQZone",
"微博": "Weibo Formand", "微博": "Weibo Formand",
"FaceBook": "Facebook", "FaceBook": "Facebook",
"链接": "Tilknytning", "链接": "Tilknytning",
@ -872,7 +872,7 @@
"再返回一次退出": "Afslut igen.", "再返回一次退出": "Afslut igen.",
"请先添加锁": "Tilføj venligst låsen først.", "请先添加锁": "Tilføj venligst låsen først.",
"可视对讲": "Visuel interkom.", "可视对讲": "Visuel interkom.",
"详细日志": "Detaljeret log logName", "详细日志": "Detaljeret log log",
"已复制到剪切板": "Kopieret", "已复制到剪切板": "Kopieret",
"拍照": "Fotografi", "拍照": "Fotografi",
"从相册选择": "Vælg mellem albumet", "从相册选择": "Vælg mellem albumet",
@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Efter nulstilling, de metacarpal vener i låsen vil blive slettet. Er du sikker på at du vil nulstille?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Efter nulstilling, de metacarpal vener i låsen vil blive slettet. Er du sikker på at du vil nulstille?",
@ -1099,7 +1100,7 @@
"支持的国家值": "USA, Canada, Storbritannien, Australien, Indien, Tyskland, Frankrig, Italien, Spanien, Japan.", "支持的国家值": "USA, Canada, Storbritannien, Australien, Indien, Tyskland, Frankrig, Italien, Spanien, Japan.",
"操作流程": "Driftsprocesser", "操作流程": "Driftsprocesser",
"操作流程值": "1 Tilføj en lås og gateway med Smart lås APP\n\n2 Aktiver den fjernlåsefunktion af låsen i APP (denne funktion er slukket som standard). Hvis du ikke har denne indstilling, understøtter låsen ikke Alexa\n\n3 Tilføj færdigheder til Alexa og autorisere dem med Smart lås APP konto og adgangskode. Når godkendelsen er vellykket, kan du opdage enheder under kontoen\n\n4 Find låsen i Alexa-appen, tænd stemme oplåsfunktionen og indstille adgangskoden for sproget.\n\n5 Låsen kan betjenes gennem Alexa", "操作流程值": "1 Tilføj en lås og gateway med Smart lås APP\n\n2 Aktiver den fjernlåsefunktion af låsen i APP (denne funktion er slukket som standard). Hvis du ikke har denne indstilling, understøtter låsen ikke Alexa\n\n3 Tilføj færdigheder til Alexa og autorisere dem med Smart lås APP konto og adgangskode. Når godkendelsen er vellykket, kan du opdage enheder under kontoen\n\n4 Find låsen i Alexa-appen, tænd stemme oplåsfunktionen og indstille adgangskoden for sproget.\n\n5 Låsen kan betjenes gennem Alexa",
"Google Home": "Google-hjemName", "Google Home": "Google-hjem",
"Action name": "Handlingsnavn", "Action name": "Handlingsnavn",
"ScienerSmart": "ScienerSmart", "ScienerSmart": "ScienerSmart",
"支持的语言": "Understøttede sprog", "支持的语言": "Understøttede sprog",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Lås stemmepakkeindstillinger", "锁语音包设置": "Lås stemmepakkeindstillinger",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Mandlige stemmer", "男声": "Mandlige stemmer",
"女声": "Kvindelige stemmer" "女声": "Kvindelige stemmer",
"您的图像和视频数据仅保留": "Dine billed- og videodata opbevares kun",
"后图像和视频数据将会失效,开通": "Derefter vil billed- og videodataene være ugyldige og aktiveret",
"云存会员": "Medlemskab af Cloud Storage",
"服务,图像视频信息随心存!": "Service-, billed- og videoinformation er i dit hjerte!",
"图像": "billede",
"视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "I øjeblikket understøtter landet ikke registrering af mobiltelefonbekræftelseskode, brug venligst din e-mailadresse til at tilmelde dig",
"注:": "Bemærk",
"必需在开始时间24小时内使用一次否则将失效": "Bruges én gang inden for 24 timer, ellers udløber",
"这是单次密码,只能使用一次": "Det er en enkelt adgangskode. Du kan kun bruge den én gang.",
"您好": "Goddag.",
"您的开门密码是": "Din adgangskode er",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Når du låser op, skal du først aktivere lås tastaturet, og derefter indtaste adgangskoden, der slutter med #nummer, #nummer i nederste højre hjørne af tastaturet, der kan være andre ikoner"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Nach dem Zurücksetzen werden die Mittelhand adern des Schlosses gelöscht. Sind Sie sicher, dass Sie zurücksetzen wollen?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Nach dem Zurücksetzen werden die Mittelhand adern des Schlosses gelöscht. Sind Sie sicher, dass Sie zurücksetzen wollen?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Sperren von Sprachpaketeinstellungen", "锁语音包设置": "Sperren von Sprachpaketeinstellungen",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Männliche Stimme", "男声": "Männliche Stimme",
"女声": "Frauenstimme" "女声": "Frauenstimme",
"您的图像和视频数据仅保留": "Ihre Bild- und Videodaten werden nur dann aufbewahrt",
"后图像和视频数据将会失效,开通": "Danach sind die Bild- und Videodaten ungültig und aktiviert",
"云存会员": "Cloud-Speicher-Mitgliedschaft",
"服务,图像视频信息随心存!": "Service-, Bild- und Videoinformationen liegen Ihnen am Herzen!",
"图像": "Bild",
"视频": "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",
"注:": "Hinweis:",
"必需在开始时间24小时内使用一次否则将失效": "Muss innerhalb von 24 Stunden nach Startzeit einmal verwendet werden, sonst läuft es ab",
"这是单次密码,只能使用一次": "Dies ist ein Einmal-Passwort und kann nur einmal verwendet werden",
"您好": "Hallo",
"您的开门密码是": "Ihr Türöffnungscode lautet",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Zum Entriegeln zuerst die Schloss-Tastatur aktivieren, dann das Passwort eingeben und mit # beenden. Die #-Taste befindet sich in der rechten unteren Ecke der Tastatur und kann ein anderes Symbol haben"
} }

View File

@ -97,7 +97,7 @@
"日榜": "Καθημερινά", "日榜": "Καθημερινά",
"月榜": "Μηνιαία", "月榜": "Μηνιαία",
"考勤记录": "Καταγραφή", "考勤记录": "Καταγραφή",
"假日信息": "Πληροφορίες διακοπώνName", "假日信息": "Πληροφορίες διακοπών",
"基本信息": "Βασικά", "基本信息": "Βασικά",
"无线键盘": "Ασύρματο πληκτρολόγιο", "无线键盘": "Ασύρματο πληκτρολόγιο",
"选择无线键盘": "Προσθήκη πληκτρολόγιου", "选择无线键盘": "Προσθήκη πληκτρολόγιου",
@ -185,7 +185,7 @@
"删除账号": "Διαγραφή λογαριασμού", "删除账号": "Διαγραφή λογαριασμού",
"个人信息": "Πληροφορίες λογαριασμού", "个人信息": "Πληροφορίες λογαριασμού",
"头像": "Άβαταρ", "头像": "Άβαταρ",
"昵称": "NickNameName", "昵称": "NickName",
"请输入昵称": "Παρακαλώ εισάγετε το ψευδώνυμό σας", "请输入昵称": "Παρακαλώ εισάγετε το ψευδώνυμό σας",
"修改昵称": "Μετονομασία", "修改昵称": "Μετονομασία",
"修改账号": "Επεξεργασία λογαριασμού", "修改账号": "Επεξεργασία λογαριασμού",
@ -693,7 +693,7 @@
"无法连接?尝试升级": "Δεν μπορείτε να συνδεθείτε;", "无法连接?尝试升级": "Δεν μπορείτε να συνδεθείτε;",
"固件升级提示": "Προτεινόμενη αναβάθμιση του Firmware", "固件升级提示": "Προτεινόμενη αναβάθμιση του Firmware",
"请先获取固件文件到手机本地,再选择升级": "Παρακαλώ αποκτήστε πρώτα το αρχείο firmware στο τοπικό τηλέφωνο και στη συνέχεια επιλέξτε Αναβάθμιση", "请先获取固件文件到手机本地,再选择升级": "Παρακαλώ αποκτήστε πρώτα το αρχείο firmware στο τοπικό τηλέφωνο και στη συνέχεια επιλέξτε Αναβάθμιση",
"固件升级中": "Το firmware αναβαθμίζεταιName", "固件升级中": "Το firmware αναβαθμίζεται",
"取消升级": "Ακύρωση της αναβάθμισης", "取消升级": "Ακύρωση της αναβάθμισης",
"固件传输中": "Άρθρο 10", "固件传输中": "Άρθρο 10",
"关闭": "Κλείσιμο", "关闭": "Κλείσιμο",
@ -834,7 +834,7 @@
"微信": "WeChat", "微信": "WeChat",
"朋友圈": "Στιγμές", "朋友圈": "Στιγμές",
"QQ": "QQ", "QQ": "QQ",
"QQ空间": "QQZoneName", "QQ空间": "QQZone",
"微博": "Γουίβο", "微博": "Γουίβο",
"FaceBook": "Βιβλίο Facebook", "FaceBook": "Βιβλίο Facebook",
"链接": "Δεσμός", "链接": "Δεσμός",
@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, οι μετακάρπιες φλέβες της κλειδαριάς θα διαγραφούν. Είστε σίγουροι ότι θέλετε να επαναφέρετε;", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, οι μετακάρπιες φλέβες της κλειδαριάς θα διαγραφούν. Είστε σίγουροι ότι θέλετε να επαναφέρετε;",
@ -1099,12 +1100,12 @@
"支持的国家值": "ΗΠΑ, Καναδάς, Ηνωμένο Βασίλειο, Αυστραλία, Ινδία, Γερμανία, Γαλλία, Ιταλία, Ισπανία, Ιαπωνία", "支持的国家值": "ΗΠΑ, Καναδάς, Ηνωμένο Βασίλειο, Αυστραλία, Ινδία, Γερμανία, Γαλλία, Ιταλία, Ισπανία, Ιαπωνία",
"操作流程": "Διαδικασία λειτουργίας", "操作流程": "Διαδικασία λειτουργίας",
"操作流程值": "1 Προσθέστε μια κλειδαριά και πύλη με την Smart κλειδαριά APP\n\n2 Ενεργοποιήστε τη λειτουργία απομακρυσμένου ξεκλειδώματος της κλειδαριάς στο APP (αυτή η συνάρτηση είναι απενεργοποιημένη από προεπιλογή). Αν δεν έχετε αυτή την επιλογή, η κλειδαριά δεν υποστηρίζει Alexa\n\n3 Προσθέστε τις δεξιότητες στην Alexa και να τις εξουσιοδοτήσετε με το λογαριασμό και τον κωδικό πρόσβασης Smart. Μετά την επιτυχία της εξουσιοδότησης, μπορείτε να ανακαλύψετε συσκευές κάτω από τον λογαριασμό\n\n4 Εντοπίστε την κλειδαριά στην εφαρμογή Alexa, ενεργοποιήστε τη λειτουργία φωνής ξεκλειδώματος, και να ορίσετε τον κωδικό πρόσβασης γλώσσας\n\n5 Η κλειδαριά μπορεί να λειτουργήσει μέσω Alexa", "操作流程值": "1 Προσθέστε μια κλειδαριά και πύλη με την Smart κλειδαριά APP\n\n2 Ενεργοποιήστε τη λειτουργία απομακρυσμένου ξεκλειδώματος της κλειδαριάς στο APP (αυτή η συνάρτηση είναι απενεργοποιημένη από προεπιλογή). Αν δεν έχετε αυτή την επιλογή, η κλειδαριά δεν υποστηρίζει Alexa\n\n3 Προσθέστε τις δεξιότητες στην Alexa και να τις εξουσιοδοτήσετε με το λογαριασμό και τον κωδικό πρόσβασης Smart. Μετά την επιτυχία της εξουσιοδότησης, μπορείτε να ανακαλύψετε συσκευές κάτω από τον λογαριασμό\n\n4 Εντοπίστε την κλειδαριά στην εφαρμογή Alexa, ενεργοποιήστε τη λειτουργία φωνής ξεκλειδώματος, και να ορίσετε τον κωδικό πρόσβασης γλώσσας\n\n5 Η κλειδαριά μπορεί να λειτουργήσει μέσω Alexa",
"Google Home": "Σπίτι του GoogleName", "Google Home": "Σπίτι του Google",
"Action name": "Όνομα ενέργειας", "Action name": "Όνομα ενέργειας",
"ScienerSmart": "ΕπιστήμοναςSmart", "ScienerSmart": "ΕπιστήμοναςSmart",
"支持的语言": "Υποστηριζόμενες γλώσσες", "支持的语言": "Υποστηριζόμενες γλώσσες",
"英语": "Αγγλική", "英语": "Αγγλική",
"Google Home操作流程的值": "1. Χρησιμοποιήστε το Smart Lock APP για να προσθέσετε κλειδαριές και πύλες\n\n2. Ενεργοποιήστε τη λειτουργία απομακρυσμένου ξεκλειδώματος της κλειδαριάς στο APP (αυτή η λειτουργία είναι απενεργοποιημένη από προεπιλογή). Χωρίς αυτή την επιλογή, η κλειδαριά δεν υποστηρίζει το Google HomeName\n\n3. Εγκαταστήστε το Google Home APP και κάντε κλικ στο \" \" πλήκτρο στην επάνω αριστερή γωνία\n\n4. Στη σελίδα Ρυθμίσεις, επιλέξτε \"Εργασία με Google\"\n\n5. Αναζητήστε το \"ScienerSmart\" και να χρησιμοποιήσετε τον έξυπνο λογαριασμό και τον κωδικό πρόσβασης για να εξουσιοδοτήσει", "Google Home操作流程的值": "1. Χρησιμοποιήστε το Smart Lock APP για να προσθέσετε κλειδαριές και πύλες\n\n2. Ενεργοποιήστε τη λειτουργία απομακρυσμένου ξεκλειδώματος της κλειδαριάς στο APP (αυτή η λειτουργία είναι απενεργοποιημένη από προεπιλογή). Χωρίς αυτή την επιλογή, η κλειδαριά δεν υποστηρίζει το Google Home\n\n3. Εγκαταστήστε το Google Home APP και κάντε κλικ στο \" \" πλήκτρο στην επάνω αριστερή γωνία\n\n4. Στη σελίδα Ρυθμίσεις, επιλέξτε \"Εργασία με Google\"\n\n5. Αναζητήστε το \"ScienerSmart\" και να χρησιμοποιήσετε τον έξυπνο λογαριασμό και τον κωδικό πρόσβασης για να εξουσιοδοτήσει",
"密码需至少包含数字/字母/字符中的2种组合": "Ο κωδικός πρόσβασης πρέπει να περιέχει τουλάχιστον 2 από τα ακόλουθα: αριθμούς, γράμματα και ειδικούς χαρακτήρες.", "密码需至少包含数字/字母/字符中的2种组合": "Ο κωδικός πρόσβασης πρέπει να περιέχει τουλάχιστον 2 από τα ακόλουθα: αριθμούς, γράμματα και ειδικούς χαρακτήρες.",
"已开锁": "Ξεκλείδωμα", "已开锁": "Ξεκλείδωμα",
"已闭锁": "Κλειδωμένο", "已闭锁": "Κλειδωμένο",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Ρυθμίσεις κλειδώματος πακέτου φωνής", "锁语音包设置": "Ρυθμίσεις κλειδώματος πακέτου φωνής",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Ανδρική φωνή", "男声": "Ανδρική φωνή",
"女声": "Γυναικεία φωνή" "女声": "Γυναικεία φωνή",
"您的图像和视频数据仅保留": "Τα δεδομένα εικόνας και βίντεο διατηρούνται μόνο",
"后图像和视频数据将会失效,开通": "Μετά από αυτό, τα δεδομένα εικόνας και βίντεο θα είναι άκυρα και θα ενεργοποιηθούν",
"云存会员": "Συνδρομή Cloud Storage",
"服务,图像视频信息随心存!": "Οι πληροφορίες εξυπηρέτησης, εικόνας και βίντεο είναι στην καρδιά σας!",
"图像": "εικόνα",
"视频": "Βίντεο",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Προς το παρόν, η χώρα δεν υποστηρίζει την εγγραφή κωδικού επαλήθευσης κινητού τηλεφώνου, χρησιμοποιήστε τη διεύθυνση email σας για να εγγραφείτε",
"注:": "Σημείωση:",
"必需在开始时间24小时内使用一次否则将失效": "Πρέπει να χρησιμοποιηθεί μία φορά εντός 24 ωρών από την ώρα έναρξης, διαφορετικά θα λήξει",
"这是单次密码,只能使用一次": "Είναι ένας μοναδικός κωδικός πρόσβασης. Μπορεί να χρησιμοποιηθεί μόνο μία φορά.",
"您好": "Γεια σας.",
"您的开门密码是": "Ο κωδικός σας είναι",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Όταν ξεκλειδώσετε, ενεργοποιήστε το πληκτρολόγιο κλειδαριού και πληκτρολογήστε τον κωδικό πρόσβασης, ο οποίος τελειώνει με το νούμερο # και το νούμερο # είναι στην κάτω δεξιά γωνία του πληκτρολόγιου, μπορεί να είναι ένα άλλο εικονίδιο"
} }

File diff suppressed because it is too large Load Diff

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Después del reinicio, se eliminarán las venas metacarpiales de la cerradura. ¿Está seguro de que desea restablecer?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Después del reinicio, se eliminarán las venas metacarpiales de la cerradura. ¿Está seguro de que desea restablecer?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Configuración del paquete de voz de bloqueo", "锁语音包设置": "Configuración del paquete de voz de bloqueo",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Voz masculina", "男声": "Voz masculina",
"女声": "Voz femenina" "女声": "Voz femenina",
"您的图像和视频数据仅保留": "Solo se conservan los datos de imagen y vídeo",
"后图像和视频数据将会失效,开通": "Después de eso, los datos de imagen y video no serán válidos y se activarán",
"云存会员": "Membresía de almacenamiento en la nube",
"服务,图像视频信息随心存!": "¡La información de servicio, imagen y video está en su corazón!",
"图像": "imagen",
"视频": "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",
"注:": "Nota",
"必需在开始时间24小时内使用一次否则将失效": "Debe usarse una vez dentro de las 24 horas de inicio, de lo contrario caducará.",
"这是单次密码,只能使用一次": "Esta es una contraseña única y solo se puede usar una vez.",
"您好": "Hola",
"您的开门密码是": "Su contraseña de apertura es",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Al abrir la cerradura, primero active el teclado de la cerradura e introduzca la contraseña para terminar con el número, la tecla de número está en la esquina inferior derecha del teclado, puede ser otro icono"
} }

View File

@ -55,7 +55,7 @@
"密码详情": "Parooli infoComment", "密码详情": "Parooli infoComment",
"修改密码": "Parooli muutmine", "修改密码": "Parooli muutmine",
"添加虹膜": "Lisa Iiris", "添加虹膜": "Lisa Iiris",
"添加门磁": "UksessensorName", "添加门磁": "Uksessensor",
"添加无线键盘": "Juhtmeta klaviatuuri", "添加无线键盘": "Juhtmeta klaviatuuri",
"添加手掌": "Lisa palmi", "添加手掌": "Lisa palmi",
"请输入员工账号": "Sisesta töötaja konto", "请输入员工账号": "Sisesta töötaja konto",
@ -101,7 +101,7 @@
"基本信息": "Põhimõtted", "基本信息": "Põhimõtted",
"无线键盘": "Juhtmeta klaviatuuri", "无线键盘": "Juhtmeta klaviatuuri",
"选择无线键盘": "Lisa klaviatuuri", "选择无线键盘": "Lisa klaviatuuri",
"门磁": "UksessensorName", "门磁": "Uksessensor",
"自动闭锁": "Automaatne lukustamine", "自动闭锁": "Automaatne lukustamine",
"锁声音": "Heli lukustamine", "锁声音": "Heli lukustamine",
"防撬报警": "Häire Tamperi", "防撬报警": "Häire Tamperi",
@ -185,7 +185,7 @@
"删除账号": "Kustuta konto", "删除账号": "Kustuta konto",
"个人信息": "Konto teave", "个人信息": "Konto teave",
"头像": "Avatar", "头像": "Avatar",
"昵称": "NikNameName", "昵称": "NikName",
"请输入昵称": "Palun sisesta oma hüüdnimi.", "请输入昵称": "Palun sisesta oma hüüdnimi.",
"修改昵称": "Nimeta ümber", "修改昵称": "Nimeta ümber",
"修改账号": "Redigeeri konto", "修改账号": "Redigeeri konto",
@ -503,8 +503,8 @@
"您的钥匙已冻结": "Sinu võti on külmutatud", "您的钥匙已冻结": "Sinu võti on külmutatud",
"您的钥匙已过期": "Sinu võti aegus", "您的钥匙已过期": "Sinu võti aegus",
"常开模式开启": "Lukk on läbisõidurežiimis", "常开模式开启": "Lukk on läbisõidurežiimis",
"超级管理员": "Super adminName", "超级管理员": "Super admin",
"授权管理员": "Lubatud adminName", "授权管理员": "Lubatud admin",
"普通用户": "Tavaline kasutaja", "普通用户": "Tavaline kasutaja",
"余": "Saldos", "余": "Saldos",
"天": "Päev", "天": "Päev",
@ -558,7 +558,7 @@
"密码生成后请在当日2359前使用否则过0点后失效。清空码用于清空今天0点之前生成的所有密码。": "Pärast parooli loomist palun kasutage seda enne 23:59 samal päeval, vastasel juhul on see kehtetu pärast kella 0. Selge koodi kasutatakse kõigi loodud paroolide tühjendamiseks täna enne kella 0.", "密码生成后请在当日2359前使用否则过0点后失效。清空码用于清空今天0点之前生成的所有密码。": "Pärast parooli loomist palun kasutage seda enne 23:59 samal päeval, vastasel juhul on see kehtetu pärast kella 0. Selge koodi kasutatakse kõigi loodud paroolide tühjendamiseks täna enne kella 0.",
"密码生成后请在当日2359前使用否则过0点后失效。": "Pärast parooli loomist palun kasutage seda enne 23:59 samal päeval, vastasel juhul on see kehtetu pärast kella 0.", "密码生成后请在当日2359前使用否则过0点后失效。": "Pärast parooli loomist palun kasutage seda enne 23:59 samal päeval, vastasel juhul on see kehtetu pärast kella 0.",
"清空密码底部提示": "Parool kehtib kuni 23:59 tühjendamise päeval", "清空密码底部提示": "Parool kehtib kuni 23:59 tühjendamise päeval",
"相机": "KaameraName", "相机": "Kaamera",
"相册": "Fotod", "相册": "Fotod",
"读写": "Säilitamine", "读写": "Säilitamine",
"定位": "Asukoht", "定位": "Asukoht",
@ -582,7 +582,7 @@
"商城": "Kaubamaja", "商城": "Kaubamaja",
"我的": "Minu", "我的": "Minu",
"微信公众号推送": "Jutt avalik konto", "微信公众号推送": "Jutt avalik konto",
"蓝牙": "BluetoothName", "蓝牙": "Bluetooth",
"需要访问蓝牙权限才能使用添加钥匙功能的位置信息": "Juurdepääs Bluetooth-i õigustele on vaja, et kasutada asukoha lisamise funktsiooni asukoha teavet", "需要访问蓝牙权限才能使用添加钥匙功能的位置信息": "Juurdepääs Bluetooth-i õigustele on vaja, et kasutada asukoha lisamise funktsiooni asukoha teavet",
"请输入Email": "Sisesta oma e- postil", "请输入Email": "Sisesta oma e- postil",
"请输入手机号": "Sisesta oma telefoninumber", "请输入手机号": "Sisesta oma telefoninumber",
@ -604,7 +604,7 @@
"家人": "Pereliigem", "家人": "Pereliigem",
"保存": "Salvesta", "保存": "Salvesta",
"APP推送": "APP lükkamine", "APP推送": "APP lükkamine",
"管理员": "AdministraatorName", "管理员": "Administraator",
"未启用": "Pole lubatud", "未启用": "Pole lubatud",
"已启用": "Lubatud", "已启用": "Lubatud",
"省电模式": "Energiasäästu režiim", "省电模式": "Energiasäästu režiim",
@ -613,7 +613,7 @@
"自定义模式": "Kohandatud režiim", "自定义模式": "Kohandatud režiim",
"猫眼设置": "Kassilmade seadmine", "猫眼设置": "Kassilmade seadmine",
"猫眼工作模式": "Kassilmade töörežiim", "猫眼工作模式": "Kassilmade töörežiim",
"自动亮屏": "Automaatne erekraanName", "自动亮屏": "Automaatne erekraan",
"亮屏持续时间": "Ekraan õigel ajal", "亮屏持续时间": "Ekraan õigel ajal",
"逗留警告": "Hoiatus.", "逗留警告": "Hoiatus.",
"异常警告": "Ebatavaline hoiatus.", "异常警告": "Ebatavaline hoiatus.",
@ -745,7 +745,7 @@
"为了让您及时收到重要通知和更新,我们需要获取通知权限。请点击“确定”按钮,然后在设置页面中启用通知权限。": "Oluliste uuenduste saamiseks klõpsake \"OK\" ja lubage teated seaded.", "为了让您及时收到重要通知和更新,我们需要获取通知权限。请点击“确定”按钮,然后在设置页面中启用通知权限。": "Oluliste uuenduste saamiseks klõpsake \"OK\" ja lubage teated seaded.",
"开启后可通过长按锁上的设置键重新上电用APP重新添加": "Pärast sisselülitamist saad uuesti sisse vajutada klahvi lukk ja lisada see uuesti APP abil", "开启后可通过长按锁上的设置键重新上电用APP重新添加": "Pärast sisselülitamist saad uuesti sisse vajutada klahvi lukk ja lisada see uuesti APP abil",
"已有": "Praegune", "已有": "Praegune",
"新增": "UusName", "新增": "Uus",
"账号格式错误": "Halb vormingus", "账号格式错误": "Halb vormingus",
"接收者信息为空": "Saaja teave on tühi", "接收者信息为空": "Saaja teave on tühi",
"请输入时间(秒)": "Palun sisesta kellaaeg (sek)", "请输入时间(秒)": "Palun sisesta kellaaeg (sek)",
@ -770,7 +770,7 @@
"转移成功": "Ülekandmine", "转移成功": "Ülekandmine",
"该已锁被删除": "Lukustatud on kustutatud", "该已锁被删除": "Lukustatud on kustutatud",
"授权管理员只能查看和管理自己下发的钥匙、密码等权限": "Volitatud admin saab hallata ainult salakoode,ekeys ja etccreated ise.", "授权管理员只能查看和管理自己下发的钥匙、密码等权限": "Volitatud admin saab hallata ainult salakoode,ekeys ja etccreated ise.",
"添加授权管理员": "Loo adminName", "添加授权管理员": "Loo admin",
"导出记录": "Eksporditeenused", "导出记录": "Eksporditeenused",
"选择时间段": "Vali ajavahemik", "选择时间段": "Vali ajavahemik",
"导出": "Eksport", "导出": "Eksport",
@ -834,7 +834,7 @@
"微信": "WeChat", "微信": "WeChat",
"朋友圈": "Hetked", "朋友圈": "Hetked",
"QQ": "QQ", "QQ": "QQ",
"QQ空间": "QQZoneName", "QQ空间": "QQZone",
"微博": "WeiboComment", "微博": "WeiboComment",
"FaceBook": "FaceBook", "FaceBook": "FaceBook",
"链接": "Lingi", "链接": "Lingi",
@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Pärast lähtestamist kustutatakse luku metakarpaalveenid. Kas tõesti soovid lähtestada?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Pärast lähtestamist kustutatakse luku metakarpaalveenid. Kas tõesti soovid lähtestada?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Lukustage häälepaketi seaded", "锁语音包设置": "Lukustage häälepaketi seaded",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Meeste hääl", "男声": "Meeste hääl",
"女声": "Naiste hääl" "女声": "Naiste hääl",
"您的图像和视频数据仅保留": "Teie pildi- ja videoandmeid säilitatakse ainult",
"后图像和视频数据将会失效,开通": "Pärast seda on pildi- ja videoandmed kehtetud ja aktiveeritud",
"云存会员": "Pilvesalvestuse liikmelisus",
"服务,图像视频信息随心存!": "Teenindus-, pildi- ja videoteave on teie südames!",
"图像": "Piltide",
"视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Praegu ei toeta riik mobiiltelefoni kinnituskoodi registreerimist, palun kasutage registreerumiseks oma e-posti aadressi",
"注:": "Märkus",
"必需在开始时间24小时内使用一次否则将失效": "Kasutada tuleb 24 tunni jooksul, muidu kaotab kehtivus.",
"这是单次密码,只能使用一次": "See on ühekordne parool, mida saab kasutada ainult üks kord.",
"您好": "Tere. Tere.",
"您的开门密码是": "Teie salasõna on",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Lukustamisel aktiveerige klaviatuur, seejärel sisestage parool, mis lõpeb numbriga # klaviatuuri paremas alumises nurgas, võib olla muud ikoonid"
} }

View File

@ -185,7 +185,7 @@
"删除账号": "Poista tili", "删除账号": "Poista tili",
"个人信息": "Tilitiedot", "个人信息": "Tilitiedot",
"头像": "Avatar", "头像": "Avatar",
"昵称": "NickNameName", "昵称": "NickName",
"请输入昵称": "Anna nimitysi", "请输入昵称": "Anna nimitysi",
"修改昵称": "Nimeä uudelleen", "修改昵称": "Nimeä uudelleen",
"修改账号": "Muokkaa tiliä", "修改账号": "Muokkaa tiliä",
@ -216,7 +216,7 @@
"添加网关": "Lisää porttiComment", "添加网关": "Lisää porttiComment",
"重新通电": "Yhdistä teho", "重新通电": "Yhdistä teho",
"指示灯": "Indikaattori Valo", "指示灯": "Indikaattori Valo",
"选择网关": "Valitse porttiName", "选择网关": "Valitse portti",
"不支持5G WiFi网络请选择2.4G WiFi网络进行配置": "5G ei ole tuettu, valitse 2.4G:n WiFi.", "不支持5G WiFi网络请选择2.4G WiFi网络进行配置": "5G ei ole tuettu, valitse 2.4G:n WiFi.",
"WiFi密码": "WiFi", "WiFi密码": "WiFi",
"请输入WiFi密码": "Syötä WiFi- salasana.", "请输入WiFi密码": "Syötä WiFi- salasana.",
@ -232,7 +232,7 @@
"使用静态IP": "Käytä staattista IP", "使用静态IP": "Käytä staattista IP",
"请输入IP地址": "Anna IP- osoite", "请输入IP地址": "Anna IP- osoite",
"请输入子网掩码": "Syötä aliverkkomaa", "请输入子网掩码": "Syötä aliverkkomaa",
"请输入默认网关": "Siirry oletusporttiName", "请输入默认网关": "Siirry oletusportti",
"所有锁": "Kaikki lukot", "所有锁": "Kaikki lukot",
"搜索所有类型的锁": "Skannaa kaikenlaisia lukkoja", "搜索所有类型的锁": "Skannaa kaikenlaisia lukkoja",
"门锁": "Ovilukko", "门锁": "Ovilukko",
@ -582,7 +582,7 @@
"商城": "Ostoskeskus", "商城": "Ostoskeskus",
"我的": "Minun", "我的": "Minun",
"微信公众号推送": "Keskustele julkinen tili", "微信公众号推送": "Keskustele julkinen tili",
"蓝牙": "BluetoothName", "蓝牙": "Bluetooth",
"需要访问蓝牙权限才能使用添加钥匙功能的位置信息": "Pääsy Bluetooth-oikeuksiin vaaditaan käyttämään sijaintitietoja lisätä avaintoiminnon lisäämiseksi", "需要访问蓝牙权限才能使用添加钥匙功能的位置信息": "Pääsy Bluetooth-oikeuksiin vaaditaan käyttämään sijaintitietoja lisätä avaintoiminnon lisäämiseksi",
"请输入Email": "Anna sähköposti", "请输入Email": "Anna sähköposti",
"请输入手机号": "Anna puhelinnumero", "请输入手机号": "Anna puhelinnumero",
@ -834,7 +834,7 @@
"微信": "Wechat", "微信": "Wechat",
"朋友圈": "Hetket", "朋友圈": "Hetket",
"QQ": "QQ", "QQ": "QQ",
"QQ空间": "QQZoneName", "QQ空间": "QQZone",
"微博": "Weibo", "微博": "Weibo",
"FaceBook": "FaceBook", "FaceBook": "FaceBook",
"链接": "Linkkiä", "链接": "Linkkiä",
@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Kun lukko on nollattu, metakarppinen suoneet poistetaan. Haluatko varmasti palauttaa?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Kun lukko on nollattu, metakarppinen suoneet poistetaan. Haluatko varmasti palauttaa?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Lukitse äänipaketin asetukset", "锁语音包设置": "Lukitse äänipaketin asetukset",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Miehen ääni", "男声": "Miehen ääni",
"女声": "Naisten ääni" "女声": "Naisten ääni",
"您的图像和视频数据仅保留": "Kuva- ja videotietosi säilytetään vain",
"后图像和视频数据将会失效,开通": "Sen jälkeen kuva- ja videotiedot ovat virheellisiä ja aktivoituvat",
"云存会员": "Pilvitallennustilan jäsenyys",
"服务,图像视频信息随心存!": "Palvelu-, kuva- ja videotiedot ovat sydämessäsi!",
"图像": "kuva",
"视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Tällä hetkellä maa ei tue matkapuhelimen vahvistuskoodin rekisteröintiä, käytä rekisteröitymiseen sähköpostiosoitettasi",
"注:": "Huomautus",
"必需在开始时间24小时内使用一次否则将失效": "Käytä kerran 24 tunnin kuluessa, muuten se päättyy.",
"这是单次密码,只能使用一次": "Tämä on yksittäinen salasana, jota voidaan käyttää vain kerran.",
"您好": "Tervehdys.",
"您的开门密码是": "Salasanasi on",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Kun avaat lukituksen, aktivoi lukitusnäppäimistö ensin ja kirjoita salasana, joka päättyy # numerolla, # näppäimistö on näppäimistön oikeassa alakulmassa, mahdollisesti muut kuvakkeet"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Après réinitialisation, les veines métacarpiennes de la serrure seront supprimées. Êtes-vous sûr de vouloir réinitialiser?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Après réinitialisation, les veines métacarpiennes de la serrure seront supprimées. Êtes-vous sûr de vouloir réinitialiser?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Paramètres du pack Lock Voice", "锁语音包设置": "Paramètres du pack Lock Voice",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Voix masculine", "男声": "Voix masculine",
"女声": "Voix de femmes" "女声": "Voix de femmes",
"您的图像和视频数据仅保留": "Vos données dimage et de vidéo ne sont conservées que",
"后图像和视频数据将会失效,开通": "Après cela, les données de limage et de la vidéo seront invalides et activées",
"云存会员": "Adhésion au stockage dans le cloud",
"服务,图像视频信息随心存!": "Le service, limage et les informations vidéo sont au cœur de vos préoccupations !",
"图像": "image",
"视频": "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",
"注:": "Remarque:",
"必需在开始时间24小时内使用一次否则将失效": "Doit être utilisé une fois dans les 24 heures suivant l'heure de début, sinon il expirera",
"这是单次密码,只能使用一次": "Ceci est un mot de passe à usage unique et ne peut être utilisé qu'une seule fois",
"您好": "Bonjour",
"您的开门密码是": "Votre code d'accès à la porte est",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Pour déverrouiller, activez d'abord le clavier du verrou, entrez ensuite le mot de passe et terminez par #. La touche # se trouve dans le coin inférieur droit du clavier et peut avoir une icône différente"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "לאחר איפוס, הורידים של המנעול יימחקו. אתה בטוח שברצונך לאפס?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "לאחר איפוס, הורידים של המנעול יימחקו. אתה בטוח שברצונך לאפס?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "הגדרות חבילת קול לנעול", "锁语音包设置": "הגדרות חבילת קול לנעול",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "קול גבר", "男声": "קול גבר",
"女声": "קול נשי" "女声": "קול נשי",
"您的图像和视频数据仅保留": "נתוני התמונה והסרטונים נשמרים רק",
"后图像和视频数据将会失效,开通": "לאחר מכן, נתוני התמונה והווידאו לא יהיו חוקיים ויופעלו",
"云存会员": "חברות באחסון בענן",
"服务,图像视频信息随心存!": "מידע על שירות, תמונה ווידאו נמצאים בלב שלך!",
"图像": "תמונה",
"视频": "וידאו",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "נכון לעכשיו, המדינה אינה תומכת ברישום קוד אימות טלפון נייד, אנא השתמש בכתובת הדוא\"ל שלך כדי להירשם",
"注:": "הערה:",
"必需在开始时间24小时内使用一次否则将失效": "יש להשתמש בו פעם אחת בתוך 24 שעות מזמן ההתחלה, אחרת הוא יפוג",
"这是单次密码,只能使用一次": "זו סיסמה חד-פעמית שניתן להשתמש בה רק פעם אחת",
"您好": "שלום",
"您的开门密码是": "קוד הפתיחה שלך הוא",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "כדי לבטל את הנעילה, הפעל תחילה את מקלדת המנעול, לאחר מכן הזן את הסיסמה וסיים ב-#. המקש # נמצא בפינה הימנית התחתונה של המקלדת ועשוי להיות סמל אחר"
} }

View File

@ -1067,7 +1067,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1080,10 +1080,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "रीसेट के बाद, लॉक के मेटाकार्पल नसों को हटा दिया जाएगा। क्या आप निश्चित रूप से रीसेट करना चाहते हैं?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "रीसेट के बाद, लॉक के मेटाकार्पल नसों को हटा दिया जाएगा। क्या आप निश्चित रूप से रीसेट करना चाहते हैं?",
@ -1145,7 +1146,7 @@
"网关添加成功": "गेटवे सफलतापूर्वक जोड़ा गया", "网关添加成功": "गेटवे सफलतापूर्वक जोड़ा गया",
"呼叫目标": "कॉल लक्ष्य", "呼叫目标": "कॉल लक्ष्य",
"管理员APP": "व्यवस्थापक एप", "管理员APP": "व्यवस्थापक एप",
"可视门铃码": "Name", "可视门铃码": "दृश्यमान दरवाजा घंटी कोड",
"电子反锁": "इलेक्ट्रॉनिक विरोधी लॉक", "电子反锁": "इलेक्ट्रॉनिक विरोधी लॉक",
"双重认证": "द्वि-कारक प्रमाणीकरण", "双重认证": "द्वि-कारक प्रमाणीकरण",
"双锁联动": "द्वि पाश सहलग्नता", "双锁联动": "द्वि पाश सहलग्नता",
@ -1160,5 +1161,18 @@
"锁语音包设置": "आवाज पैकेज सेटिंग्स ताला लगाएँ", "锁语音包设置": "आवाज पैकेज सेटिंग्स ताला लगाएँ",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "पुरुष आवाज", "男声": "पुरुष आवाज",
"女声": "महिला आवाज" "女声": "महिला आवाज",
"您的图像和视频数据仅保留": "आपकी छवि और वीडियो डेटा केवल बनाए रखा जाता है",
"后图像和视频数据将会失效,开通": "उसके बाद, छवि और वीडियो डेटा अमान्य और सक्रिय हो जाएगा",
"云存会员": "क्लाउड स्टोरेज सदस्यता",
"服务,图像视频信息随心存!": "सेवा, छवि और वीडियो जानकारी आपके दिल में हैं!",
"图像": "प्रतिबिंब",
"视频": "वीडियो",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "वर्तमान में, देश मोबाइल फोन सत्यापन कोड पंजीकरण का समर्थन नहीं करता है, कृपया पंजीकरण करने के लिए अपने ईमेल पते का उपयोग करें",
"注:": "नोट:",
"必需在开始时间24小时内使用一次否则将失效": "आरंभ समय के 24 घंटे के भीतर एक बार उपयोग करना आवश्यक है, अन्यथा इसकी समय सीमा समाप्त हो जाएगी",
"这是单次密码,只能使用一次": "यह एकल उपयोग का पासवर्ड है और केवल एक बार उपयोग किया जा सकता है",
"您好": "नमस्ते",
"您的开门密码是": "आपका दरवाज़ा खोलने का कोड है",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "अनलॉक करने के लिए, पहले लॉक कीबोर्ड को सक्रिय करें, फिर पासवर्ड दर्ज करें और # के साथ समाप्त करें। # कुंजी कीबोर्ड के निचले दाएं कोने में है और इसमें कोई अन्य चिह्न हो सकता है"
} }

View File

@ -1043,7 +1043,6 @@
"一键开锁": "一鍵解鎖", "一键开锁": "一鍵解鎖",
"已开通": "打開", "已开通": "打開",
"英文": "English", "英文": "English",
"英文": "English",
"简体中文": "简体中文", "简体中文": "简体中文",
"繁体中文": "繁體中文", "繁体中文": "繁體中文",
"法语": "Français", "法语": "Français",
@ -1066,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1079,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "重置後,鎖的掌靜脈將被刪除。 你確定要重置啊?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "重置後,鎖的掌靜脈將被刪除。 你確定要重置啊?",
@ -1161,5 +1161,18 @@
"锁语音包设置": "鎖語音包設定", "锁语音包设置": "鎖語音包設定",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "男聲", "男声": "男聲",
"女声": "女聲" "女声": "女聲",
"您的图像和视频数据仅保留": "您的圖像和視頻數據僅保留",
"后图像和视频数据将会失效,开通": "后圖像和視頻數據將會失效,開通",
"云存会员": "雲存會員",
"服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!",
"图像": "圖像",
"视频": "視頻",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "當前國家不支援手機驗證碼註冊,請使用郵箱進行註冊",
"注:": "註:",
"必需在开始时间24小时内使用一次否则将失效": "必須在開始時間24小時內使用一次否則將失效",
"这是单次密码,只能使用一次": "這是單次密碼,只能使用一次",
"您好": "您好",
"您的开门密码是": "您的開門密碼是",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "開鎖時,先啟動鎖鍵盤,再輸入密碼,以#號結束,#號鍵在鍵盤右下角,有可能是其他圖標"
} }

View File

@ -185,7 +185,7 @@
"删除账号": "Obriši korisnički račun.", "删除账号": "Obriši korisnički račun.",
"个人信息": "Informacije o računu", "个人信息": "Informacije o računu",
"头像": "Avatar", "头像": "Avatar",
"昵称": "NickNameName", "昵称": "NickName",
"请输入昵称": "Molim, unesite svoj nadimak", "请输入昵称": "Molim, unesite svoj nadimak",
"修改昵称": "Preimenuj", "修改昵称": "Preimenuj",
"修改账号": "Uredi korisnički račun.", "修改账号": "Uredi korisnički račun.",
@ -316,7 +316,7 @@
"开门器": "Otvarač vrata", "开门器": "Otvarač vrata",
"面容开锁": "Otključa lice", "面容开锁": "Otključa lice",
"开门方向设置": "Smjer otvaranja", "开门方向设置": "Smjer otvaranja",
"电机功率设置": "Postavljanje MotorPowerName", "电机功率设置": "Postavljanje MotorPower",
"开锁时是否需联网": "Ako je internet potreban prilikom otključavanja", "开锁时是否需联网": "Ako je internet potreban prilikom otključavanja",
"选择要加入分组的锁": "Odaberite zaključavanje za dodavanje ovoj grupi", "选择要加入分组的锁": "Odaberite zaključavanje za dodavanje ovoj grupi",
"锁数量": "Broj zaključanje", "锁数量": "Broj zaključanje",
@ -703,7 +703,7 @@
"传输中": "U provozu", "传输中": "U provozu",
"发送人": "Izdaja", "发送人": "Izdaja",
"发送时间": "Izdano vrijeme:", "发送时间": "Izdano vrijeme:",
"钥匙详情": "EKEY InfoName", "钥匙详情": "EKEY Info",
"姓名": "Ime", "姓名": "Ime",
"发送": "Pošalji", "发送": "Pošalji",
"请确认姓名全名和身份证号码是否正确": "Potvrdite da su puno ime i identifikacijski broj ispravni.", "请确认姓名全名和身份证号码是否正确": "Potvrdite da su puno ime i identifikacijski broj ispravni.",
@ -834,9 +834,9 @@
"微信": "WeChat", "微信": "WeChat",
"朋友圈": "Trenutaci", "朋友圈": "Trenutaci",
"QQ": "QQ", "QQ": "QQ",
"QQ空间": "QQZoneName", "QQ空间": "QQZone",
"微博": "Weibo", "微博": "Weibo",
"FaceBook": "FacebookName", "FaceBook": "Facebook",
"链接": "Vez", "链接": "Vez",
"今天": "Danas", "今天": "Danas",
"密码错误": "Nevažeća lozinka", "密码错误": "Nevažeća lozinka",
@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Nakon resetiranja, metakarpalne vene brave će biti izbrisane. Jeste li sigurni da želite resetiranje?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Nakon resetiranja, metakarpalne vene brave će biti izbrisane. Jeste li sigurni da želite resetiranje?",
@ -1103,8 +1104,8 @@
"Action name": "Ime akcije", "Action name": "Ime akcije",
"ScienerSmart": "ZnanstvenikSmart", "ScienerSmart": "ZnanstvenikSmart",
"支持的语言": "Podržani jezici", "支持的语言": "Podržani jezici",
"英语": "EngleskiName", "英语": "Engleski",
"Google Home操作流程的值": "1. Koristite Smart lock APP za dodavanje brava i prolaza\n\n2. Omogućite daljinsku funkciju otključavanja brave u APP (ova funkcija je zadano isključena). Bez ove opcije, brava ne podržava Google HomeName\n\n3. Instalirajte Google Home APP i kliknite \" \" gumb u gornjem lijevom kutu\n\n4. Na stranici podešavanja odaberite \"Radi s Googleom\"\n\n5. Tražite \"ScienerSmart\" i upotrijebite pametni APP račun i lozinku za ovlašćenje", "Google Home操作流程的值": "1. Koristite Smart lock APP za dodavanje brava i prolaza\n\n2. Omogućite daljinsku funkciju otključavanja brave u APP (ova funkcija je zadano isključena). Bez ove opcije, brava ne podržava Google Home\n\n3. Instalirajte Google Home APP i kliknite \" \" gumb u gornjem lijevom kutu\n\n4. Na stranici podešavanja odaberite \"Radi s Googleom\"\n\n5. Tražite \"ScienerSmart\" i upotrijebite pametni APP račun i lozinku za ovlašćenje",
"密码需至少包含数字/字母/字符中的2种组合": "Lozinka mora sadržavati najmanje 2 od sljedećih: brojeve, slova i posebne znakove", "密码需至少包含数字/字母/字符中的2种组合": "Lozinka mora sadržavati najmanje 2 od sljedećih: brojeve, slova i posebne znakove",
"已开锁": "Otključan", "已开锁": "Otključan",
"已闭锁": "Zaključano", "已闭锁": "Zaključano",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Postavke zaključavanja glasovnog paketa", "锁语音包设置": "Postavke zaključavanja glasovnog paketa",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Muški glas", "男声": "Muški glas",
"女声": "Ženski glas" "女声": "Ženski glas",
"您的图像和视频数据仅保留": "Vaši podaci o slici i videozapisu zadržavaju se samo",
"后图像和视频数据将会失效,开通": "Nakon toga, slikovni i video podaci bit će nevažeći i aktivirani",
"云存会员": "Članstvo u pohrani u oblaku",
"服务,图像视频信息随心存!": "Informacije o usluzi, slikama i videozapisima su vam u srcu!",
"图像": "slika",
"视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Trenutno zemlja ne podržava registraciju koda za provjeru mobilnog telefona, za registraciju koristite svoju adresu e-pošte",
"注:": "Napomena:",
"必需在开始时间24小时内使用一次否则将失效": "Mora se upotrijebiti jednom unutar 24 sata od vremena početka, inače će isteći",
"这是单次密码,只能使用一次": "Ovo je jednokratna lozinka i može se koristiti samo jednom",
"您好": "Bok",
"您的开门密码是": "Vaša šifra za otvaranje vrata je",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Da biste otključali, prvo aktivirajte tipkovnicu brave, zatim unesite lozinku i završite s #. Tipka # nalazi se u donjem desnom kutu tipkovnice i može imati drugu ikonu"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "A reset után a zár metakarpális erei törlődnek. Biztos vagy benne, hogy vissza akarsz állítani?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "A reset után a zár metakarpális erei törlődnek. Biztos vagy benne, hogy vissza akarsz állítani?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Hangcsomag zárolási beállításai", "锁语音包设置": "Hangcsomag zárolási beállításai",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Férfi hang", "男声": "Férfi hang",
"女声": "női hang" "女声": "női hang",
"您的图像和视频数据仅保留": "A kép- és videóadatokat csak a rendszer őrzi meg",
"后图像和视频数据将会失效,开通": "Ezt követően a kép- és videóadatok érvénytelenek lesznek és aktiválódnak",
"云存会员": "Felhőalapú tárolási tagság",
"服务,图像视频信息随心存!": "A szolgáltatás, a képi és videós információk a szívedben vannak!",
"图像": "kép",
"视频": "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",
"注:": "Megjegyzés:",
"必需在开始时间24小时内使用一次否则将失效": "A kezdési időponttól számított 24 órán belül egyszer kell használni, különben lejár",
"这是单次密码,只能使用一次": "Ez egy egyszeri jelszó, amelyet csak egyszer lehet használni",
"您好": "Szia",
"您的开门密码是": "Az ajtónyitó kódod",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "A feloldáshoz először aktiválja a zár billentyűzetét, majd írja be a jelszót, és fejezze be a # gombbal. A # gomb a billentyűzet jobb alsó sarkában található, és más ikonnal is rendelkezhet"
} }

View File

@ -1067,7 +1067,7 @@
"波兰语": "Լեհերեն", "波兰语": "Լեհերեն",
"斯洛伐克语": "Սլովենչինա", "斯洛伐克语": "Սլովենչինա",
"捷克语": "Չեշտինա", "捷克语": "Չեշտինա",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1080,10 +1080,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Սուոմի", "芬兰语": "Սուոմի",
"丹麦语": "Դանսկ", "丹麦语": "Դանսկ",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Վերագործարկումից հետո կողպեքի մետակարպալ երակները կջնջվեն: Իրո՞ք ցանկանում եք վերակայել:", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Վերագործարկումից հետո կողպեքի մետակարպալ երակները կջնջվեն: Իրո՞ք ցանկանում եք վերակայել:",
@ -1166,5 +1167,18 @@
"锁语音包设置": "Փակել ձայնային փաթեթի պարամետրերը", "锁语音包设置": "Փակել ձայնային փաթեթի պարամետրերը",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "տղամարդկանց ձայն", "男声": "տղամարդկանց ձայն",
"女声": "կանանց ձայն" "女声": "կանանց ձայն",
"您的图像和视频数据仅保留": "Ձեր պատկերի եւ վիդեո տվյալները պահպանվում են միայն",
"后图像和视频数据将会失效,开通": "Դրանից հետո պատկերի եւ վիդեո տվյալները կլինեն անվավեր եւ կակտիվացվեն",
"云存会员": "Cloud Storage Membership",
"服务,图像视频信息随心存!": "Ծառայությունը, պատկերը եւ վիդեո տեղեկատվությունը ձեր սրտում են:",
"图像": "Պատկերասրահ",
"视频": "Տեսանյութ",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Ներկայումս երկիրը չի աջակցում բջջային հեռախոսի ստուգման կոդի գրանցմանը, խնդրում ենք գրանցվելու համար օգտագործել ձեր էլ. փոստի հասցեն",
"注:": "Նշում՝",
"必需在开始时间24小时内使用一次否则将失效": "Անհրաժեշտ է օգտագործել մեկ անգամ սկսելու ժամանակից 24 ժամվա ընթացքում, հակառակ դեպքում այն կվազվի",
"这是单次密码,只能使用一次": "Սա մեկ անգամյա գաղտնաբառ է եւ կարող է օգտագործվել միայն մեկ անգամ",
"您好": "Ողջույն",
"您的开门密码是": "Ձեր դռան բանալին հետեւյալն է",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Ապակողպելու համար նախ ակտիվացրեք կողպեքի ստեղնաշարը, ապա մուտքագրեք գաղտնաբառը եւ ավարտեք #-ով: #-ի ստեղնը գտնվում է ստեղնաշարի ներքեւի աջ անկյունում եւ կարող է ունենալ այլ պատկերակ"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Setelah mengulang, pembuluh darah metakarpal dari kunci akan dihapus. Yakin ingin mengatur ulang?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Setelah mengulang, pembuluh darah metakarpal dari kunci akan dihapus. Yakin ingin mengatur ulang?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Mengunci paket suara", "锁语音包设置": "Mengunci paket suara",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "6 tahun sebelumnya", "男声": "6 tahun sebelumnya",
"女声": "Suara wanita" "女声": "Suara wanita",
"您的图像和视频数据仅保留": "Data gambar dan video Anda hanya disimpan",
"后图像和视频数据将会失效,开通": "Setelah itu, data gambar dan video akan tidak valid dan diaktifkan",
"云存会员": "Keanggotaan Cloud Storage",
"服务,图像视频信息随心存!": "Informasi layanan, gambar, dan video adalah inti Anda!",
"图像": "citra",
"视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Saat ini, negara tersebut tidak mendukung pendaftaran kode verifikasi ponsel, silakan gunakan alamat email Anda untuk mendaftar",
"注:": "Catatan:",
"必需在开始时间24小时内使用一次否则将失效": "Harus digunakan sekali dalam waktu 24 jam setelah waktu mulai, jika tidak akan kedaluwarsa",
"这是单次密码,只能使用一次": "Ini adalah kata sandi sekali pakai dan hanya bisa digunakan sekali",
"您好": "Halo",
"您的开门密码是": "Kode akses pintu Anda adalah",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Untuk membuka kunci, aktifkan keyboard kunci terlebih dahulu, lalu masukkan kata sandi dan akhiri dengan #. Tombol # berada di sudut kanan bawah keyboard dan mungkin memiliki ikon berbeda"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Dopo il reset, le vene metacarpali della serratura verranno cancellate. Sei sicuro di voler reimpostare?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Dopo il reset, le vene metacarpali della serratura verranno cancellate. Sei sicuro di voler reimpostare?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Impostazioni pacchetto vocale blocco", "锁语音包设置": "Impostazioni pacchetto vocale blocco",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "voce maschile", "男声": "voce maschile",
"女声": "voce femminile" "女声": "voce femminile",
"您的图像和视频数据仅保留": "I dati delle immagini e dei video vengono conservati solo",
"后图像和视频数据将会失效,开通": "Successivamente, i dati dell'immagine e del video non saranno più validi e attivati",
"云存会员": "Iscrizione al cloud storage",
"服务,图像视频信息随心存!": "Le informazioni sul servizio, le immagini e i video sono al tuo centro!",
"图像": "immagine",
"视频": "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",
"注:": "Nota:",
"必需在开始时间24小时内使用一次否则将失效": "Deve essere utilizzato una volta entro 24 ore dall'orario di inizio, altrimenti scadrà",
"这是单次密码,只能使用一次": "Questa è una password monouso e può essere utilizzata solo una volta",
"您好": "Ciao",
"您的开门密码是": "Il tuo codice di accesso alla porta è",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Per sbloccare, attiva prima la tastiera del lucchetto, quindi inserisci la password e termina con #. Il tasto # si trova nell'angolo in basso a destra della tastiera e potrebbe avere un'icona diversa"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "リセット後、ロックの中手骨静脈が削除されます。リセットしてもよろしいですか。", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "リセット後、ロックの中手骨静脈が削除されます。リセットしてもよろしいですか。",
@ -1160,5 +1161,18 @@
"锁语音包设置": "ロック音声パケット設定", "锁语音包设置": "ロック音声パケット設定",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "男声", "男声": "男声",
"女声": "女声" "女声": "女声",
"您的图像和视频数据仅保留": "画像と動画のデータのみが保持されます",
"后图像和视频数据将会失效,开通": "その後、画像とビデオのデータは無効になり、アクティブになります",
"云存会员": "クラウドストレージメンバーシップ",
"服务,图像视频信息随心存!": "サービス、画像、ビデオ情報があなたの中心にあります!",
"图像": "画像",
"视频": "ビデオ",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "現在、この国は携帯電話の認証コード登録をサポートしていませんので、メールアドレスを使用して登録してください",
"注:": "注:",
"必需在开始时间24小时内使用一次否则将失效": "開始時刻から24時間以内に1回使用する必要があり、そうでなければ無効になります",
"这是单次密码,只能使用一次": "これはワンタイムパスワードで、一度だけ使用できます",
"您好": "こんにちは",
"您的开门密码是": "あなたのドアアクセスコードは",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "ロックを解除するには、まずロックキーボードをアクティブにし、次にパスワードを入力し、#で終了します。#キーはキーボードの右下隅にあり、別のアイコンの場合があります"
} }

View File

@ -187,7 +187,7 @@
"删除账号": "ანგარიშის წაშლა", "删除账号": "ანგარიშის წაშლა",
"个人信息": "ანგარიშის ინფორმაცია", "个人信息": "ანგარიშის ინფორმაცია",
"头像": "ავატარი", "头像": "ავატარი",
"昵称": "ნიკName", "昵称": "ნიკ",
"请输入昵称": "გთხოვთ შეიყვანოთ თქვენი მეტსახელი", "请输入昵称": "გთხოვთ შეიყვანოთ თქვენი მეტსახელი",
"修改昵称": "გადარქმევა", "修改昵称": "გადარქმევა",
"修改账号": "ანგარიშის რედაქტირება", "修改账号": "ანგარიშის რედაქტირება",
@ -1067,7 +1067,7 @@
"波兰语": "პოლსკი", "波兰语": "პოლსკი",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1080,10 +1080,11 @@
"印度尼西亚语": "ბაჰასა ინდონეზია", "印度尼西亚语": "ბაჰასა ინდონეზია",
"芬兰语": "სუომი", "芬兰语": "სუომი",
"丹麦语": "დანსკი", "丹麦语": "დანსკი",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "გადატვირთვის შემდეგ, საკეტის მეტაკარპალური ვენები წაიშლება. დარწმუნებული ხართ, რომ გსურთ გადატვირთვა?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "გადატვირთვის შემდეგ, საკეტის მეტაკარპალური ვენები წაიშლება. დარწმუნებული ხართ, რომ გსურთ გადატვირთვა?",
@ -1166,5 +1167,18 @@
"锁语音包设置": "ხმის პაკეტის პარამეტრები", "锁语音包设置": "ხმის პაკეტის პარამეტრები",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "მამაკაცის ხმა", "男声": "მამაკაცის ხმა",
"女声": "ქალის ხმა" "女声": "ქალის ხმა",
"您的图像和视频数据仅保留": "თქვენი სურათი და ვიდეო მონაცემები ინახება მხოლოდ",
"后图像和视频数据将会失效,开通": "ამის შემდეგ, სურათისა და ვიდეო მონაცემები არასწორი და გააქტიურებული იქნება",
"云存会员": "Cloud Storage წევრობა",
"服务,图像视频信息随心存!": "მომსახურება, სურათი და ვიდეო ინფორმაცია თქვენს გულშია!",
"图像": "სურათი",
"视频": "ვიდეო",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "ამჟამად, ქვეყანა არ უჭერს მხარს მობილური ტელეფონის დამადასტურებელი კოდის რეგისტრაციას, გთხოვთ გამოიყენოთ თქვენი ელექტრონული ფოსტის მისამართი რეგისტრაციისთვის",
"注:": "შენიშვნა:",
"必需在开始时间24小时内使用一次否则将失效": "უნდა გამოიყენოთ ერთხელ დაწყების დროიდან 24 საათის განმავლობაში, წინააღმდეგ შემთხვევაში ვადა გაუვა",
"这是单次密码,只能使用一次": "ეს არის ერთჯერადი პაროლი და შეიძლება გამოყენებულ იქნას მხოლოდ ერთხელ",
"您好": "გამარჯობა",
"您的开门密码是": "თქვენი კარის გახსნის კოდი არის",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "განბლოკვისთვის პირველ რიგში გაააქტიურეთ დამკეტის კლავიატურა, შემდეგ შეიყვანეთ პაროლი და დაასრულეთ #. # ღილაკი მდებარეობს კლავიატურის ქვედა მარჯვენა კუთხეში და შეიძლება ჰქონდეს სხვა ხატულა"
} }

View File

@ -1085,6 +1085,7 @@
"乌尔都语": "乌尔都语", "乌尔都语": "乌尔都语",
"亚美尼亚语": "亚美尼亚语", "亚美尼亚语": "亚美尼亚语",
"格鲁吉亚语": "格鲁吉亚语", "格鲁吉亚语": "格鲁吉亚语",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?",
@ -1171,5 +1172,18 @@
"语音包设置": "语音包设置", "语音包设置": "语音包设置",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "男声", "男声": "男声",
"女声": "女声" "女声": "女声",
"您的图像和视频数据仅保留": "您的图像和视频数据仅保留",
"后图像和视频数据将会失效,开通": "后图像和视频数据将会失效,开通",
"云存会员": "云存会员",
"服务,图像视频信息随心存!": "服务,图像视频信息随心存!",
"图像": "图像",
"视频": "视频",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "当前国家不支持手机验证码注册,请使用邮箱进行注册",
"注:":"注:",
"必需在开始时间24小时内使用一次否则将失效": "必需在开始时间24小时内使用一次否则将失效",
"这是单次密码,只能使用一次": "这是单次密码,只能使用一次",
"您好": "您好",
"您的开门密码是": "您的开门密码是",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标"
} }

View File

@ -31,8 +31,8 @@
"简写周三": "WW", "简写周三": "WW",
"简写周四": "T", "简写周四": "T",
"简写周五": "F", "简写周五": "F",
"简写周六": "SName", "简写周六": "S",
"简写周日": "SName", "简写周日": "S",
"周一": "MonComment", "周一": "MonComment",
"周二": "Туе", "周二": "Туе",
"周三": "Жеті", "周三": "Жеті",
@ -116,7 +116,7 @@
"微信二维码": "QR кодін ашу", "微信二维码": "QR кодін ашу",
"拥有电子钥匙的人,通过微信扫一扫这个二维码,即可开门。每把锁的二维码都不相同,你可以将其打印出来贴在对应的锁旁边": "Электронлық кілттер бар адамдар осы QR коды \"WeChat\" дегенді сіздеп, шұқсаты ашылады. Әрбір блоктың QR коды басқа. Оны баспаға сәйкесті блоктың жағысын орналаса аласыз.", "拥有电子钥匙的人,通过微信扫一扫这个二维码,即可开门。每把锁的二维码都不相同,你可以将其打印出来贴在对应的锁旁边": "Электронлық кілттер бар адамдар осы QR коды \"WeChat\" дегенді сіздеп, шұқсаты ашылады. Әрбір блоктың QR коды басқа. Оны баспаға сәйкесті блоктың жағысын орналаса аласыз.",
"锁编号": "Боқталсын", "锁编号": "Боқталсын",
"电量": "БатареяName", "电量": "Батарея",
"锁分组": "Топты бұғаттау", "锁分组": "Топты бұғаттау",
"选择分组": "Топты таңдау", "选择分组": "Топты таңдау",
"创建新分组": "Топты құру", "创建新分组": "Топты құру",
@ -279,7 +279,7 @@
"发卡工具": "КодтамасыComment", "发卡工具": "КодтамасыComment",
"购买高级功能须知": "Хабарламасы", "购买高级功能须知": "Хабарламасы",
"购买高级功能提示": "Қосымша мүмкіндіктер құрылғыда, егер керек болса, бұғаттардың санын ашу үшін көмектесіңіз. Қосымша мүмкіндіктері ғана өзіңізді бұғаттарыңыз. Егер әкімгілікті әкімші болса, қызметті ашу үшін блоктау жоғарғы әкімшісін қатынасыз", "购买高级功能提示": "Қосымша мүмкіндіктер құрылғыда, егер керек болса, бұғаттардың санын ашу үшін көмектесіңіз. Қосымша мүмкіндіктері ғана өзіңізді бұғаттарыңыз. Егер әкімгілікті әкімші болса, қызметті ашу үшін блоктау жоғарғы әкімшісін қатынасыз",
"免费体验": "Бос сынауName", "免费体验": "Бос сынау",
"立即开通": "Қазір ашу", "立即开通": "Қазір ашу",
"购买短信": "SMS сақтау", "购买短信": "SMS сақтау",
"购买邮件": "Эл. поштаны сақтау", "购买邮件": "Эл. поштаны сақтау",
@ -301,8 +301,8 @@
"对于选中的这些锁当用户用APP开锁时他的手机需要是连网的否则无法开锁": "Таңдалған блоктарды APP-мен ашу үшін пайдаланушының телефонын онлайн болу керек.", "对于选中的这些锁当用户用APP开锁时他的手机需要是连网的否则无法开锁": "Таңдалған блоктарды APP-мен ашу үшін пайдаланушының телефонын онлайн болу керек.",
"配置WiFi": "WiFi баптау", "配置WiFi": "WiFi баптау",
"请输入WiFi名字": "Wifi атын келтіріңіз", "请输入WiFi名字": "Wifi атын келтіріңіз",
"WiFi配网": "WiFi тарату желіName", "WiFi配网": "WiFi тарату желі",
"胁迫卡": "Стрес картасыName", "胁迫卡": "Стрес картасы",
"员工是否有密码": "Бастапқы кодтары", "员工是否有密码": "Бастапқы кодтары",
"员工是否有卡": "Карта бар ғой", "员工是否有卡": "Карта бар ғой",
"员工是否有指纹": "Бақылау тізімін орнату", "员工是否有指纹": "Бақылау тізімін орнату",
@ -327,7 +327,7 @@
"防误开已关闭,关门后仍可使用面容开锁": "Ашылмағанды жабылсын", "防误开已关闭,关门后仍可使用面容开锁": "Ашылмағанды жабылсын",
"添加和使用面容开锁时": "Жүктеу кезінде тағы қосу мен қолданылсын", "添加和使用面容开锁时": "Жүктеу кезінде тағы қосу мен қолданылсын",
"添加和使用面容开锁时提示": "\n1, бір адам қашықтығы операцияның алдында ұстап көріңіз.\n2, қазірішін бұғаттардың алдында 0,5 ~ 0,8 мсят, әзірін бұғаттарды келтіріңіз.\n3. Өшіріңізді бейімде болсап, өзіңізді таңдаңыз.\n4. Көйін анықтауы дұрыс емес болса, цифриқ пернетінің перне енгізінді қолмен қайта қосу үшін перне іске қоса аласыз.", "添加和使用面容开锁时提示": "\n1, бір адам қашықтығы операцияның алдында ұстап көріңіз.\n2, қазірішін бұғаттардың алдында 0,5 ~ 0,8 мсят, әзірін бұғаттарды келтіріңіз.\n3. Өшіріңізді бейімде болсап, өзіңізді таңдаңыз.\n4. Көйін анықтауы дұрыс емес болса, цифриқ пернетінің перне енгізінді қолмен қайта қосу үшін перне іске қоса аласыз.",
"秒": "SName", "秒": "S",
"请根据门锁实际情况,请谨慎选择电机功率:": "Мотодор қуаттандық қадамдастыру үшін таңдаңыз:", "请根据门锁实际情况,请谨慎选择电机功率:": "Мотодор қуаттандық қадамдастыру үшін таңдаңыз:",
"小功率:": "Миноват:", "小功率:": "Миноват:",
"耗电少": "Қуаттандықтан кейі", "耗电少": "Қуаттандықтан кейі",
@ -351,7 +351,7 @@
"员工信息": "Жергілікті мәліметі", "员工信息": "Жергілікті мәліметі",
"员工": "Таңдау", "员工": "Таңдау",
"打卡方式无效": "Қол жеткізбеді", "打卡方式无效": "Қол жеткізбеді",
"中国": "КітаName", "中国": "Кіта",
"选择钥匙": "Eky таңдау", "选择钥匙": "Eky таңдау",
"编辑": "Өңдеу", "编辑": "Өңдеу",
"无": "Жоқ", "无": "Жоқ",
@ -531,7 +531,7 @@
"公司名称不能小于6个字符": "Компанияның атауы 6 таңба болмайды", "公司名称不能小于6个字符": "Компанияның атауы 6 таңба болмайды",
"WIFI列表": "WIFI тізімі", "WIFI列表": "WIFI тізімі",
"刷新": "Жаңарту", "刷新": "Жаңарту",
"手动配网": "Қолмен үлестірім желіName", "手动配网": "Қолмен үлестірім желі",
"远距离": "Үл қашықтығы", "远距离": "Үл қашықтығы",
"中距离": "Орташа қашықтығы", "中距离": "Орташа қашықтығы",
"近距离": "Қысқа қашықтығы", "近距离": "Қысқа қашықтығы",
@ -548,7 +548,7 @@
"管理员密码": "Әдетті өшіру", "管理员密码": "Әдетті өшіру",
"如需修改,请输入新的管理员密码(6位),点击确定即可修改": "Егер өзгерту керек болса, жаңа әкімшіші", "如需修改,请输入新的管理员密码(6位),点击确定即可修改": "Егер өзгерту керек болса, жаңа әкімшіші",
"修改": "Өзгерту", "修改": "Өзгерту",
"网络摄像头": "КамераName", "网络摄像头": "Камера",
"重命名": "Атын ауыстыру", "重命名": "Атын ауыстыру",
"分组下的锁将被移到未分组里": "Топтың төменгі блокталар тобысмен жылжытады", "分组下的锁将被移到未分组里": "Топтың төменгі блокталар тобысмен жылжытады",
"编辑成功": "Сәтті өңдеу", "编辑成功": "Сәтті өңдеу",
@ -574,7 +574,7 @@
"请手动在系统设置中开启": "Жүйелік параметрлерде қолмен іске қосыңыз", "请手动在系统设置中开启": "Жүйелік параметрлерде қолмен іске қосыңыз",
"权限以继续使用应用": "Қолданбаны жалғастыру рұқсат ету.", "权限以继续使用应用": "Қолданбаны жалғастыру рұқсат ету.",
"去设置": "Оны орнату", "去设置": "Оны орнату",
"当前网络": "Назардағы желіName", "当前网络": "Назардағы желі",
"位置信息": "Орналасуы ақпарат", "位置信息": "Орналасуы ақпарат",
"请输入wifi名称": "Wifi атауын келтіріңіз", "请输入wifi名称": "Wifi атауын келтіріңіз",
"虹膜": "Iris", "虹膜": "Iris",
@ -601,7 +601,7 @@
"提醒方式": "Ескерту жолы", "提醒方式": "Ескерту жолы",
"开门方式": "Қашықты ашылсын", "开门方式": "Қашықты ашылсын",
"请选择": "Таңдау", "请选择": "Таңдау",
"家人": "Үлгі мүшесіName", "家人": "Үлгі мүшесі",
"保存": "Сақтау", "保存": "Сақтау",
"APP推送": "APP басы", "APP推送": "APP басы",
"管理员": "Adminu", "管理员": "Adminu",
@ -639,13 +639,13 @@
"全部视频": "Барлық видеолар", "全部视频": "Барлық видеолар",
"已为本设备免费提供3大滚动视频储存服务": "Құрылғының шкі видео сақтау қызметі орындалды", "已为本设备免费提供3大滚动视频储存服务": "Құрылғының шкі видео сақтау қызметі орындалды",
"视频播放": "Видео ойнау", "视频播放": "Видео ойнау",
"全选": "БарлықтыName", "全选": "Барлықты",
"请选择要删除的视频": "Өшіру келетін видеоін таңдаңыз", "请选择要删除的视频": "Өшіру келетін видеоін таңдаңыз",
"请选择要下载的视频": "Жүктеу үшін осы видеоты таңдаңыз", "请选择要下载的视频": "Жүктеу үшін осы видеоты таңдаңыз",
"欢迎使用": "Қолданға қоша", "欢迎使用": "Қолданға қоша",
"用户协议和隐私政策概要": "Пайдаланушы келесі мен бақылау ережесінің ақпарат", "用户协议和隐私政策概要": "Пайдаланушы келесі мен бақылау ережесінің ақпарат",
"协议概要": "Протоколды тобысы", "协议概要": "Протоколды тобысы",
"感谢您使用本应用。我们非常重视您的个人信息和隐私保护,在使用本产品之前,请认真阅读": "Бұл қолданба қолданбасы үшін рахмет. Біздің жеке мәліметіңізді әдеттіңізге және жеке ақпараттық қорғастырыңызды. Осы продуктты қолдану алдында, оны ескертін оқыңызName", "感谢您使用本应用。我们非常重视您的个人信息和隐私保护,在使用本产品之前,请认真阅读": "Бұл қолданба қолданбасы үшін рахмет. Біздің жеке мәліметіңізді әдеттіңізге және жеке ақпараттық қорғастырыңызды. Осы продуктты қолдану алдында, оны ескертін оқыңыз",
"《用户协议》": "Пайдаланушы ақпараты", "《用户协议》": "Пайдаланушы ақпараты",
"和": "Сот", "和": "Сот",
"《隐私政策》": "חPrivacy ережес", "《隐私政策》": "חPrivacy ережес",
@ -805,7 +805,7 @@
"蓝牙未打开,请到设置里面打开蓝牙": "Bluetooth енгізілмеген, Bluetooth баптауларын көрсетіңіз", "蓝牙未打开,请到设置里面打开蓝牙": "Bluetooth енгізілмеген, Bluetooth баптауларын көрсетіңіз",
"删除用户时,会将用户拥有的钥匙一起删除。": "Пайдаланушының келтірілген, егер Пайдаланушыға сәйкес келеді.", "删除用户时,会将用户拥有的钥匙一起删除。": "Пайдаланушының келтірілген, егер Пайдаланушыға сәйкес келеді.",
"配置网络": "Желі & баптау", "配置网络": "Желі & баптау",
"你好": "ЖарыName", "你好": "Жары",
"成功": "Сәттін", "成功": "Сәттін",
"类型选择": "Таңдау", "类型选择": "Таңдау",
"请选择要使用哪种类型": "Қолданатын түрін таңдаңыз", "请选择要使用哪种类型": "Қолданатын түрін таңдаңыз",
@ -834,8 +834,8 @@
"微信": "WeChat", "微信": "WeChat",
"朋友圈": "Текшер", "朋友圈": "Текшер",
"QQ": "QQ", "QQ": "QQ",
"QQ空间": "QQZoneName", "QQ空间": "QQZone",
"微博": "WeiboName", "微博": "Weibo",
"FaceBook": "FaceBook", "FaceBook": "FaceBook",
"链接": "Сілтеме", "链接": "Сілтеме",
"今天": "Бүгіз", "今天": "Бүгіз",
@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Қайта ысырып тастағаннан соң бұғаттағы метакарпалар өшіріледі. Шынымен ысырып тастауды қалайсыз ба?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Қайта ысырып тастағаннан соң бұғаттағы метакарпалар өшіріледі. Шынымен ысырып тастауды қалайсыз ба?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Дауыстық бума параметрлерін құлыптау", "锁语音包设置": "Дауыстық бума параметрлерін құлыптау",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "ер дауысы", "男声": "ер дауысы",
"女声": "Әйел дауысы" "女声": "Әйел дауысы",
"您的图像和视频数据仅保留": "Сіздің кескініңіз бен бейне деректеріңіз тек сақталады",
"后图像和视频数据将会失效,开通": "Осыдан кейін кескін мен бейне деректер жарамсыз болып, белсендіріледі",
"云存会员": "Бұлтты сақтауға мүшелік",
"服务,图像视频信息随心存!": "Қызмет, бейне және бейне ақпарат сіздің жүрегіңізде жатыр!",
"图像": "кескіні",
"视频": "Бейне",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Қазіргі уақытта елде ұялы телефонды растау кодын тіркеуді қолдамайды, тіркелу үшін электрондық пошта мекенжайыңызды пайдаланыңыз",
"注:": "Ескерту:",
"必需在开始时间24小时内使用一次否则将失效": "Бастау уақытынан бастап 24 сағат ішінде бір рет қолдану керек, әйтпесе мерзімі аяқталады",
"这是单次密码,只能使用一次": "Бұл бір реттік құпиясөз, оны тек бір рет қолдануға болады",
"您好": "Сәлеметсіз бе",
"您的开门密码是": "Есікті ашу кодыңыз",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Құлыпты ашу үшін алдымен құлып пернетақтасын іске қосыңыз, содан кейін құпиясөзді енгізіп, # арқылы аяқтаңыз. # пернесі пернетақтаның төменгі оң жақ бұрышында орналасқан және басқа белгі болуы мүмкін"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 중수골 정맥이 삭제됩니다. 당신은 당신이 재설정 하시겠습니까?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 중수골 정맥이 삭제됩니다. 당신은 당신이 재설정 하시겠습니까?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "음성팩 설정 잠금", "锁语音包设置": "음성팩 설정 잠금",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "남성", "男声": "남성",
"女声": "여성 목소리" "女声": "여성 목소리",
"您的图像和视频数据仅保留": "이미지 및 동영상 데이터만 보존됩니다.",
"后图像和视频数据将会失效,开通": "그 후 이미지 및 비디오 데이터는 유효하지 않고 활성화됩니다",
"云存会员": "클라우드 스토리지 멤버십",
"服务,图像视频信息随心存!": "서비스, 이미지 및 비디오 정보가 당신의 중심에 있습니다!",
"图像": "이미지",
"视频": "비디오",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "현재 해당 국가는 휴대폰 인증코드 등록을 지원하지 않으니 이메일 주소를 사용하여 등록하세요.",
"注:": "참고:",
"必需在开始时间24小时内使用一次否则将失效": "시작 시간으로부터 24시간 이내에 한 번 사용해야 하며, 그렇지 않으면 만료됩니다.",
"这是单次密码,只能使用一次": "이것은 일회용 비밀번호로 한 번만 사용할 수 있습니다.",
"您好": "안녕하세요",
"您的开门密码是": "귀하의 문 열기 코드는",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "잠금을 해제하려면 먼저 잠금 키보드를 활성화한 다음 비밀번호를 입력하고 #로 끝냅니다. # 키는 키보드의 오른쪽 하단 모서리에 있으며 다른 아이콘일 수 있습니다."
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Po reset užrakto metakarpinės venos bus ištrintos. Ar tikrai norite atstatyti?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Po reset užrakto metakarpinės venos bus ištrintos. Ar tikrai norite atstatyti?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Balso paketo nustatymų užrakinimas", "锁语音包设置": "Balso paketo nustatymų užrakinimas",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "vyriškas balsas", "男声": "vyriškas balsas",
"女声": "Moteriškas balsas" "女声": "Moteriškas balsas",
"您的图像和视频数据仅保留": "Vaizdo ir vaizdo įrašų duomenys saugomi tik",
"后图像和视频数据将会失效,开通": "Po to vaizdo ir vaizdo duomenys bus negaliojantys ir suaktyvinti",
"云存会员": "Debesies saugyklos narystė",
"服务,图像视频信息随心存!": "Aptarnavimas, vaizdas ir video informacija yra jūsų širdis!",
"图像": "vaizdas",
"视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Šiuo metu šalis nepalaiko mobiliojo telefono patvirtinimo kodo registracijos, registruodamiesi naudokite savo el. pašto adresą",
"注:": "Pastaba:",
"必需在开始时间24小时内使用一次否则将失效": "Turi būti naudojamas vieną kartą per 24 valandas nuo pradžios laiko, kitaip jis baigs galioti",
"这是单次密码,只能使用一次": "Tai vienkartinis slaptažodis, kurį galima naudoti tik vieną kartą",
"您好": "Sveiki",
"您的开门密码是": "Jūsų durų atidarymo kodas yra",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Norėdami atrakinti, pirmiausia suaktyvinkite užrakto klaviatūrą, tada įveskite slaptažodį ir baikite #. Klavišas # yra klaviatūros apatiniame dešiniajame kampe ir gali būti kita piktograma"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Selepas menetapkan semula, urat metacarpal kunci akan dipadamkan. Adakah anda pasti anda mahu menetapkan semula?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Selepas menetapkan semula, urat metacarpal kunci akan dipadamkan. Adakah anda pasti anda mahu menetapkan semula?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Balso paketo nustatymų užrakinimas", "锁语音包设置": "Balso paketo nustatymų užrakinimas",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "vyriškas balsas", "男声": "vyriškas balsas",
"女声": "Moteriškas balsas" "女声": "Moteriškas balsas",
"您的图像和视频数据仅保留": "Data imej dan video anda hanya dikekalkan",
"后图像和视频数据将会失效,开通": "Selepas itu, data imej dan video akan menjadi tidak sah dan diaktifkan",
"云存会员": "Keahlian Storan Awan",
"服务,图像视频信息随心存!": "Maklumat perkhidmatan, imej dan video adalah di hati anda!",
"图像": "Imej",
"视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Pada masa ini, negara ini tidak menyokong pendaftaran kod pengesahan telefon bimbit, sila gunakan alamat e-mel anda untuk mendaftar",
"注:": "Nota:",
"必需在开始时间24小时内使用一次否则将失效": "Mesti digunakan sekali dalam masa 24 jam dari masa mula, jika tidak ia akan luput",
"这是单次密码,只能使用一次": "Ini ialah kata laluan sekali guna dan hanya boleh digunakan sekali",
"您好": "Helo",
"您的开门密码是": "Kod akses pintu anda ialah",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Untuk membuka kunci, aktifkan papan kekunci kunci terlebih dahulu, kemudian masukkan kata laluan dan tamatkan dengan #. Kekunci # berada di sudut kanan bawah papan kekunci dan mungkin mempunyai ikon lain"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Na reset worden de middenhandsbeenaders van het slot verwijderd. Weet je zeker dat je wilt resetten?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Na reset worden de middenhandsbeenaders van het slot verwijderd. Weet je zeker dat je wilt resetten?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Instellingen voor spraakpakket vergrendelen", "锁语音包设置": "Instellingen voor spraakpakket vergrendelen",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "mannelijke stem", "男声": "mannelijke stem",
"女声": "Vrouwelijke stem" "女声": "Vrouwelijke stem",
"您的图像和视频数据仅保留": "Uw beeld- en videogegevens worden alleen bewaard",
"后图像和视频数据将会失效,开通": "Daarna zijn de afbeeldings- en videogegevens ongeldig en geactiveerd",
"云存会员": "Lidmaatschap voor cloudopslag",
"服务,图像视频信息随心存!": "Service-, beeld- en video-informatie staan bij u centraal!",
"图像": "beeld",
"视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Momenteel ondersteunt het land de registratie van de verificatiecode voor mobiele telefoons niet, gebruik uw e-mailadres om u te registreren",
"注:": "Opmerking:",
"必需在开始时间24小时内使用一次否则将失效": "Moet één keer worden gebruikt binnen 24 uur na de starttijd, anders verloopt het",
"这是单次密码,只能使用一次": "Dit is een eenmalig wachtwoord en kan maar één keer worden gebruikt",
"您好": "Hallo",
"您的开门密码是": "Uw deurtoegangscode is",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Om te ontgrendelen, activeert u eerst het toetsenbord van het slot, voert u vervolgens het wachtwoord in en eindigt u met #. De #-toets bevindt zich in de rechterbenedenhoek van het toetsenbord en kan een ander pictogram hebben"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Po zresetowaniu żyły śródręcza zamka zostaną usunięte. Czy na pewno chcesz zresetować?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Po zresetowaniu żyły śródręcza zamka zostaną usunięte. Czy na pewno chcesz zresetować?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Ustawienia blokowania pakietu głosowego", "锁语音包设置": "Ustawienia blokowania pakietu głosowego",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Mężczyzna", "男声": "Mężczyzna",
"女声": "Głos kobiecy" "女声": "Głos kobiecy",
"您的图像和视频数据仅保留": "Dane obrazu i filmu są przechowywane tylko",
"后图像和视频数据将会失效,开通": "Po tym czasie dane obrazu i wideo zostaną nieważne i aktywowane",
"云存会员": "Członkostwo w usłudze Cloud Storage",
"服务,图像视频信息随心存!": "Informacje o serwisie, obrazie i wideo są w Twoim sercu!",
"图像": "obraz",
"视频": "Wideo",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Obecnie kraj nie obsługuje rejestracji kodem weryfikacyjnym telefonu komórkowego, użyj swojego adresu e-mail, aby się zarejestrować",
"注:": "Uwaga:",
"必需在开始时间24小时内使用一次否则将失效": "Należy użyć raz w ciągu 24 godzin od czasu rozpoczęcia, w przeciwnym razie wygaśnie",
"这是单次密码,只能使用一次": "To hasło jednorazowe, którego można użyć tylko raz",
"您好": "Cześć",
"您的开门密码是": "Twój kod dostępu do drzwi to",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Aby odblokować, najpierw aktywuj klawiaturę zamka, następnie wprowadź hasło i zakończ #. Klawisz # znajduje się w prawym dolnym rogu klawiatury i może mieć inną ikonę"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Após a reinicialização, as veias do metacarpo do bloqueio serão excluídas. Tens a certeza que queres reiniciar?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Após a reinicialização, as veias do metacarpo do bloqueio serão excluídas. Tens a certeza que queres reiniciar?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Configurações do pacote de voz bloqueada", "锁语音包设置": "Configurações do pacote de voz bloqueada",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Voz masculina", "男声": "Voz masculina",
"女声": "voz feminina" "女声": "voz feminina",
"您的图像和视频数据仅保留": "Seus dados de imagem e vídeo são retidos apenas",
"后图像和视频数据将会失效,开通": "Depois disso, os dados de imagem e vídeo serão inválidos e ativados",
"云存会员": "Associação de armazenamento em nuvem",
"服务,图像视频信息随心存!": "Informações de serviço, imagem e vídeo estão no seu coração!",
"图像": "imagem",
"视频": "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",
"注:": "Nota:",
"必需在开始时间24小时内使用一次否则将失效": "Deve ser usado uma vez dentro de 24 horas após o horário de início, caso contrário expirará",
"这是单次密码,只能使用一次": "Esta é uma senha de uso único e só pode ser usada uma vez",
"您好": "Olá",
"您的开门密码是": "Seu código de acesso à porta é",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Para desbloquear, primeiro ative o teclado do cadeado e depois digite a senha terminando com #. A tecla # está no canto inferior direito do teclado e pode ter um ícone diferente"
} }

1183
lan/lan_pt_br.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -104,7 +104,7 @@
"门磁": "Senzor uși", "门磁": "Senzor uși",
"自动闭锁": "Blocare automată", "自动闭锁": "Blocare automată",
"锁声音": "Blochează sunetul.", "锁声音": "Blochează sunetul.",
"防撬报警": "Alertă TamperName", "防撬报警": "Alertă Tamper",
"重置键": "Butonul resitează", "重置键": "Butonul resitează",
"锁时间": "Blochează ceasul", "锁时间": "Blochează ceasul",
"诊断": "Diagnostică", "诊断": "Diagnostică",
@ -185,7 +185,7 @@
"删除账号": "Șterge cont", "删除账号": "Șterge cont",
"个人信息": "Informații cont", "个人信息": "Informații cont",
"头像": "Avatar", "头像": "Avatar",
"昵称": "NickNameName", "昵称": "NickName",
"请输入昵称": "Introduceți porecla dumneavoastră", "请输入昵称": "Introduceți porecla dumneavoastră",
"修改昵称": "Redenumește:", "修改昵称": "Redenumește:",
"修改账号": "Editează cont", "修改账号": "Editează cont",
@ -210,7 +210,7 @@
"WiFi名称": "Nume WiFi", "WiFi名称": "Nume WiFi",
"网络MAC": "Rețea MAC", "网络MAC": "Rețea MAC",
"网关升级": "Actualizare GatewayComment", "网关升级": "Actualizare GatewayComment",
"网关连接的锁": "Blocare (blocare) conectat la această GatewayName", "网关连接的锁": "Blocare (blocare) conectat la această Gateway",
"信号强": "Puternică", "信号强": "Puternică",
"选择网关类型": "Alegeți tipul de port", "选择网关类型": "Alegeți tipul de port",
"添加网关": "Adaugă poartă", "添加网关": "Adaugă poartă",
@ -316,7 +316,7 @@
"开门器": "Deschizător de uși", "开门器": "Deschizător de uși",
"面容开锁": "Fața deblochează", "面容开锁": "Fața deblochează",
"开门方向设置": "Set de direcție de deschidere", "开门方向设置": "Set de direcție de deschidere",
"电机功率设置": "Setare MotorPowerName", "电机功率设置": "Setare MotorPower",
"开锁时是否需联网": "Dacă Internetul este necesar la deblocarea", "开锁时是否需联网": "Dacă Internetul este necesar la deblocarea",
"选择要加入分组的锁": "Selectați blocarea S pentru a adăuga la acest grupă", "选择要加入分组的锁": "Selectați blocarea S pentru a adăuga la acest grupă",
"锁数量": "Blochează numărător", "锁数量": "Blochează numărător",
@ -593,7 +593,7 @@
"开门通知": "Notificare de deschidere.", "开门通知": "Notificare de deschidere.",
"N天未开门": "N zile fără deschiderea ușii", "N天未开门": "N zile fără deschiderea ușii",
"门未关好": "Uşa nu e închisă.", "门未关好": "Uşa nu e închisă.",
"防拆报警": "Alarmă TamperName", "防拆报警": "Alarmă Tamper",
"低电量提醒": "Baterie scăzută", "低电量提醒": "Baterie scăzută",
"胁迫开门": "Deschiderea ușilor forțate", "胁迫开门": "Deschiderea ușilor forțate",
"有人按门铃": "Cineva sună la uşă.", "有人按门铃": "Cineva sună la uşă.",
@ -633,12 +633,12 @@
"云存": "Stocarea norilor", "云存": "Stocarea norilor",
"本地": "Această localitate:", "本地": "Această localitate:",
"3天滚动储存": "3 zile de păstrare rulare", "3天滚动储存": "3 zile de păstrare rulare",
"去升级": "Actualizare acumName", "去升级": "Actualizare acum",
"下载列表": "Lista descărcării", "下载列表": "Lista descărcării",
"已下载": "Descărcat", "已下载": "Descărcat",
"全部视频": "Toate videoclipurile", "全部视频": "Toate videoclipurile",
"已为本设备免费提供3大滚动视频储存服务": "Pentru acest dispozitiv au fost furnizate trei servicii de stocare video de derulare gratuite", "已为本设备免费提供3大滚动视频储存服务": "Pentru acest dispozitiv au fost furnizate trei servicii de stocare video de derulare gratuite",
"视频播放": "Redare videoName", "视频播放": "Redare video",
"全选": "Toate.", "全选": "Toate.",
"请选择要删除的视频": "Alegeți videoclipul pe care doriți să o ștergeți.", "请选择要删除的视频": "Alegeți videoclipul pe care doriți să o ștergeți.",
"请选择要下载的视频": "Vă rugăm să selectați videoclipul pe care doriți să le descărcați", "请选择要下载的视频": "Vă rugăm să selectați videoclipul pe care doriți să le descărcați",
@ -691,7 +691,7 @@
"请输入身份证号和真实姓名": "Introduceți numărul și numele real.", "请输入身份证号和真实姓名": "Introduceți numărul și numele real.",
"点击返回设备配对": "Atinge înapoi la împerecherea dispozitivului", "点击返回设备配对": "Atinge înapoi la împerecherea dispozitivului",
"无法连接?尝试升级": "Nu se poate conecta?", "无法连接?尝试升级": "Nu se poate conecta?",
"固件升级提示": "Prompt de upgrade FirmwareName", "固件升级提示": "Prompt de upgrade Firmware",
"请先获取固件文件到手机本地,再选择升级": "Vă rugăm să obțineți fișierul firmware la telefonul local întâi, și apoi selectați Upgrade.", "请先获取固件文件到手机本地,再选择升级": "Vă rugăm să obțineți fișierul firmware la telefonul local întâi, și apoi selectați Upgrade.",
"固件升级中": "Firware-ul este în actualizare", "固件升级中": "Firware-ul este în actualizare",
"取消升级": "Anulează actualizarea", "取消升级": "Anulează actualizarea",
@ -710,7 +710,7 @@
"传输期间请勿离开当前页面": "Nu părăsi pagina curentă în timpul transferului", "传输期间请勿离开当前页面": "Nu părăsi pagina curentă în timpul transferului",
"机型": "Modele", "机型": "Modele",
"硬件版本": "Versiune hardware", "硬件版本": "Versiune hardware",
"固件版本": "Versiunea FirmwareName", "固件版本": "Versiunea Firmware",
"手动升级": "Upgrade manuală", "手动升级": "Upgrade manuală",
"设备连接中...": "Conectare dispozitivă...", "设备连接中...": "Conectare dispozitivă...",
"未避免异常情况,请在门打开时升级": "Excepţii inevitabile, vă rugăm să upgradezi când uşa este deschisă.", "未避免异常情况,请在门打开时升级": "Excepţii inevitabile, vă rugăm să upgradezi când uşa este deschisă.",
@ -834,7 +834,7 @@
"微信": "WeChat", "微信": "WeChat",
"朋友圈": "Momente", "朋友圈": "Momente",
"QQ": "QQ", "QQ": "QQ",
"QQ空间": "QQZoneName", "QQ空间": "QQZone",
"微博": "Weibo.", "微博": "Weibo.",
"FaceBook": "FacebookComment", "FaceBook": "FacebookComment",
"链接": "Legătură", "链接": "Legătură",
@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "După resetare, venele metacarpale ale încuietorii vor fi şterse. Sigur doriți să resetați?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "După resetare, venele metacarpale ale încuietorii vor fi şterse. Sigur doriți să resetați?",
@ -1099,7 +1100,7 @@
"支持的国家值": "Statele Unite ale Americii, Canada, Marea Britanie, Australia, India, Germania, Franța, Italia, Spania, Japonia", "支持的国家值": "Statele Unite ale Americii, Canada, Marea Britanie, Australia, India, Germania, Franța, Italia, Spania, Japonia",
"操作流程": "Procesul operațional", "操作流程": "Procesul operațional",
"操作流程值": "1 Adăugați o blocare și o poartă cu Smart blocare APP\n\n2 Activați funcția de deblocare la distanță a încuietorii din APP (acesta funcție este oprită implicit). Dacă nu aveți această opțiune, blocarea nu suportă Alexa\n\n3 Adăugați abilități pentru Alexa și autorizați-le cu Smart blocare contul și parola APP. După ce autorizaţia va avea succes, puteţi descoperi dispozitivele sub cont\n\n4 Localizaţi blocarea în aplicaţia Alexa, activaţi funcţia de deblocare vocală, şi setaţi parola limbii\n\n5 Încuietoarea poate fi operată prin Alexa", "操作流程值": "1 Adăugați o blocare și o poartă cu Smart blocare APP\n\n2 Activați funcția de deblocare la distanță a încuietorii din APP (acesta funcție este oprită implicit). Dacă nu aveți această opțiune, blocarea nu suportă Alexa\n\n3 Adăugați abilități pentru Alexa și autorizați-le cu Smart blocare contul și parola APP. După ce autorizaţia va avea succes, puteţi descoperi dispozitivele sub cont\n\n4 Localizaţi blocarea în aplicaţia Alexa, activaţi funcţia de deblocare vocală, şi setaţi parola limbii\n\n5 Încuietoarea poate fi operată prin Alexa",
"Google Home": "Acasă GoogleName", "Google Home": "Acasă Google",
"Action name": "Nume acțiune", "Action name": "Nume acțiune",
"ScienerSmart": "ScienerSmart", "ScienerSmart": "ScienerSmart",
"支持的语言": "Limbi suportate", "支持的语言": "Limbi suportate",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Configurarea pachetului vocal de blocare", "锁语音包设置": "Configurarea pachetului vocal de blocare",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "vocea bărbatului", "男声": "vocea bărbatului",
"女声": "Voce feminină" "女声": "Voce feminină",
"您的图像和视频数据仅保留": "Datele tale de imagine și video sunt păstrate numai",
"后图像和视频数据将会失效,开通": "După aceea, datele de imagine și video vor fi invalide și activate",
"云存会员": "Abonament de stocare în cloud",
"服务,图像视频信息随心存!": "Serviciile, imaginile și informațiile video sunt în centrul dumneavoastră!",
"图像": "imagine",
"视频": "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",
"注:": "Notă:",
"必需在开始时间24小时内使用一次否则将失效": "Trebuie folosit o dată în termen de 24 de ore de la ora de început, altfel va expira",
"这是单次密码,只能使用一次": "Aceasta este o parolă unică și poate fi folosită doar o dată",
"您好": "Bună",
"您的开门密码是": "Codul dvs. de acces la ușă este",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Pentru a debloca, activați mai întâi tastatura lacătului, apoi introduceți parola și terminați cu #. Tasta # se află în colțul din dreapta jos al tastaturii și poate avea o altă pictogramă"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "После сброса пястные вены замка будут удалены. Вы уверены, что хотите сбросить?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "После сброса пястные вены замка будут удалены. Вы уверены, что хотите сбросить?",
@ -1164,5 +1165,18 @@
"锁语音包设置": "Запустить настройки голосового пакета", "锁语音包设置": "Запустить настройки голосового пакета",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Мужской голос", "男声": "Мужской голос",
"女声": "Женские голоса" "女声": "Женские голоса",
"您的图像和视频数据仅保留": "Ваши изображения и видеоданные сохраняются только",
"后图像和视频数据将会失效,开通": "После этого изображение и видео данные будут недействительными и активированы",
"云存会员": "Членство в облачном хранилище",
"服务,图像视频信息随心存!": "Сервисная, имиджевая и видеоинформация в Вашем сердце!",
"图像": "образ",
"视频": "Видео",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "В настоящее время страна не поддерживает регистрацию кода верификации мобильного телефона, пожалуйста, используйте свой адрес электронной почты для регистрации",
"注:": "Примечание:",
"必需在开始时间24小时内使用一次否则将失效": "Должен быть использован один раз в течение 24 часов с момента начала, иначе он истечет",
"这是单次密码,只能使用一次": "Это одноразовый пароль, который можно использовать только один раз",
"您好": "Привет!",
"您的开门密码是": "Ваш код доступа к двери",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Чтобы разблокировать, сначала активируйте клавиатуру замка, затем введите пароль и закончите #. Клавиша # находится в правом нижнем углу клавиатуры и может иметь другой значок"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Po resetovaní budú metakarpálne žily zámku vymazané. Ste si istí, že chcete obnoviť?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Po resetovaní budú metakarpálne žily zámku vymazané. Ste si istí, že chcete obnoviť?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Zamknutie nastavení hlasového balíka", "锁语音包设置": "Zamknutie nastavení hlasového balíka",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "mužský hlas", "男声": "mužský hlas",
"女声": "Ženský hlas" "女声": "Ženský hlas",
"您的图像和视频数据仅保留": "Vaše údaje o obrázkoch a videách sa zachovajú iba",
"后图像和视频数据将会失效,开通": "Potom budú údaje o obrázku a videu neplatné a aktivované",
"云存会员": "Členstvo v cloudovom úložisku",
"服务,图像视频信息随心存!": "Informácie o službách, obrázkoch a videách sú vo vašom srdci!",
"图像": "obraz",
"视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "V súčasnosti krajina nepodporuje registráciu overovacieho kódu mobilného telefónu, na registráciu použite svoju e-mailovú adresu",
"注:": "Poznámka:",
"必需在开始时间24小时内使用一次否则将失效": "Musí byť použitý raz do 24 hodín od počiatočného času, inak vyprší",
"这是单次密码,只能使用一次": "Toto je jednorazové heslo, ktoré možno použiť iba raz",
"您好": "Ahoj",
"您的开门密码是": "Váš prístupový kód do dverí je",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Ak chcete odomknúť, najprv aktivujte klávesnicu zámku, potom zadajte heslo a ukončite #. Kľúč # je v pravom dolnom rohu klávesnice a môže mať inú ikonu"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Након ресетовања, метакарпалне вене браве ће бити избрисане. Да ли сте сигурни да желите да ресетујете?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Након ресетовања, метакарпалне вене браве ће бити избрисане. Да ли сте сигурни да желите да ресетујете?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Закључајте подешавања говорног пакета", "锁语音包设置": "Закључајте подешавања говорног пакета",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "мушки глас", "男声": "мушки глас",
"女声": "женски глас" "女声": "женски глас",
"您的图像和视频数据仅保留": "Ваши подаци о слици и видео записима се задржавају само",
"后图像和视频数据将会失效,开通": "Након тога, сликовни и видео подаци ће бити неважећи и активирани",
"云存会员": "Чланство у облаку за складиштење",
"服务,图像视频信息随心存!": "Сервис , слике и видео информације су у вашем срцу!",
"图像": "Слика",
"视频": "Пријава",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Тренутно , земља не подржава регистрацију кода за верификацију мобилног телефона, молимо вас да користите своју адресу е-поште за регистрацију",
"注:": "Напомена:",
"必需在开始时间24小时内使用一次否则将失效": "Мора се користити једном у року од 24 сата од времена почетка, иначе истиче",
"这是单次密码,只能使用一次": "Ово је једнократна лозинка која се може користити само једном",
"您好": "Здраво",
"您的开门密码是": "Ваш код за отварање врата је",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Да бисте откључали, прво активирајте тастатуру браве, затим унесите лозинку и завршите са #. Тастер # се налази у доњем десном углу тастатуре и може имати другу икону"
} }

View File

@ -116,7 +116,7 @@
"微信二维码": "Lås upp QR- koden", "微信二维码": "Lås upp QR- koden",
"拥有电子钥匙的人,通过微信扫一扫这个二维码,即可开门。每把锁的二维码都不相同,你可以将其打印出来贴在对应的锁旁边": "Personer med elektroniska nycklar kan öppna dörren genom att skanna denna QR-kod genom WeChat. QR-koden för varje lås är olika. Du kan skriva ut den och klistra in den bredvid motsvarande lås", "拥有电子钥匙的人,通过微信扫一扫这个二维码,即可开门。每把锁的二维码都不相同,你可以将其打印出来贴在对应的锁旁边": "Personer med elektroniska nycklar kan öppna dörren genom att skanna denna QR-kod genom WeChat. QR-koden för varje lås är olika. Du kan skriva ut den och klistra in den bredvid motsvarande lås",
"锁编号": "Låsnummer", "锁编号": "Låsnummer",
"电量": "BatteriName", "电量": "Batteri",
"锁分组": "Lås grupp", "锁分组": "Lås grupp",
"选择分组": "Välj grupp", "选择分组": "Välj grupp",
"创建新分组": "Skapa en grupp", "创建新分组": "Skapa en grupp",
@ -146,8 +146,8 @@
"上传": "Uppladdning", "上传": "Uppladdning",
"本操作将上传锁内数据到服务器,过程可能需要几分钟,请耐心等待": "Ladda upp data från lås till server.Det kan ta flera minuter.", "本操作将上传锁内数据到服务器,过程可能需要几分钟,请耐心等待": "Ladda upp data från lås till server.Det kan ta flera minuter.",
"请选择要从哪把锁导入": "Välj ett lås att importera från", "请选择要从哪把锁导入": "Välj ett lås att importera från",
"有新版本": "Har ny versionName", "有新版本": "Har ny version",
"当前版本": "Nuvarande versionName", "当前版本": "Nuvarande version",
"升级": "Uppdatera", "升级": "Uppdatera",
"空闲": "Lediga", "空闲": "Lediga",
"已入住": "Upptagen", "已入住": "Upptagen",
@ -185,7 +185,7 @@
"删除账号": "Ta bort konto", "删除账号": "Ta bort konto",
"个人信息": "Kontoinformation", "个人信息": "Kontoinformation",
"头像": "Avatar", "头像": "Avatar",
"昵称": "NickNameName", "昵称": "NickName",
"请输入昵称": "Ange ditt smeknamn", "请输入昵称": "Ange ditt smeknamn",
"修改昵称": "Byt namn", "修改昵称": "Byt namn",
"修改账号": "Redigera konto", "修改账号": "Redigera konto",
@ -316,7 +316,7 @@
"开门器": "Dörröppnare", "开门器": "Dörröppnare",
"面容开锁": "Ansiktet upplåsas", "面容开锁": "Ansiktet upplåsas",
"开门方向设置": "Öppningsriktning", "开门方向设置": "Öppningsriktning",
"电机功率设置": "Inställning av motorpowerName", "电机功率设置": "Inställning av motorpower",
"开锁时是否需联网": "Om Internet krävs vid upplåsning", "开锁时是否需联网": "Om Internet krävs vid upplåsning",
"选择要加入分组的锁": "Välj Lås för att lägga till i gruppen.", "选择要加入分组的锁": "Välj Lås för att lägga till i gruppen.",
"锁数量": "Lås antal", "锁数量": "Lås antal",
@ -450,7 +450,7 @@
"是否发送电子钥匙给未注册账号": "Vill du skicka en ekey till ett nytt konto", "是否发送电子钥匙给未注册账号": "Vill du skicka en ekey till ett nytt konto",
"取消": "Avbryt", "取消": "Avbryt",
"标记成功": "Markera framgångsrikt", "标记成功": "Markera framgångsrikt",
"微信好友": "WeChat- vännerName", "微信好友": "WeChat- vänner",
"短信": "SMS", "短信": "SMS",
"邮件": "E- post@ info: whatsthis", "邮件": "E- post@ info: whatsthis",
"更多": "Flere", "更多": "Flere",
@ -703,7 +703,7 @@
"传输中": "Under transitering", "传输中": "Under transitering",
"发送人": "Utfärdat av:", "发送人": "Utfärdat av:",
"发送时间": "Utfärdad tid", "发送时间": "Utfärdad tid",
"钥匙详情": "EKEY- infoName", "钥匙详情": "EKEY- info",
"姓名": "Namn", "姓名": "Namn",
"发送": "Skicka", "发送": "Skicka",
"请确认姓名全名和身份证号码是否正确": "Bekräfta att fullständigt namn och ID-nummer är korrekt.", "请确认姓名全名和身份证号码是否正确": "Bekräfta att fullständigt namn och ID-nummer är korrekt.",
@ -834,8 +834,8 @@
"微信": "Wechat", "微信": "Wechat",
"朋友圈": "Momentar", "朋友圈": "Momentar",
"QQ": "QQ", "QQ": "QQ",
"QQ空间": "QQZoneName", "QQ空间": "QQZone",
"微博": "WeiboName", "微博": "Weibo",
"FaceBook": "Facebok", "FaceBook": "Facebok",
"链接": "Länk", "链接": "Länk",
"今天": "Idag", "今天": "Idag",
@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Efter återställd, de metakarpal venerna i låset tas bort. Är du säker på att du vill återställa?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Efter återställd, de metakarpal venerna i låset tas bort. Är du säker på att du vill återställa?",
@ -1099,7 +1100,7 @@
"支持的国家值": "USA, Kanada, Storbritannien, Australien, Indien, Tyskland, Frankrike, Italien, Spanien, Japan.", "支持的国家值": "USA, Kanada, Storbritannien, Australien, Indien, Tyskland, Frankrike, Italien, Spanien, Japan.",
"操作流程": "Driftsprocess", "操作流程": "Driftsprocess",
"操作流程值": "1 Lägg till ett lås och gateway med Smart Lås APP\n\n2 Aktivera fjärrlåsningsfunktionen för låset i APP (denna funktion är avstängd som standard). Om du inte har det här alternativet stöder inte låset Alexa\n\n3 Lägg till färdigheter till Alexa och godkänna dem med Smart lås APP konto och lösenord. När auktorisationen är framgångsrik kan du upptäcka enheter under kontot\n\n4 Hitta låset i Alexa-appen, slå på röst upplåsningsfunktionen och ställa in språklösenordet.\n\n5 Låset kan manövreras genom Alexa", "操作流程值": "1 Lägg till ett lås och gateway med Smart Lås APP\n\n2 Aktivera fjärrlåsningsfunktionen för låset i APP (denna funktion är avstängd som standard). Om du inte har det här alternativet stöder inte låset Alexa\n\n3 Lägg till färdigheter till Alexa och godkänna dem med Smart lås APP konto och lösenord. När auktorisationen är framgångsrik kan du upptäcka enheter under kontot\n\n4 Hitta låset i Alexa-appen, slå på röst upplåsningsfunktionen och ställa in språklösenordet.\n\n5 Låset kan manövreras genom Alexa",
"Google Home": "Google HomeName", "Google Home": "Google Home",
"Action name": "Åtgärdsnamn", "Action name": "Åtgärdsnamn",
"ScienerSmart": "ScienerSmart", "ScienerSmart": "ScienerSmart",
"支持的语言": "Stödda språk", "支持的语言": "Stödda språk",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Lås inställningar för röstpaket", "锁语音包设置": "Lås inställningar för röstpaket",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Mänsklig röst", "男声": "Mänsklig röst",
"女声": "Kvinnlig röst" "女声": "Kvinnlig röst",
"您的图像和视频数据仅保留": "Dina bild- och videodata sparas endast",
"后图像和视频数据将会失效,开通": "Efter det kommer bild- och videodata att vara ogiltiga och aktiverade",
"云存会员": "Medlemskap i molnlagring",
"服务,图像视频信息随心存!": "Service, bild- och videoinformation finns i ditt hjärta!",
"图像": "bild",
"视频": "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",
"注:": "Obs:",
"必需在开始时间24小时内使用一次否则将失效": "Måste användas en gång inom 24 timmar efter starttiden, annars löper den ut",
"这是单次密码,只能使用一次": "Detta är ett engångslösenord och kan endast användas en gång",
"您好": "Hej",
"您的开门密码是": "Din dörröppningskod är",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "För att låsa upp, aktivera först låsens tangentbord, ange sedan lösenordet och avsluta med #. #-tangenten finns i det nedre högra hörnet av tangentbordet och kan ha en annan ikon"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วหลอดเลือดดำ metacarpal ของล็อคจะถูกลบออกคุณแน่ใจว่าอยากจะรีเซ็ต?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วหลอดเลือดดำ metacarpal ของล็อคจะถูกลบออกคุณแน่ใจว่าอยากจะรีเซ็ต?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "ล็อคการตั้งค่า Voice Pack", "锁语音包设置": "ล็อคการตั้งค่า Voice Pack",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "เสียงผู้ชาย", "男声": "เสียงผู้ชาย",
"女声": "เสียงผู้หญิง" "女声": "เสียงผู้หญิง",
"您的图像和视频数据仅保留": "ระบบจะเก็บข้อมูลรูปภาพและวิดีโอของคุณไว้เท่านั้น",
"后图像和视频数据将会失效,开通": "หลังจากนั้น ข้อมูลรูปภาพและวิดีโอจะไม่ถูกต้องและเปิดใช้งาน",
"云存会员": "สมาชิกที่เก็บข้อมูลบนคลาวด์",
"服务,图像视频信息随心存!": "ข้อมูลบริการ รูปภาพ และวิดีโออยู่ที่หัวใจของคุณ!",
"图像": "ภาพ",
"视频": "วีดิทัศน์",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "ปัจจุบันประเทศไม่รองรับการลงทะเบียนรหัสยืนยันโทรศัพท์มือถือ โปรดใช้ที่อยู่อีเมลของคุณในการลงทะเบียน",
"注:": "หมายเหตุ:",
"必需在开始时间24小时内使用一次否则将失效": "ต้องใช้ภายใน 24 ชั่วโมงหลังจากเวลาเริ่มต้น มิฉะนั้นจะหมดอายุ",
"这是单次密码,只能使用一次": "นี่คือรหัสผ่านแบบใช้ครั้งเดียวและสามารถใช้ได้เพียงครั้งเดียวเท่านั้น",
"您好": "สวัสดี",
"您的开门密码是": "รหัสการเข้าถึงประตูของคุณคือ",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "ในการปลดล็อค ให้เปิดใช้งานแป้นพิมพ์ล็อคก่อน จากนั้นป้อนรหัสผ่านและจบด้วย # ปุ่ม # อยู่ที่มุมล่างขวาของแป้นพิมพ์และอาจมีไอคอนอื่น"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Sıfırlamadan sonra, kilidin metacarpal damarları silinecektir. Sıfırlamak istediğine emin misin?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Sıfırlamadan sonra, kilidin metacarpal damarları silinecektir. Sıfırlamak istediğine emin misin?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Ses Paketi Ayarlarını Kilitle", "锁语音包设置": "Ses Paketi Ayarlarını Kilitle",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Erkek Sesi", "男声": "Erkek Sesi",
"女声": "Kadın Sesi" "女声": "Kadın Sesi",
"您的图像和视频数据仅保留": "Görüntü ve video verileriniz yalnızca korunur",
"后图像和视频数据将会失效,开通": "Bundan sonra, görüntü ve video verileri geçersiz olacak ve etkinleştirilecektir",
"云存会员": "Bulut Depolama Üyeliği",
"服务,图像视频信息随心存!": "Servis, görüntü ve video bilgileri kalbinizde!",
"图像": "resim",
"视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Şu anda ülke cep telefonu doğrulama kodu kaydını desteklememektedir, lütfen kaydolmak için e-posta adresinizi kullanın",
"注:": "Not:",
"必需在开始时间24小时内使用一次否则将失效": "Başlangıç zamanından itibaren 24 saat içinde bir kez kullanılmalıdır, aksi takdirde süresi dolacaktır",
"这是单次密码,只能使用一次": "Bu tek kullanımlık bir şifredir ve yalnızca bir kez kullanılabilir",
"您好": "Merhaba",
"您的开门密码是": "Kapı erişim kodunuz",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Kilidi açmak için önce kilit klavyesini etkinleştirin, ardından şifreyi girin ve # ile bitirin. # tuşu klavyenin sağ alt köşesindedir ve farklı bir simge olabilir"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "重置後,鎖的掌靜脈將被刪除。 是否確實要重置?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "重置後,鎖的掌靜脈將被刪除。 是否確實要重置?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "鎖語音包設定", "锁语音包设置": "鎖語音包設定",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "男聲", "男声": "男聲",
"女声": "女聲" "女声": "女聲",
"您的图像和视频数据仅保留": "您的圖像和視頻數據僅保留",
"后图像和视频数据将会失效,开通": "后圖像和視頻數據將會失效,開通",
"云存会员": "雲存會員",
"服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!",
"图像": "圖像",
"视频": "視頻",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "當前國家不支援手機驗證碼註冊,請使用郵箱進行註冊",
"注:": "註:",
"必需在开始时间24小时内使用一次否则将失效": "必須在開始時間24小時內使用一次否則將失效",
"这是单次密码,只能使用一次": "這是單次密碼,只能使用一次",
"您好": "您好",
"您的开门密码是": "您的開門密碼是",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "開鎖時,先啟動鎖鍵盤,再輸入密碼,以#號結束,#號鍵在鍵盤右下角,有可能是其他圖標"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Після скидання п'ясткові вени замку будуть видалені. Ви впевнені, що хочете скинути налаштування?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Після скидання п'ясткові вени замку будуть видалені. Ви впевнені, що хочете скинути налаштування?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Параметри блокування голосового пакету", "锁语音包设置": "Параметри блокування голосового пакету",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Чоловічий голос", "男声": "Чоловічий голос",
"女声": "жіночий голос" "女声": "жіночий голос",
"您的图像和视频数据仅保留": "Ваші зображення та відеодані зберігаються лише",
"后图像和视频数据将会失效,开通": "Після цього дані зображення та відео будуть недійсними та активованими",
"云存会员": "Членство в хмарних сховищах",
"服务,图像视频信息随心存!": "Сервіс, зображення та відео інформація у вашому серці!",
"图像": "образ",
"视频": "Відео",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Наразі країна не підтримує реєстрацію коду підтвердження на мобільному телефоні, будь ласка, використовуйте свою адресу електронної пошти для реєстрації",
"注:": "Примітка:",
"必需在开始时间24小时内使用一次否则将失效": "Потрібно використати один раз протягом 24 годин після початкового часу, інакше термін дії спливе",
"这是单次密码,只能使用一次": "Це одноразовий пароль, який можна використовувати лише один раз",
"您好": "Привіт",
"您的开门密码是": "Ваш код доступу до дверей",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Щоб розблокувати, спочатку активуйте клавіатуру замка, потім введіть пароль і закінчіть #. Клавіша # знаходиться в правому нижньому куті клавіатури та може мати інший значок"
} }

View File

@ -1067,7 +1067,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1080,10 +1080,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "ری سیٹ کرنے کے بعد ، لاک کی میٹاکارپل رگیں حذف کردی جائیں گی۔ کیا آپ واقعی دوبارہ ترتیب دینا چاہتے ہیں؟", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "ری سیٹ کرنے کے بعد ، لاک کی میٹاکارپل رگیں حذف کردی جائیں گی۔ کیا آپ واقعی دوبارہ ترتیب دینا چاہتے ہیں؟",
@ -1160,5 +1161,18 @@
"锁语音包设置": "صوتی پیکیج کی ترتیبات لاک کریں", "锁语音包设置": "صوتی پیکیج کی ترتیبات لاک کریں",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "مردوں کی آواز", "男声": "مردوں کی آواز",
"女声": "خواتین کی آواز" "女声": "خواتین کی آواز",
"您的图像和视频数据仅保留": "آپ کی تصویر اور ویڈیو کا ڈیٹا صرف برقرار رکھا گیا ہے",
"后图像和视频数据将会失效,开通": "اس کے بعد ، تصویر اور ویڈیو کا ڈیٹا غیر قانونی اور فعال ہوجائے گا۔",
"云存会员": "Cloud Storage Membership",
"服务,图像视频信息随心存!": "خدمت، تصویر اور ویڈیو کی معلومات آپ کے دل میں ہیں!",
"图像": "روپ",
"视频": "ویڈیو",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "فی الحال، ملک موبائل فون کی توثیقی کوڈ رجسٹریشن کی حمایت نہیں کرتا ہے، براہ کرم رجسٹر کرنے کے لئے اپنا ای میل ایڈریس استعمال کریں",
"注:": "نوٹ:",
"必需在开始时间24小时内使用一次否则将失效": "وقت آغاز سے 24 گھنٹوں کے اندر ایک بار استعمال کرنا ضروری ہے، ورنہ اس کی میعاد ختم ہو جائے گی",
"这是单次密码,只能使用一次": "یہ ایک بار کا پاس ورڈ ہے اور صرف ایک بار استعمال کیا جا سکتا ہے",
"您好": "ہیلو",
"您的开门密码是": "آپ کا دروازہ کھولنے کا کوڈ ہے",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "غیر مقفل کرنے کے لئے، پہلے لاک کی بورڈ کو چالو کریں، پھر پاس ورڈ درج کریں اور # کے ساتھ ختم کریں۔ # کلید کی بورڈ کے دائیں نچلے کونے میں ہے اور اس میں کوئی اور آئیکن ہو سکتی ہے"
} }

View File

@ -1065,7 +1065,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1078,10 +1078,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"繁体中文(中国台湾)": "繁體中文(中國臺灣)", "繁体中文(中国台湾)": "繁體中文(中國臺灣)",
"繁体中文(中国香港)": "繁體中文(中國香港)", "繁体中文(中国香港)": "繁體中文(中國香港)",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Sau khi đặt lại, các tĩnh mạch metacarpal của khóa sẽ bị xóa. Bạn có chắc muốn thiết lập lại không?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "Sau khi đặt lại, các tĩnh mạch metacarpal của khóa sẽ bị xóa. Bạn có chắc muốn thiết lập lại không?",
@ -1160,5 +1161,18 @@
"锁语音包设置": "Khóa cài đặt gói thoại", "锁语音包设置": "Khóa cài đặt gói thoại",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Giọng nam", "男声": "Giọng nam",
"女声": "Giọng nữ" "女声": "Giọng nữ",
"您的图像和视频数据仅保留": "Dữ liệu hình ảnh và video của bạn chỉ được giữ lại",
"后图像和视频数据将会失效,开通": "Sau đó, dữ liệu hình ảnh và video sẽ không hợp lệ và được kích hoạt",
"云存会员": "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!",
"图像": "ảnh",
"视频": "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ý",
"注:": "Lưu ý:",
"必需在开始时间24小时内使用一次否则将失效": "Phải được sử dụng một lần trong vòng 24 giờ kể từ thời điểm bắt đầu, nếu không sẽ hết hạn",
"这是单次密码,只能使用一次": "Đây là mật khẩu một lần và chỉ có thể sử dụng một lần",
"您好": "Xin chào",
"您的开门密码是": "Mã truy cập cửa của bạn là",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Để mở khóa, trước tiên hãy kích hoạt bàn phím khóa, sau đó nhập mật khẩu và kết thúc bằng #. Phím # nằm ở góc dưới bên phải của bàn phím và có thể có biểu tượng khác"
} }

View File

@ -63,7 +63,6 @@
"授权管理员拥有操作这把锁的重要权限,请确保只发给我你信任的人": "授权管理员拥有操作这把锁的重要权限,请确保只发给我你信任的人", "授权管理员拥有操作这把锁的重要权限,请确保只发给我你信任的人": "授权管理员拥有操作这把锁的重要权限,请确保只发给我你信任的人",
"功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。": "功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。", "功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。": "功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。",
"此功能的开启和关闭只能在锁附近通过手机蓝牙进行": "此功能的开启和关闭只能在锁附近通过手机蓝牙进行", "此功能的开启和关闭只能在锁附近通过手机蓝牙进行": "此功能的开启和关闭只能在锁附近通过手机蓝牙进行",
"功能开启后,你将可以通过网关远程开锁。": "功能开启后,你将可以通过网关远程开锁。", "功能开启后,你将可以通过网关远程开锁。": "功能开启后,你将可以通过网关远程开锁。",
"排列方式": "排列方式", "排列方式": "排列方式",
"早到榜": "早到榜", "早到榜": "早到榜",
@ -1070,7 +1069,7 @@
"波兰语": "Polski", "波兰语": "Polski",
"斯洛伐克语": "Slovenčina", "斯洛伐克语": "Slovenčina",
"捷克语": "Čeština", "捷克语": "Čeština",
"希腊语": "Ελληνικά", "希腊语": "ελληνικά",
"希伯来语": "עברית", "希伯来语": "עברית",
"塞尔维亚语": "Српски", "塞尔维亚语": "Српски",
"土耳其语": "Türkçe", "土耳其语": "Türkçe",
@ -1083,10 +1082,11 @@
"印度尼西亚语": "Bahasa Indonesia", "印度尼西亚语": "Bahasa Indonesia",
"芬兰语": "Suomi", "芬兰语": "Suomi",
"丹麦语": "Dansk", "丹麦语": "Dansk",
"印地语": "हिंदीName", "印地语": "हिंदी",
"乌尔都语": "اوردو", "乌尔都语": "اوردو",
"亚美尼亚语": "Հայերեն", "亚美尼亚语": "Հայերեն",
"格鲁吉亚语": "ქართული", "格鲁吉亚语": "ქართული",
"巴西葡萄牙语": "Português do Brasil",
"重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?", "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?": "重置后,该锁的掌静脉都将被删除哦,确认要重置吗?",
"在线": "在线", "在线": "在线",
"离线": "离线", "离线": "离线",
@ -1101,7 +1101,7 @@
"支持的国家": "支持的国家", "支持的国家": "支持的国家",
"支持的国家值": "美国、加拿大、英国、澳大利亚、印度、德国、法国、意大利、西班牙、日本", "支持的国家值": "美国、加拿大、英国、澳大利亚、印度、德国、法国、意大利、西班牙、日本",
"操作流程": "操作流程", "操作流程": "操作流程",
"操作流程值":"1 用智能锁APP添加锁和网关\n\n2 在APP里开启锁的远程开锁功能这个功能默认是关闭的。如果没有这个选项则锁不支持Alexa \n\n3 在Alexa中添加Skill并用智能锁APP的账号和密码进行授权。授权成功后就可以发现账号下的设备\n\n4 在Alexa app里找到锁开启语音开锁的功能并设置语言密码\n\n5 可以通过Alexa操作锁了", "操作流程值": "1 用智能锁APP添加锁和网关\n\n2 在APP里开启锁的远程开锁功能这个功能默认是关闭的。如果没有这个选项则锁不支持Alexa \n\n3 在Alexa中添加Skill并用智能锁APP的账号和密码进行授权。授权成功后就可以发现账号下的设备\n\n4 在Alexa app里找到锁开启语音开锁的功能并设置语言密码\n\n5 可以通过Alexa操作锁了",
"Google Home": "Google Home", "Google Home": "Google Home",
"Action name": "Action name", "Action name": "Action name",
"ScienerSmart": "ScienerSmart", "ScienerSmart": "ScienerSmart",
@ -1173,5 +1173,18 @@
"语音包设置": "语音包设置", "语音包设置": "语音包设置",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "男声", "男声": "男声",
"女声": "女声" "女声": "女声",
} "您的图像和视频数据仅保留": "您的图像和视频数据仅保留",
"后图像和视频数据将会失效,开通": "后图像和视频数据将会失效,开通",
"云存会员": "云存会员",
"服务,图像视频信息随心存!": "服务,图像视频信息随心存!",
"图像": "图像",
"视频": "视频",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "当前国家不支持手机验证码注册,请使用邮箱进行注册",
"注:":"注:",
"必需在开始时间24小时内使用一次否则将失效": "必需在开始时间24小时内使用一次否则将失效",
"这是单次密码,只能使用一次": "这是单次密码,只能使用一次",
"您好": "您好",
"您的开门密码是": "您的开门密码是",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标"
}

348
langAzure.py Normal file
View File

@ -0,0 +1,348 @@
#!/usr/bin/python3
import datetime
import json
import os
import re
import sys
import time
from typing import Dict
import requests
# 运行格式方式一python langAzure.py
# 运行格式方式二python3 langAzure.py
# 语言文件路径
path = "./resources/lang/"
# 原语言
SOURCE_LANG = 'en_US'
# 过滤不翻译的语言
FILTER_LANG = ['zh_CN', 'en_US']
# Azure翻译语言映射基于: https://docs.azure.cn/zh-cn/ai-services/translator/text-translation/reference/v3/translate
# 语言代码https://api.translator.azure.cn/languages?api-version=3.0&scope=translation
AZURE_LANG_MAP = {
# 'zh_CN': {
# 'name': '简体中文',
# 'code': 'zh-Hans'
# },
# 'zh_TW': {
# 'name': '繁体中文',
# 'code': 'zh-Hant',
# },
# 'zh_HK': {
# 'name': '粤语(繁体)',
# 'code': 'yue',
# },
# 'en_US': {
# 'name': '英文',
# 'code': 'en',
# },
# 'fr_FR': {
# 'name': '法语',
# 'code': 'fr',
# },
# 'ru_RU': {
# 'name': '俄语',
# 'code': 'ru',
# },
# 'de_DE': {
# 'name': '德语',
# 'code': 'de',
# },
# 'ja_JP': {
# 'name': '日语',
# 'code': 'ja',
# },
# 'ko_KR': {
# 'name': '韩语',
# 'code': 'ko',
# },
# 'it_IT': {
# 'name': '意大利语',
# 'code': 'it',
# },
# 'pt_PT': {
# 'name': '葡萄牙语',
# 'code': 'pt-PT',
# },
# 'es_ES': {
# 'name': '西班牙语',
# 'code': 'es',
# },
# 'ar_SA': {
# 'name': '阿拉伯语',
# 'code': 'ar',
# },
# 'vi_VN': {
# 'name': '越南语',
# 'code': 'vi',
# },
# 'ms_MY': {
# 'name': '马来语',
# 'code': 'ms',
# },
# 'nl_NL': {
# 'name': '荷兰语',
# 'code': 'nl',
# },
# 'ro_RO': {
# 'name': '罗马尼亚语',
# 'code': 'ro',
# },
# 'lt_LT': {
# 'name': '立陶宛语',
# 'code': 'lt',
# },
# 'sv_SE': {
# 'name': '瑞典语',
# 'code': 'sv',
# },
# 'et_EE': {
# 'name': '爱沙尼亚语',
# 'code': 'et',
# },
# 'pl_PL': {
# 'name': '波兰语',
# 'code': 'pl',
# },
# 'sk_SK': {
# 'name': '斯洛伐克语',
# 'code': 'sk',
# },
# 'cs_CZ': {
# 'name': '捷克语',
# 'code': 'cs',
# },
# 'el_GR': {
# 'name': '希腊语',
# 'code': 'el',
# },
# 'he_IL': {
# 'name': '希伯来语',
# 'code': 'he',
# },
# 'tr_TR': {
# 'name': '土耳其语',
# 'code': 'tr',
# },
# 'hu_HU': {
# 'name': '匈牙利语',
# 'code': 'hu',
# },
# 'bg_BG': {
# 'name': '保加利亚语',
# 'code': 'bg',
# },
# 'kk_KZ': {
# 'name': '哈萨克语',
# 'code': 'kk',
# },
# 'bn_BD': {
# 'name': '孟加拉语',
# 'code': 'bn',
# },
# 'hr_HR': {
# 'name': '克罗地亚语',
# 'code': 'hr',
# },
# 'th_TH': {
# 'name': '泰语',
# 'code': 'th',
# },
# 'id_ID': {
# 'name': '印尼语',
# 'code': 'id',
# },
# 'fi_FI': {
# 'name': '芬兰语',
# 'code': 'fi',
# },
# 'da_DK': {
# 'name': '丹麦语',
# 'code': 'da',
# },
# 'uk_UA': {
# 'name': '乌克兰语',
# 'code': 'uk',
# },
# 'sr_RS': {
# 'name': '塞尔维亚语(西里尔)',
# 'code': 'sr-Cyrl',
# },
# 'hi_IN': {
# 'name': '印地语',
# 'code': 'hi',
# },
# 'ur_PK': {
# 'name': '乌尔都语',
# 'code': 'ur',
# },
# 'hy_AM': {
# 'name': '亚美尼亚语',
# 'code': 'hy',
# },
# 'ka_GE': {
# 'name': '格鲁吉亚语',
# 'code': 'ka',
# },
'pt_BR': {
'name': '葡萄牙语 (巴西)',
'code': 'pt',
},
}
# =============================== 以下为固定代码,非必要请勿修改 ===============================
# Azure配置
AZURE_CONFIG = {
'api_url': 'https://api.cognitive.microsofttranslator.com',
'subscription_key': '5UGFXbyyyIlwtvFbl5HUeWeHffW9aKLNIiZlqWsRZuLaFSmXfxfzJQQJ99BGAC3pKaRXJ3w3AAAbACOGpL8p', # 替换为您的订阅密钥
'region': 'eastasia', # 替换为您的区域,例如 'eastasia'
}
def main():
en_path = path + SOURCE_LANG + ".json"
# 判断文件是否存在
if not os.path.exists(en_path):
print('文件不存在:', en_path)
sys.exit(1)
# 读取文件内容
en_us_content = read_file(en_path)
# 把json转数组
en_us_data = json.loads(en_us_content)
# 遍历AZURE_LANG_MAP
for key in AZURE_LANG_MAP:
# 过滤掉不翻译的语言
if key in FILTER_LANG:
continue
lang_path = path + key + ".json"
# 验证文件是否存在,如果不存在即创建
if not os.path.exists(lang_path):
create_file(lang_path)
data_content = read_file(lang_path)
if data_content.strip(): # Check if the file is not empty
datas = json.loads(data_content)
else:
datas = {}
total = len(en_us_data) # 总数
current = 0 # 当前数
for en_us_key in en_us_data:
current += 1
# 检查key是否包含中文
has_chinese = bool(re.search(r'[\u4e00-\u9fff]', en_us_key))
text_to_translate = en_us_key if has_chinese else en_us_data[en_us_key]
print('语言:%s 正在翻译处理第%d/%d批数据 是否中文:%s' % (key, current, total, has_chinese))
# 过滤已存在的key
if en_us_key in datas:
continue
# 异常处理
try:
if has_chinese:
# 从中文翻译到目标语言
datas[en_us_key] = azure_translation('zh-Hans', AZURE_LANG_MAP[key]['code'], text_to_translate)
else:
# 从英文翻译到目标语言
datas[en_us_key] = azure_translation(AZURE_LANG_MAP[SOURCE_LANG]['code'], AZURE_LANG_MAP[key]['code'], text_to_translate)
# 延迟1秒避免API限制
#time.sleep(1)
except Exception as e:
print('翻译异常:', e.args, 'key:', en_us_key, 'content:', en_us_data[en_us_key])
continue
# 写入文件
with open(lang_path, 'w', encoding='utf-8') as file:
json.dump(datas, file, ensure_ascii=False, indent=4)
def azure_translation(source_language, target_language, text):
"""
使用Azure翻译API进行文本翻译
Args:
source_language: 源语言代码
target_language: 目标语言代码
text: 要翻译的文本
Returns:
翻译后的文本
"""
# 构建API端点
endpoint = f"{AZURE_CONFIG['api_url']}/translate"
# 设置参数
params = {
'api-version': '3.0',
'from': source_language,
'to': target_language
}
# 设置请求头
headers = {
'Ocp-Apim-Subscription-Key': AZURE_CONFIG['subscription_key'],
'Ocp-Apim-Subscription-Region': AZURE_CONFIG['region'],
'Content-type': 'application/json',
'X-ClientTraceId': str(datetime.datetime.now().timestamp())
}
# 构建请求体
body = [{'text': text}]
try:
# 发送请求
response = requests.post(endpoint, params=params, headers=headers, json=body)
# 检查响应状态
if response.status_code != 200:
raise Exception(f"Azure翻译API请求失败状态码{response.status_code},响应:{response.text}")
# 解析响应
result = response.json()
# 提取翻译结果
if result and len(result) > 0 and 'translations' in result[0]:
return result[0]['translations'][0]['text']
else:
raise Exception(f"Azure翻译API响应格式异常{result}")
except requests.exceptions.RequestException as e:
raise Exception(f"Azure翻译API网络请求异常{str(e)}")
except json.JSONDecodeError as e:
raise Exception(f"Azure翻译API响应JSON解析异常{str(e)}")
# 创建文件
def create_file(file_path):
with open(file_path, 'w') as file:
pass
# 读取文件内容
def read_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()
return content
if __name__ == "__main__":
# 检查配置
if AZURE_CONFIG['subscription_key'] == 'YOUR_SUBSCRIPTION_KEY':
print("错误请先在脚本中配置您的Azure订阅密钥")
print("请修改AZURE_CONFIG中的subscription_key和region")
sys.exit(1)
main()

View File

@ -1,5 +1,5 @@
//<cn> //<cn>
import 'package:umeng_common_sdk/umeng_common_sdk.dart'; // import 'package:umeng_common_sdk/umeng_common_sdk.dart';
import '../../flavors.dart'; import '../../flavors.dart';
class UmengHelper { class UmengHelper {
@ -15,27 +15,24 @@ class UmengHelper {
return _instance!; return _instance!;
} }
Future<void> initApp() async { Future<void> initApp() async {}
}
Future<void> initSdk() async { Future<void> initSdk() async {
UmengCommonSdk.initCommon( // UmengCommonSdk.initCommon(
F.umengKey.androidKey, F.umengKey.iosKey, F.umengKey.channel); // F.umengKey.androidKey, F.umengKey.iosKey, F.umengKey.channel);
UmengCommonSdk.setPageCollectionModeManual(); // UmengCommonSdk.setPageCollectionModeManual();
} }
Future<void> login(String userId) async { Future<void> login(String userId) async {
UmengCommonSdk.onProfileSignIn(userId); // UmengCommonSdk.onProfileSignIn(userId);
} }
Future<void> trackEvent( Future<void> trackEvent(String eventName, Map<String, Object> parameters) async {
String eventName, Map<String, Object> parameters) async { // UmengCommonSdk.onEvent(eventName, parameters);
UmengCommonSdk.onEvent(eventName, parameters);
} }
Future<void> logout() async { Future<void> logout() async {
UmengCommonSdk.onProfileSignOff(); // UmengCommonSdk.onProfileSignOff();
} }
} }
//</cn> //</cn>

View File

@ -144,7 +144,7 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver, BaseWidget {
break; break;
case AppLifecycleState.paused: case AppLifecycleState.paused:
// AppLog.log('App--->进入后台'); // AppLog.log('App--->进入后台');
BlueManage().disconnect(); BlueManage.instance.disconnect();
break; break;
case AppLifecycleState.resumed: case AppLifecycleState.resumed:
// AppLog.log('App--->进入前台'); // AppLog.log('App--->进入前台');

View File

@ -18,6 +18,7 @@ import 'package:star_lock/main/lockDetail/iris/addIris/addIris_page.dart';
import 'package:star_lock/main/lockDetail/iris/addIrisType/addIrisTypeManage/addIrisTypeManage_page.dart'; import 'package:star_lock/main/lockDetail/iris/addIrisType/addIrisTypeManage/addIrisTypeManage_page.dart';
import 'package:star_lock/main/lockDetail/iris/irisList/irisList_page.dart'; import 'package:star_lock/main/lockDetail/iris/irisList/irisList_page.dart';
import 'package:star_lock/main/lockDetail/lockDetail/lockDetail_main_page.dart'; import 'package:star_lock/main/lockDetail/lockDetail/lockDetail_main_page.dart';
import 'package:star_lock/main/lockDetail/lockSet/aiAssistant/ai_assistant_page.dart';
import 'package:star_lock/main/lockDetail/lockSet/catEyeSet/catEyeCustomMode/catEyeCustomMode_page.dart'; import 'package:star_lock/main/lockDetail/lockSet/catEyeSet/catEyeCustomMode/catEyeCustomMode_page.dart';
import 'package:star_lock/main/lockDetail/lockSet/catEyeSet/catEyeSet/catEyeSet_page.dart'; import 'package:star_lock/main/lockDetail/lockSet/catEyeSet/catEyeSet/catEyeSet_page.dart';
import 'package:star_lock/main/lockDetail/lockSet/catEyeSet/videoSlot/videoSlot_page.dart'; import 'package:star_lock/main/lockDetail/lockSet/catEyeSet/videoSlot/videoSlot_page.dart';
@ -532,6 +533,7 @@ abstract class Routers {
static const String permissionGuidancePage = static const String permissionGuidancePage =
'/permissionGuidancePage'; // '/permissionGuidancePage'; //
static const String lockVoiceSettingPage = '/lockVoiceSetting'; // static const String lockVoiceSettingPage = '/lockVoiceSetting'; //
static const String aiAssistant = '/aiAssistant';
} }
abstract class AppRouters { abstract class AppRouters {
@ -1224,6 +1226,9 @@ abstract class AppRouters {
GetPage<dynamic>( GetPage<dynamic>(
name: Routers.thirdPartyPlatformPage, name: Routers.thirdPartyPlatformPage,
page: () => ThirdPartyPlatformPage()), page: () => ThirdPartyPlatformPage()),
GetPage<dynamic>(
name: Routers.aiAssistant,
page: () => AiAssistantPage()),
// //
// GetPage<dynamic>(name: Routers.h264View, page: () => H264WebView()), // webview播放页面 // GetPage<dynamic>(name: Routers.h264View, page: () => H264WebView()), // webview播放页面
]; ];

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 {
@ -47,7 +46,7 @@ class BlueManage {
StreamSubscription<BluetoothConnectionState>? _connectionStateSubscription; StreamSubscription<BluetoothConnectionState>? _connectionStateSubscription;
StreamSubscription<int>? _mtuSubscription; StreamSubscription<int>? _mtuSubscription;
int? _mtuSize = 20; int? _mtuSize = 30;
// //
String connectDeviceName = ''; String connectDeviceName = '';
@ -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;
@ -85,6 +83,12 @@ class BlueManage {
return _manager; return _manager;
} }
// 访
static BlueManage get instance {
_manager ??= BlueManage._init();
return _manager!;
}
BlueManage? get manager => shareManager(); BlueManage? get manager => shareManager();
void _initBlue() { void _initBlue() {
@ -94,15 +98,18 @@ class BlueManage {
} }
void _initGetMtuSubscription() { void _initGetMtuSubscription() {
_mtuSubscription ??= bluetoothConnectDevice!.mtu.listen((int value) { //
_mtuSubscription?.cancel();
_mtuSubscription = null;
_mtuSubscription = bluetoothConnectDevice!.mtu.listen((int value) {
_mtuSize = value - 3; _mtuSize = value - 3;
AppLog.log('_mtuSizeValue:$value mtuSize:$_mtuSize'); AppLog.log('设备MTU变化 - 原始值:$value 计算后MTU:$_mtuSize 设备:${bluetoothConnectDevice?.remoteId.str}');
}); });
} }
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;
}); });
@ -112,18 +119,14 @@ class BlueManage {
_connectionStateSubscription?.cancel(); _connectionStateSubscription?.cancel();
_connectionStateSubscription = null; _connectionStateSubscription = null;
_connectionStateSubscription = bluetoothConnectDevice!.connectionState _connectionStateSubscription = bluetoothConnectDevice!.connectionState.listen((BluetoothConnectionState state) async {
.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 {
@ -148,39 +151,27 @@ 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) {
// AppLog.log('startScanSingle 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState'); // AppLog.log('startScanSingle 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
if (_adapterState == BluetoothAdapterState.on) { if (_adapterState == BluetoothAdapterState.on) {
try { try {
BuglyTool.uploadException( BuglyTool.uploadException(message: '开始指定设备名称的扫描蓝牙设备', detail: '调用方法是:startScanSingle 指定设备名称是:$deviceName', upload: false);
message: '开始指定设备名称的扫描蓝牙设备',
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(
continuousDivisor: divisor, continuousDivisor: divisor, continuousUpdates: true, withKeywords: <String>[deviceName], timeout: Duration(seconds: timeout));
continuousUpdates: true,
withKeywords: <String>[deviceName],
timeout: Duration(seconds: timeout));
final Completer<dynamic> completer = Completer<dynamic>(); final Completer<dynamic> completer = Completer<dynamic>();
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
final bool isExit = results.any((ScanResult element) => .any((ScanResult element) => (element.device.platformName == deviceName) || (element.advertisementData.advName == deviceName));
(element.device.platformName == deviceName) || final int milliseconds = DateTime.now().millisecondsSinceEpoch - start.millisecondsSinceEpoch;
(element.advertisementData.advName == deviceName)); AppLog.log('扫描到的设备数:${results.length} 是否查找到 $isExit 以查找$milliseconds毫秒');
final int milliseconds = DateTime.now().millisecondsSinceEpoch -
start.millisecondsSinceEpoch;
AppLog.log(
'扫描到的设备数:${results.length} 是否查找到 $isExit 以查找$milliseconds毫秒');
BuglyTool.uploadException( BuglyTool.uploadException(
message: '指定设备名称的扫描蓝牙设备 监听扫描结果', message: '指定设备名称的扫描蓝牙设备 监听扫描结果',
detail: detail: 'startScanSingle$deviceName 监听扫描结果 是否查找到 $isExit 以查找$milliseconds毫秒 扫描到的设备数:${results.length} results:$results',
'startScanSingle$deviceName 监听扫描结果 是否查找到 $isExit 以查找$milliseconds毫秒 扫描到的设备数:${results.length} results:$results',
upload: false); upload: false);
if (isExit) { if (isExit) {
for (final ScanResult scanResult in results) { for (final ScanResult scanResult in results) {
@ -192,20 +183,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;
@ -214,8 +200,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);
} }
} }
@ -223,10 +208,7 @@ class BlueManage {
completer.complete(); completer.complete();
} }
}, onError: (e) { }, onError: (e) {
BuglyTool.uploadException( BuglyTool.uploadException(message: '指定设备名称的扫描蓝牙设备 监听扫描结果失败', detail: '打印失败问题 e${e.toString()}', upload: false);
message: '指定设备名称的扫描蓝牙设备 监听扫描结果失败',
detail: '打印失败问题 e${e.toString()}',
upload: false);
AppLog.log('扫描失败:$e'); AppLog.log('扫描失败:$e');
}); });
FlutterBluePlus.cancelWhenScanComplete(subscription); FlutterBluePlus.cancelWhenScanComplete(subscription);
@ -234,10 +216,7 @@ class BlueManage {
scanDevicesCallBack(scanDevices); scanDevicesCallBack(scanDevices);
subscription.cancel(); subscription.cancel();
} catch (e) { } catch (e) {
BuglyTool.uploadException( BuglyTool.uploadException(message: '指定设备名称的扫描蓝牙设备 内部逻辑整形失败', detail: 'tartScanSingle内部逻辑整形失败 e:${e.toString()}', upload: false);
message: '指定设备名称的扫描蓝牙设备 内部逻辑整形失败',
detail: 'tartScanSingle内部逻辑整形失败 e:${e.toString()}',
upload: false);
AppLog.log('扫描失败'); AppLog.log('扫描失败');
} }
} else { } else {
@ -254,17 +233,14 @@ class BlueManage {
} }
/// ///
Future<void> startScan(int timeout, DeviceType deviceType, Future<void> startScan(int timeout, DeviceType deviceType, ScanDevicesCallBack scanDevicesCallBack, {List<Guid>? idList}) async {
ScanDevicesCallBack scanDevicesCallBack,
{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));
final StreamSubscription<List<ScanResult>> subscription = final StreamSubscription<List<ScanResult>> subscription = FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
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) {
@ -275,21 +251,16 @@ class BlueManage {
} }
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;
@ -323,10 +294,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) {
@ -357,11 +326,30 @@ 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
} else {
// 0~255
int statusValue = int.parse(pairStatus, radix: 16);
// byte01
int byte0 = (statusValue >> 0) & 0x01; //
// byte12
int byte1 = (statusValue >> 1) & 0x01; //
//
bool isPaired = (byte0 == 1);
//
bool hasNewEvent = (byte1 == 1);
//
if (!isPaired) {
return true; // true
} else {
return false; // false
}
} }
// 01trueuuid // 01trueuuid
} }
@ -377,8 +365,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
@ -397,8 +384,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');
@ -407,26 +396,26 @@ 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: '点击按钮 蓝牙已经连接 下一步扫描连接蓝牙',
detail: detail: 'blueSendData 直接回调状态 蓝牙连接状态bluetoothConnectionState$bluetoothConnectionState deviceName:$deviceName',
'blueSendData 直接回调状态 蓝牙连接状态bluetoothConnectionState$bluetoothConnectionState deviceName:$deviceName',
upload: false); upload: false);
stateCallBack(bluetoothConnectionState!); stateCallBack(bluetoothConnectionState!);
} }
} else { } else {
BuglyTool.uploadException( BuglyTool.uploadException(
message: '点击按钮 蓝牙未打开', message: '点击按钮 蓝牙未打开', detail: 'blueSendData 蓝牙未打开--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName', upload: false);
detail:
'blueSendData 蓝牙未打开--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName',
upload: false);
try { try {
stateCallBack(BluetoothConnectionState.disconnected); stateCallBack(BluetoothConnectionState.disconnected);
openBlue(); openBlue();
@ -434,16 +423,12 @@ 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: '点击按钮 蓝牙状态不可用', detail: 'blueSendData 蓝牙状态不可用--isAvailable:$isAvailable', upload: false);
message: '点击按钮 蓝牙状态不可用',
detail: 'blueSendData 蓝牙状态不可用--isAvailable:$isAvailable',
upload: false);
stateCallBack(BluetoothConnectionState.disconnected); stateCallBack(BluetoothConnectionState.disconnected);
AppLog.log('开始扫描 蓝牙不可用,不能进行蓝牙操作'); AppLog.log('开始扫描 蓝牙不可用,不能进行蓝牙操作');
} }
@ -451,25 +436,19 @@ class BlueManage {
} }
/// ///
Future<void> _connect( Future<void> _connect(String deviceName, ConnectStateCallBack connectStateCallBack, {bool isAddEquipment = false}) async {
String deviceName, ConnectStateCallBack connectStateCallBack,
{bool isAddEquipment = false}) async {
connectDeviceName = deviceName; connectDeviceName = deviceName;
// //
final List<ScanResult> devicesList = scanDevices; final List<ScanResult> devicesList = scanDevices;
// 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',
@ -481,22 +460,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) {
@ -505,8 +479,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);
}); });
} }
// //
@ -523,16 +496,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(
@ -541,16 +511,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
element.device.platformName == connectDeviceName || .any((ScanResult element) => element.device.platformName == connectDeviceName || element.advertisementData.advName == connectDeviceName);
element.advertisementData.advName == connectDeviceName);
return isExistDevice; return isExistDevice;
} }
@ -561,154 +529,66 @@ class BlueManage {
bool isAddEquipment = false, // bool isAddEquipment = false, //
bool isReconnect = true, // bool isReconnect = true, //
}) async { }) async {
// final int knownDeviceIndex =
// AppLog.log("devicesList:$devicesList"); devicesList.indexWhere((ScanResult d) => (d.device.platformName == deviceName) || (d.advertisementData.advName == deviceName));
final int knownDeviceIndex = devicesList.indexWhere((ScanResult d) =>
(d.device.platformName == 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];
// AppLog.log('bluetoothConnectDevice: $bluetoothConnectDevice scanResult:$scanResult');
_initGetMtuSubscription(); _initGetMtuSubscription();
_initListenConnectionState(); _initListenConnectionState();
} }
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;
} }
AppLog.log('调用了停止扫描的方法');
await stopScan();
if (scanResult.advertisementData.serviceUuids[0].toString().length >= 5 &&
(scanResult.advertisementData.serviceUuids[0].toString()[5] == '0') &&
isAddEquipment == false) {
//
if (isReconnect == true) {
AppLog.log('该锁已被重置, 重新发送扫描命令');
BuglyTool.uploadException(
message: '该锁已被重置, 重新发送扫描命令startScanSingle 上传记录当前方法是_connectDevice',
detail:
'添加这个判断是因为有些苹果设备或者安卓等性能比较好的设备时,添加完锁之后,锁板未改变为已添加状态之前,就进行了蓝牙连接,导致添加完锁就失败,这里进行了判断,如果第一次连接失败,就清除缓存重新扫描连接 该锁已被重置, 重新发送扫描命令 serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
upload: false);
scanDevices.clear();
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
_connectDevice(scanDevices, deviceName, connectStateCallBack,
isAddEquipment: isAddEquipment, isReconnect: false);
});
} else {
connectStateCallBack(BluetoothConnectionState.disconnected);
if (!F.isSKY) {
EasyLoading.showToast('该锁已被重置'.tr, duration: 2000.milliseconds);
}
scanDevices.clear();
BuglyTool.uploadException(
message: '提示该锁已被重置, 回调断开连接, 清除缓存上传记录当前方法是_connectDevice',
detail:
'isReconnect:$isReconnect serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
upload: false);
}
return;
}
if (scanResult.advertisementData.serviceUuids[0].toString().length >= 30 &&
(scanResult.advertisementData.serviceUuids[0].toString()[31] == '0') &&
isAddEquipment == false) {
//
if (isReconnect == true) {
AppLog.log('该锁已被重置, 重新发送扫描命令');
BuglyTool.uploadException(
message: '该锁已被重置, 重新发送扫描命令startScanSingle 上传记录当前方法是_connectDevice',
detail:
'添加这个判断是因为有些苹果设备或者安卓等性能比较好的设备时,添加完锁之后,锁板未改变为已添加状态之前,就进行了蓝牙连接,导致添加完锁就失败,这里进行了判断,如果第一次连接失败,就清除缓存重新扫描连接 该锁已被重置, 重新发送扫描命令 serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
upload: false);
scanDevices.clear();
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
_connectDevice(scanDevices, deviceName, connectStateCallBack,
isAddEquipment: isAddEquipment, isReconnect: false);
});
} else {
connectStateCallBack(BluetoothConnectionState.disconnected);
if (!F.isSKY) {
EasyLoading.showToast('该锁已被重置'.tr, duration: 2000.milliseconds);
}
scanDevices.clear();
BuglyTool.uploadException(
message: '提示该锁已被重置, 回调断开连接, 清除缓存上传记录当前方法是_connectDevice',
detail:
'isReconnect:$isReconnect serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
upload: false);
}
return;
}
BuglyTool.uploadException(
message: '从devicesList里面查到了设备 下一步连接设备 上传记录当前方法是_connectDevice',
detail:
'devicesList:$devicesList scanResult:${scanResult.toString()} bluetoothConnectDevice${bluetoothConnectDevice.toString()} connectDeviceMacAddress$connectDeviceMacAddress',
upload: false);
// //
await bluetoothDeviceConnect(bluetoothConnectDevice!, connectStateCallBack); await bluetoothDeviceConnect(bluetoothConnectDevice!, connectStateCallBack);
} }
// //
Future<void> doNotSearchBLE( Future<void> doNotSearchBLE(String masAdds, ConnectStateCallBack connectStateCallBack, {bool isAddEquipment = false}) async {
String masAdds, ConnectStateCallBack connectStateCallBack,
{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();
BuglyTool.uploadException( BuglyTool.uploadException(
message: '直接给蓝牙设备写入 上传记录当前方法是doNotSearchBLE', message: '直接给蓝牙设备写入 上传记录当前方法是doNotSearchBLE', detail: '直接给蓝牙设备写入 通过fromId方法创建一个BluetoothDevice masAdds$masAdds', upload: false);
detail: '直接给蓝牙设备写入 通过fromId方法创建一个BluetoothDevice masAdds$masAdds',
upload: false);
} 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,
mtu: 512,
);
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');
@ -723,8 +603,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);
@ -733,22 +612,22 @@ 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!);
if (Platform.isAndroid) {
await bluetoothConnectDevice.requestMtu(512);
}
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(
@ -770,22 +649,16 @@ 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: '发现服务时报错原因e$e bluetoothDeviceConnect:${bluetoothConnectDevice.toString()}', upload: false);
detail:
'发现服务时报错原因e$e bluetoothDeviceConnect:${bluetoothConnectDevice.toString()}',
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;
@ -833,10 +706,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;
@ -845,20 +715,30 @@ 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 {
_initGetMtuSubscription();
// MTU还是默认值
if ((_mtuSize == 23 || _mtuSize == 20) && bluetoothConnectDevice != null) {
try {
if (Platform.isAndroid) {
await bluetoothConnectDevice!.requestMtu(512);
}
} catch (e) {
AppLog.log('重新请求MTU失败: $e');
}
}
// //
int retryCount = 0; int retryCount = 0;
const int maxRetries = 3; const int maxRetries = 3;
const int retryDelayMs = 500; const int retryDelayMs = 500;
final List<int> valueList = value; final List<int> valueList = value;
AppLog.log('发送数据时当前的mtuSize是:${_mtuSize}');
final List subData = splitList(valueList, _mtuSize!); final List subData = splitList(valueList, _mtuSize!);
for (int i = 0; i < subData.length; i++) { for (int i = 0; i < subData.length; i++) {
@ -869,27 +749,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 {
// //
@ -900,8 +775,7 @@ class BlueManage {
} }
if (!packetSent) { if (!packetSent) {
throw Exception( throw Exception('蓝牙写入失败,数据包 ${i + 1}/${subData.length} 已达到最大重试次数');
'蓝牙写入失败,数据包 ${i + 1}/${subData.length} 已达到最大重试次数');
} }
} }
@ -933,15 +807,19 @@ class BlueManage {
Future<void> disconnect() async { Future<void> disconnect() async {
try { try {
connectDeviceMacAddress = ''; connectDeviceMacAddress = '';
// MTU监听
_mtuSubscription?.cancel();
_mtuSubscription = null;
_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;
} }
} }
@ -954,10 +832,29 @@ class BlueManage {
} }
} }
// MTU信息
String getMtuDebugInfo() {
return 'MTU Debug Info:\n'
'- Current MTU Size: $_mtuSize\n'
'- Connected Device: ${bluetoothConnectDevice?.remoteId.str ?? "None"}\n'
'- Device Name: $connectDeviceName\n'
'- Connection State: $bluetoothConnectionState\n'
'- MTU Subscription Active: ${_mtuSubscription != null}';
}
void disposed() { void disposed() {
_sendStreamSubscription?.cancel(); _sendStreamSubscription?.cancel();
_mtuSubscription!.cancel(); _mtuSubscription?.cancel();
_adapterStateStateSubscription!.cancel(); _adapterStateStateSubscription?.cancel();
_connectionStateSubscription!.cancel(); _connectionStateSubscription?.cancel();
//
_mtuSize = 20;
connectDeviceName = '';
connectDeviceMacAddress = '';
bluetoothConnectDevice = null;
scanDevices.clear();
allData.clear();
lastTimeData.clear();
} }
} }

View File

@ -0,0 +1,74 @@
import 'dart:convert';
import '../io_tool/io_tool.dart';
import '../sm4Encipher/sm4.dart';
import '../io_reply.dart';
import '../io_sender.dart';
import '../io_type.dart';
import 'package:crypto/crypto.dart' as crypto;
///
class SenderReadRegisterKeyCommand extends SenderProtocol {
SenderReadRegisterKeyCommand({
this.lockID,
this.token,
this.needAuthor,
this.publicKey,
this.privateKey,
}) : super(CommandType.readRegisterKey);
String? lockID;
List<int>? token;
int? needAuthor;
List<int>? publicKey;
List<int>? privateKey;
@override
String toString() {
return 'SenderReadRegisterKeyCommand{ lockID: $lockID, token: $token, '
'needAuthor: $needAuthor, publicKey: $publicKey, '
'privateKey: $privateKey}';
}
@override
List<int> messageDetail() {
List<int> data = <int>[];
List<int> ebcData = <int>[];
//
final int type = commandType!.typeValue;
final double typeDouble = type / 256;
final int type1 = typeDouble.toInt();
final int type2 = type % 256;
data.add(type1);
data.add(type2);
// id 40
final int lockIDLength = utf8.encode(lockID!).length;
data.addAll(utf8.encode(lockID!));
data = getFixedLengthList(data, 40 - lockIDLength);
if ((data.length % 16) != 0) {
final int add = 16 - data.length % 16;
for (int i = 0; i < add; i++) {
data.add(0);
}
}
printLog(data);
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
return ebcData;
}
}
class SenderReadRegisterKeyCommandReply extends Reply {
SenderReadRegisterKeyCommandReply.parseData(CommandType commandType, List<int> dataDetail)
: super.parseData(commandType, dataDetail) {
data = dataDetail;
final int status = data[6];
errorWithStstus(status);
}
}

View File

@ -0,0 +1,54 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:crypto/crypto.dart' as crypto;
import '../io_reply.dart';
import '../io_sender.dart';
import '../io_tool/io_tool.dart';
import '../io_type.dart';
import '../sm4Encipher/sm4.dart';
//oat升级
class ReadLockCurrentVoicePacket extends SenderProtocol {
ReadLockCurrentVoicePacket({
this.lockID,
}) : super(CommandType.readLockCurrentVoicePacket);
String? lockID;
@override
String toString() {
return 'ReadLockCurrentVoicePacket{lockID: $lockID}';
}
@override
List<int> messageDetail() {
List<int> data = <int>[];
//
final int type = commandType!.typeValue;
final double typeDouble = type / 256;
final int type1 = typeDouble.toInt();
final int type2 = type % 256;
data.add(type1);
data.add(type2);
// id 40
final int lockIDLength = utf8.encode(lockID!).length;
data.addAll(utf8.encode(lockID!));
data = getFixedLengthList(data, 40 - lockIDLength);
printLog(data);
return data;
}
}
class ReadLockCurrentVoicePacketReply extends Reply {
ReadLockCurrentVoicePacketReply.parseData(
CommandType commandType, List<int> dataDetail)
: super.parseData(commandType, dataDetail) {
data = dataDetail;
status = data[2];
errorWithStstus(status);
}
}

View File

@ -0,0 +1,106 @@
import 'dart:convert';
import '../io_tool/io_tool.dart';
import '../sm4Encipher/sm4.dart';
import '../io_reply.dart';
import '../io_sender.dart';
import '../io_type.dart';
import 'package:crypto/crypto.dart' as crypto;
///
class SenderAuthorizationCodeCommand extends SenderProtocol {
SenderAuthorizationCodeCommand({
this.lockID,
this.uuid,
this.key,
this.mac,
this.platform,
this.utcTimeStamp,
this.token,
this.needAuthor,
this.publicKey,
this.privateKey,
}) : super(CommandType.sendAuthorizationCode);
String? lockID;
String? uuid;
String? key;
String? mac;
int? platform; //01
int? utcTimeStamp;
List<int>? token;
int? needAuthor;
List<int>? publicKey;
List<int>? privateKey;
@override
String toString() {
return 'SenderAuthorizationCodeCommand{ lockID: $lockID, token: $token, '
'needAuthor: $needAuthor, publicKey: $publicKey, '
'privateKey: $privateKey}';
}
@override
List<int> messageDetail() {
List<int> data = <int>[];
List<int> ebcData = <int>[];
//
final int type = commandType!.typeValue;
final double typeDouble = type / 256;
final int type1 = typeDouble.toInt();
final int type2 = type % 256;
data.add(type1);
data.add(type2);
// id 40
final int lockIDLength = utf8.encode(lockID!).length;
data.addAll(utf8.encode(lockID!));
data = getFixedLengthList(data, 40 - lockIDLength);
// uuid 40
final int uuidLength = utf8.encode(uuid!).length;
data.addAll(utf8.encode(uuid!));
data = getFixedLengthList(data, 40 - uuidLength);
// key 40
final int keyLength = utf8.encode(key!).length;
data.addAll(utf8.encode(key!));
data = getFixedLengthList(data, 40 - keyLength);
// mac 40
final int macLength = utf8.encode(mac!).length;
data.addAll(utf8.encode(mac!));
data = getFixedLengthList(data, 40 - macLength);
data.add(platform!);
data.add((utcTimeStamp! & 0xff000000) >> 24);
data.add((utcTimeStamp! & 0xff0000) >> 16);
data.add((utcTimeStamp! & 0xff00) >> 8);
data.add(utcTimeStamp! & 0xff);
if ((data.length % 16) != 0) {
final int add = 16 - data.length % 16;
for (int i = 0; i < add; i++) {
data.add(0);
}
}
printLog(data);
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
return ebcData;
}
}
class SenderAuthorizationCodeCommandReply extends Reply {
SenderAuthorizationCodeCommandReply.parseData(CommandType commandType, List<int> dataDetail)
: super.parseData(commandType, dataDetail) {
data = dataDetail;
final int status = data[6];
errorWithStstus(status);
}
}

View File

@ -0,0 +1,61 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:crypto/crypto.dart' as crypto;
import '../io_reply.dart';
import '../io_sender.dart';
import '../io_tool/io_tool.dart';
import '../io_type.dart';
import '../sm4Encipher/sm4.dart';
//oat升级
class SetVoicePackageFinalResult extends SenderProtocol {
SetVoicePackageFinalResult({
this.lockID,
this.languageCode,
}) : super(CommandType.setLockCurrentVoicePacket);
String? lockID;
String? languageCode;
@override
String toString() {
return 'SetVoicePackageFinalResult{lockID: $lockID, languageCode: $languageCode}';
}
@override
List<int> messageDetail() {
List<int> data = <int>[];
//
final int type = commandType!.typeValue;
final double typeDouble = type / 256;
final int type1 = typeDouble.toInt();
final int type2 = type % 256;
data.add(type1);
data.add(type2);
// id 40
final int lockIDLength = utf8.encode(lockID!).length;
data.addAll(utf8.encode(lockID!));
data = getFixedLengthList(data, 40 - lockIDLength);
//languageCode 20
final int languageCodeLength = utf8.encode(languageCode!).length;
data.addAll(utf8.encode(languageCode!));
data = getFixedLengthList(data, 20 - languageCodeLength);
printLog(data);
return data;
}
}
class SetVoicePackageFinalResultReply extends Reply {
SetVoicePackageFinalResultReply.parseData(
CommandType commandType, List<int> dataDetail)
: super.parseData(commandType, dataDetail) {
data = dataDetail;
status = data[2];
errorWithStstus(status);
}
}

View File

@ -27,6 +27,11 @@ class EventSendModel {
Uuid? serviceId; Uuid? serviceId;
Uuid? characteristicId; Uuid? characteristicId;
bool? allowLongWrite = false; bool? allowLongWrite = false;
@override
String toString() {
return 'EventSendModel{data: $data, topic: $topic, sendChannel: $sendChannel, deviceId: $deviceId, serviceId: $serviceId, characteristicId: $characteristicId, allowLongWrite: $allowLongWrite}';
}
} }
/// ///

View File

@ -9,10 +9,10 @@ List<String> getDeviceType(DeviceType deviceType) {
List<String> t = ['758824']; List<String> t = ['758824'];
switch (deviceType) { switch (deviceType) {
case DeviceType.blue: case DeviceType.blue:
t = ['758824', '75', '768824', '76','24']; t = ['758824', '75', '768824', '76', '24'];
break; break;
case DeviceType.gateway: case DeviceType.gateway:
t = ['758825','25']; t = ['758825', '25'];
break; break;
} }
return t; return t;
@ -44,13 +44,17 @@ enum CommandType {
startVoicePackageConfigure, // 0x30A1 startVoicePackageConfigure, // 0x30A1
voicePackageConfigureProcess, // 0x30A2 voicePackageConfigureProcess, // 0x30A2
voicePackageConfigureConfirmation, // 0x30A3 voicePackageConfigureConfirmation, // 0x30A3
getDeviceModel, // 0x30A4 readLockCurrentVoicePacket, // 0x30A4
setLockCurrentVoicePacket, // 0x30A5
getDeviceModel, // 0x30A4
gatewayConfiguringWifi, // 0x30F4 gatewayConfiguringWifi, // 0x30F4
gatewayConfiguringWifiResult, // 0x30F5 gatewayConfiguringWifiResult, // 0x30F5
gatewayGetWifiList, //wifi列表 0x30F6 gatewayGetWifiList, //wifi列表 0x30F6
gatewayGetWifiListResult, //wifi列表结果 0x30F7 gatewayGetWifiListResult, //wifi列表结果 0x30F7
gatewayGetStatus, // 0x30F8 gatewayGetStatus, // 0x30F8
readRegisterKey, // 0x30A7
sendAuthorizationCode, // 0x30A6
generalExtendedCommond, // = 0x3030 generalExtendedCommond, // = 0x3030
gecChangeAdministratorPassword, // - = 2 gecChangeAdministratorPassword, // - = 2
@ -210,7 +214,12 @@ extension ExtensionCommandType on CommandType {
break; break;
case 0x30A4: case 0x30A4:
{ {
type = CommandType.getDeviceModel; type = CommandType.readLockCurrentVoicePacket;
}
break;
case 0x30A5:
{
type = CommandType.setLockCurrentVoicePacket;
} }
break; break;
case 0x30F4: case 0x30F4:
@ -238,6 +247,16 @@ extension ExtensionCommandType on CommandType {
type = CommandType.gatewayGetStatus; type = CommandType.gatewayGetStatus;
} }
break; break;
case 0x30A6:
{
type = CommandType.sendAuthorizationCode;
}
break;
case 0x30A7:
{
type = CommandType.readRegisterKey;
}
break;
default: default:
{ {
type = CommandType.readStarLockStatusInfo; type = CommandType.readStarLockStatusInfo;
@ -340,9 +359,18 @@ extension ExtensionCommandType on CommandType {
case CommandType.voicePackageConfigureConfirmation: case CommandType.voicePackageConfigureConfirmation:
type = 0x30A3; type = 0x30A3;
break; break;
case CommandType.getDeviceModel: case CommandType.readLockCurrentVoicePacket:
type = 0x30A4; type = 0x30A4;
break; break;
case CommandType.setLockCurrentVoicePacket:
type = 0x30A5;
break;
case CommandType.sendAuthorizationCode:
type = 0x30A6;
break;
case CommandType.readRegisterKey:
type = 0x30A7;
break;
default: default:
type = 0x300A; type = 0x300A;
break; break;
@ -362,7 +390,8 @@ extension ExtensionCommandType on CommandType {
case CommandType.gatewayGetWifiList: case CommandType.gatewayGetWifiList:
case CommandType.gatewayConfiguringWifi: case CommandType.gatewayConfiguringWifi:
case CommandType.gatewayGetStatus: case CommandType.gatewayGetStatus:
case CommandType.getDeviceModel: case CommandType.readLockCurrentVoicePacket:
case CommandType.setLockCurrentVoicePacket:
// //
type = 0x20; type = 0x20;
break; break;
@ -476,7 +505,16 @@ extension ExtensionCommandType on CommandType {
t = '语音包配置确认'; t = '语音包配置确认';
break; break;
case 0x30A4: case 0x30A4:
t = '获取设备型号'; t = '读取锁当前语音包';
break;
case 0x30A5:
t = '设置锁当前语音包';
break;
case 0x30A6:
t = '发送授权码';
break;
case 0x30A7:
t = '读取注册密钥';
break; break;
default: default:
t = '读星锁状态信息'; t = '读星锁状态信息';

View File

@ -16,11 +16,15 @@ import 'package:star_lock/blue/io_protocol/io_getDeviceModel.dart';
import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart'; import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart'; import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart'; import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart';
import 'package:star_lock/blue/io_protocol/io_readRegisterKey.dart';
import 'package:star_lock/blue/io_protocol/io_readSupportFunctionsNoParameters.dart'; import 'package:star_lock/blue/io_protocol/io_readSupportFunctionsNoParameters.dart';
import 'package:star_lock/blue/io_protocol/io_readSupportFunctionsWithParameters.dart'; import 'package:star_lock/blue/io_protocol/io_readSupportFunctionsWithParameters.dart';
import 'package:star_lock/blue/io_protocol/io_readVoicePackageFinalResult.dart';
import 'package:star_lock/blue/io_protocol/io_referEventRecordTime.dart'; import 'package:star_lock/blue/io_protocol/io_referEventRecordTime.dart';
import 'package:star_lock/blue/io_protocol/io_sendAuthorizationCode.dart';
import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsNoParameters.dart'; import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsNoParameters.dart';
import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsWithParameters.dart'; import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsWithParameters.dart';
import 'package:star_lock/blue/io_protocol/io_setVoicePackageFinalResult.dart';
import 'package:star_lock/blue/io_protocol/io_timing.dart'; import 'package:star_lock/blue/io_protocol/io_timing.dart';
import 'package:star_lock/blue/io_protocol/io_voicePackageConfigure.dart'; import 'package:star_lock/blue/io_protocol/io_voicePackageConfigure.dart';
import 'package:star_lock/blue/io_protocol/io_voicePackageConfigureProcess.dart'; import 'package:star_lock/blue/io_protocol/io_voicePackageConfigureProcess.dart';
@ -317,6 +321,30 @@ class CommandReciverManager {
commandType, data); commandType, data);
} }
break; break;
case CommandType.readLockCurrentVoicePacket:
{
reply =
ReadLockCurrentVoicePacketReply.parseData(commandType, data);
}
break;
case CommandType.setLockCurrentVoicePacket:
{
reply =
SetVoicePackageFinalResultReply.parseData(commandType, data);
}
break;
case CommandType.readRegisterKey:
{
reply =
SenderReadRegisterKeyCommandReply.parseData(commandType, data);
}
break;
case CommandType.sendAuthorizationCode:
{
reply =
SenderAuthorizationCodeCommandReply.parseData(commandType, data);
}
break;
case CommandType.generalExtendedCommond: case CommandType.generalExtendedCommond:
{ {
// //

View File

@ -1,4 +1,3 @@
import 'dart:async'; import 'dart:async';
import 'package:star_lock/blue/entity/lock_user_no_list_entity.dart'; import 'package:star_lock/blue/entity/lock_user_no_list_entity.dart';
@ -22,10 +21,10 @@ import 'io_tool/manager_event_bus.dart';
import 'sender_data.dart'; import 'sender_data.dart';
class SenderBeforeDataManage { class SenderBeforeDataManage {
factory SenderBeforeDataManage() => shareManager()!; factory SenderBeforeDataManage() => shareManager()!;
SenderBeforeDataManage._init(); SenderBeforeDataManage._init();
static SenderBeforeDataManage? _manager; static SenderBeforeDataManage? _manager;
static SenderBeforeDataManage? shareManager() { static SenderBeforeDataManage? shareManager() {
@ -42,6 +41,7 @@ class SenderBeforeDataManage {
// //
StreamSubscription<Reply>? _replySubscription; StreamSubscription<Reply>? _replySubscription;
// //
bool isBeforeAddUser = true; bool isBeforeAddUser = true;
@ -123,14 +123,14 @@ class SenderBeforeDataManage {
final int status = reply.data[6]; final int status = reply.data[6];
switch (status) { switch (status) {
case 0x00: case 0x00:
// //
CommonDataManage().initUserNo = 0; CommonDataManage().initUserNo = 0;
CommonDataManage().currentKeyInfo.initUserNo = 0; CommonDataManage().currentKeyInfo.initUserNo = 0;
_updateLockInitUserNo(); _updateLockInitUserNo();
break; break;
case 0x06: case 0x06:
// //
final List<int> token = reply.data.sublist(2, 6); final List<int> token = reply.data.sublist(2, 6);
final List<String> strTokenList = changeIntListToStringList(token); final List<String> strTokenList = changeIntListToStringList(token);
Storage.setStringList(saveBlueToken, strTokenList); Storage.setStringList(saveBlueToken, strTokenList);
@ -139,17 +139,15 @@ class SenderBeforeDataManage {
CommandSenderManager().sendNormalData(transferSmartLockData); CommandSenderManager().sendNormalData(transferSmartLockData);
break; break;
default: default:
// //
break; break;
} }
} }
// //
Future<List<int>> getCleanUpUsers({List<int>? tokenList}) async { Future<List<int>> getCleanUpUsers({List<int>? tokenList}) async {
final LockUserNoListEntity entity = await ApiRepository.to final LockUserNoListEntity entity = await ApiRepository.to.getLockUserNoList(lockId: CommonDataManage().currentKeyInfo.lockId!);
.getLockUserNoList(lockId: CommonDataManage().currentKeyInfo.lockId!); if (!entity.errorCode!.codeIsSuccessful || (entity.data?.userNos ?? <int>[]).isEmpty) {
if (!entity.errorCode!.codeIsSuccessful ||
(entity.data?.userNos ?? <int>[]).isEmpty) {
throw Exception('ApiRepository.to.getLockUserNoList 访问失败'); throw Exception('ApiRepository.to.getLockUserNoList 访问失败');
} }
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -197,27 +195,28 @@ class SenderBeforeDataManage {
int endDateTime = 0; int endDateTime = 0;
bool isRound = false; bool isRound = false;
int useCountLimit = 0xffff; int useCountLimit = 0xffff;
if(currentKeyInfo.keyType == XSConstantMacro.keyTypeTime){ if (currentKeyInfo.keyType == XSConstantMacro.keyTypeTime) {
// //
startDateTime = currentKeyInfo.startDate! ~/ 1000; startDateTime = currentKeyInfo.startDate! ~/ 1000;
endDateTime = currentKeyInfo.endDate! ~/ 1000; endDateTime = currentKeyInfo.endDate! ~/ 1000;
}else if(currentKeyInfo.keyType == XSConstantMacro.keyTypeLoop){ } else if (currentKeyInfo.keyType == XSConstantMacro.keyTypeLoop) {
// //
isRound = true; isRound = true;
startTime = DateTime.fromMillisecondsSinceEpoch(currentKeyInfo.startDate!); startTime = DateTime.fromMillisecondsSinceEpoch(currentKeyInfo.startDate!);
endTime = DateTime.fromMillisecondsSinceEpoch(currentKeyInfo.endDate!); endTime = DateTime.fromMillisecondsSinceEpoch(currentKeyInfo.endDate!);
startDateTime = DateTool().dateToTimestamp(DateTool().dateToYMDString(currentKeyInfo.startDate!.toString()), 1) ~/ 1000; startDateTime = DateTool().dateToTimestamp(DateTool().dateToYMDString(currentKeyInfo.startDate!.toString()), 1) ~/ 1000;
endDateTime = (DateTool().dateToTimestamp(DateTool().dateToYMDString(currentKeyInfo.endDate!.toString()), 1) + CommonDataManage().dayLatestTime) ~/ 1000; endDateTime =
}else if(currentKeyInfo.keyType == XSConstantMacro.keyTypeOnce){ (DateTool().dateToTimestamp(DateTool().dateToYMDString(currentKeyInfo.endDate!.toString()), 1) + CommonDataManage().dayLatestTime) ~/ 1000;
// } else if (currentKeyInfo.keyType == XSConstantMacro.keyTypeOnce) {
useCountLimit = 1; //
} useCountLimit = 1;
}
// AppLog.log("startTime.hour:${startTime!.hour} startTime.minute:${startTime!.minute} endTime.hour:${endTime!.hour} endTime.minute:${endTime!.minute}}"); // AppLog.log("startTime.hour:${startTime!.hour} startTime.minute:${startTime!.minute} endTime.hour:${endTime!.hour} endTime.minute:${endTime!.minute}}");
final AddUserCommand addUserData = AddUserCommand( final AddUserCommand addUserData = AddUserCommand(
lockID: BlueManage().connectDeviceName, lockID: BlueManage().connectDeviceName,
authUserID: currentKeyInfo.senderUserId!.toString(), authUserID: currentKeyInfo.senderUserId?.toString() ?? '1',
keyID: currentKeyInfo.keyId.toString(), keyID: currentKeyInfo.keyId.toString(),
userID: await Storage.getUid(), userID: await Storage.getUid(),
openMode: 1, openMode: 1,
@ -226,10 +225,7 @@ class SenderBeforeDataManage {
expireDate: endDateTime, expireDate: endDateTime,
useCountLimit: useCountLimit, useCountLimit: useCountLimit,
isRound: isRound ? 1 : 0, isRound: isRound ? 1 : 0,
weekRound: isRound weekRound: isRound ? DateTool().accordingTheCycleIntoTheCorrespondingNumber(currentKeyInfo.weekDays!) : 0,
? DateTool().accordingTheCycleIntoTheCorrespondingNumber(
currentKeyInfo.weekDays!)
: 0,
startHour: isRound ? startTime!.hour : 0, startHour: isRound ? startTime!.hour : 0,
startMin: isRound ? startTime!.minute : 0, startMin: isRound ? startTime!.minute : 0,
endHour: isRound ? endTime!.hour : 0, endHour: isRound ? endTime!.hour : 0,
@ -271,8 +267,7 @@ class SenderBeforeDataManage {
// NO // NO
Future<void> _updateLockUserNo(List<int> dataList) async { Future<void> _updateLockUserNo(List<int> dataList) async {
final LockNetTokenEntity entity = await ApiRepository.to.updateLockUserNo( final LockNetTokenEntity entity = await ApiRepository.to.updateLockUserNo(
keyId: CommonDataManage().currentKeyInfo.keyId.toString(), keyId: CommonDataManage().currentKeyInfo.keyId.toString(), lockUserNo: CommonDataManage().currentKeyInfo.lockUserNo.toString());
lockUserNo: CommonDataManage().currentKeyInfo.lockUserNo.toString());
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
eventBus.fire(RefreshLockListInfoDataEvent()); eventBus.fire(RefreshLockListInfoDataEvent());
eventBus.fire(LockAddUserSucceedEvent(<int>[0], 0)); eventBus.fire(LockAddUserSucceedEvent(<int>[0], 0));
@ -281,9 +276,8 @@ class SenderBeforeDataManage {
// InitUserNo // InitUserNo
Future<void> _updateLockInitUserNo() async { Future<void> _updateLockInitUserNo() async {
final LockNetTokenEntity entity = await ApiRepository.to.updateLockInitUserNo( final LockNetTokenEntity entity = await ApiRepository.to
lockId: CommonDataManage().currentKeyInfo.lockId ?? 0, .updateLockInitUserNo(lockId: CommonDataManage().currentKeyInfo.lockId ?? 0, initUserNo: CommonDataManage().currentKeyInfo.initUserNo ?? 0);
initUserNo: CommonDataManage().currentKeyInfo.initUserNo ?? 0);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
eventBus.fire(RefreshLockListInfoDataEvent()); eventBus.fire(RefreshLockListInfoDataEvent());
eventBus.fire(LockInitUserNoEvent()); eventBus.fire(LockInitUserNoEvent());

View File

@ -6,6 +6,8 @@ import 'package:star_lock/blue/io_protocol/io_deletUser.dart';
import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart'; import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart'; import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart'; import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart';
import 'package:star_lock/blue/io_protocol/io_readRegisterKey.dart';
import 'package:star_lock/blue/io_protocol/io_sendAuthorizationCode.dart';
import 'io_gateway/io_gateway_configuringWifi.dart'; import 'io_gateway/io_gateway_configuringWifi.dart';
import 'io_gateway/io_gateway_getStatus.dart'; import 'io_gateway/io_gateway_getStatus.dart';
@ -1109,10 +1111,7 @@ class IoSenderManage {
//ota //ota
static void senderProcessOtaUpgradeCommand( static void senderProcessOtaUpgradeCommand(
{required int? index, {required int? index, required int? size, required List<int>? data, CommandSendCallBack? callBack}) {
required int? size,
required List<int>? data,
CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData( CommandSenderManager().managerSendData(
command: ProcessOtaUpgradeCommand( command: ProcessOtaUpgradeCommand(
index: index, index: index,
@ -1321,8 +1320,7 @@ class IoSenderManage {
} }
// wifi列表 // wifi列表
static void gatewayGetWifiCommand( static void gatewayGetWifiCommand({required String? userID, CommandSendCallBack? callBack}) {
{required String? userID, CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData( CommandSenderManager().managerSendData(
command: GatewayGetWifiCommand( command: GatewayGetWifiCommand(
userID: userID, userID: userID,
@ -1339,21 +1337,51 @@ class IoSenderManage {
CommandSendCallBack? callBack}) { CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData( CommandSenderManager().managerSendData(
command: GatewayConfiguringWifiCommand( command: GatewayConfiguringWifiCommand(
ssid: ssid, ssid: ssid, password: password, gatewayConfigurationStr: gatewayConfigurationStr),
password: password,
gatewayConfigurationStr: gatewayConfigurationStr),
isBeforeAddUser: true, isBeforeAddUser: true,
callBack: callBack); callBack: callBack);
} }
// //
static void gatewayGetStatusCommand( static void gatewayGetStatusCommand(
{required String? lockID, {required String? lockID, required String? userID, CommandSendCallBack? callBack}) {
required String? userID,
CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData( CommandSenderManager().managerSendData(
command: GatewayGetStatusCommand(lockID: lockID, userID: userID), command: GatewayGetStatusCommand(lockID: lockID, userID: userID), isBeforeAddUser: true, callBack: callBack);
isBeforeAddUser: true, }
callBack: callBack);
//
static void readRegisterKey({
required String? lockID,
CommandSendCallBack? callBack,
}) {
CommandSenderManager().managerSendData(
command: SenderReadRegisterKeyCommand(lockID: lockID),
isBeforeAddUser: true,
callBack: callBack,
);
}
//
static void sendAuthorizationCode({
required String? lockID,
required String? uuid,
required String? key,
required String? mac,
required int? platform,
required int? utcTimeStamp,
CommandSendCallBack? callBack,
}) {
CommandSenderManager().managerSendData(
command: SenderAuthorizationCodeCommand(
lockID: lockID,
uuid: uuid,
key: key,
mac: mac,
platform: platform,
utcTimeStamp: utcTimeStamp,
),
isBeforeAddUser: true,
callBack: callBack,
);
} }
} }

View File

@ -45,49 +45,50 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xFFFFFFFF), backgroundColor: const Color(0xFFFFFFFF),
appBar: TitleAppBar( appBar: TitleAppBar(
barTitle: '登录'.tr, barTitle: '登录'.tr,
haveBack: false, haveBack: false,
backgroundColor: AppColors.mainColor, backgroundColor: AppColors.mainColor,
actionsList: <Widget>[ actionsList: <Widget>[
if (state.isChina == true) if (state.isChina == true)
IconButton( IconButton(
onPressed: () { onPressed: () {
WechatManageTool.getAppInfo( WechatManageTool.getAppInfo(CustomerTool.openCustomerService);
CustomerTool.openCustomerService); },
}, icon: const Icon(
icon: const Icon( Icons.support_agent,
Icons.support_agent, color: Colors.white,
color: Colors.white, )),
)), TextButton(
TextButton( child: Text(
child: Text( '注册'.tr,
'注册'.tr, style: TextStyle(color: Colors.white, fontSize: 24.sp),
style: TextStyle(color: Colors.white, fontSize: 24.sp),
),
onPressed: () async {
final data = await Get.toNamed(Routers.starLockRegisterPage);
if (data != null) {
state.emailOrPhoneController.text = data['phoneOrEmailStr'];
logic.checkNext(state.emailOrPhoneController);
state.pwdController.text = data['pwd'];
logic.checkNext(state.pwdController);
setState(() {});
}
},
), ),
], onPressed: () async {
), final data = await Get.toNamed(Routers.starLockRegisterPage);
body: ListView( if (data != null) {
state.emailOrPhoneController.text = data['phoneOrEmailStr'];
logic.checkNext(state.emailOrPhoneController);
state.pwdController.text = data['pwd'];
logic.checkNext(state.pwdController);
setState(() {});
}
},
),
],
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: ListView(
padding: EdgeInsets.only(top: 120.h, left: 40.w, right: 40.w), padding: EdgeInsets.only(top: 120.h, left: 40.w, right: 40.w),
children: <Widget>[ children: <Widget>[
Container( Container(
padding: EdgeInsets.all(10.w), padding: EdgeInsets.all(10.w),
child: Center( child: Center(child: Image.asset('images/icon_main_sky_1024.png', width: 110.w, height: 110.w))),
child: Image.asset('images/icon_main_sky_1024.png',
width: 110.w, height: 110.w))),
SizedBox(height: 50.w), SizedBox(height: 50.w),
Obx(() => CommonItem( Obx(() => CommonItem(
leftTitel: '你所在的国家/地区'.tr, leftTitel: '你所在的国家/地区'.tr,
@ -99,12 +100,10 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
rightWidget: Text( rightWidget: Text(
'${state.countryName} +${state.countryCode.value}', '${state.countryName} +${state.countryCode.value}',
textAlign: TextAlign.end, textAlign: TextAlign.end,
style: TextStyle( style: TextStyle(fontSize: 22.sp, color: AppColors.darkGrayTextColor),
fontSize: 22.sp, color: AppColors.darkGrayTextColor),
), ),
action: () async { action: () async {
final result = final result = await Get.toNamed(Routers.selectCountryRegionPage);
await Get.toNamed(Routers.selectCountryRegionPage);
if (result != null) { if (result != null) {
result as Map<String, dynamic>; result as Map<String, dynamic>;
state.countryCode.value = result['code']; state.countryCode.value = result['code'];
@ -120,8 +119,7 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
logic.checkNext(state.emailOrPhoneController); logic.checkNext(state.emailOrPhoneController);
}, },
leftWidget: Padding( leftWidget: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
child: Image.asset( child: Image.asset(
'images/icon_login_account.png', 'images/icon_login_account.png',
width: 36.w, width: 36.w,
@ -145,8 +143,7 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
isPwd: true, isPwd: true,
// isSuffixIcon: 2, // isSuffixIcon: 2,
leftWidget: Padding( leftWidget: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
child: Image.asset( child: Image.asset(
'images/icon_login_password.png', 'images/icon_login_password.png',
width: 36.w, width: 36.w,
@ -168,12 +165,9 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
}, },
child: Container( child: Container(
// color: Colors.red, // color: Colors.red,
padding: EdgeInsets.only( padding: EdgeInsets.only(left: 5.w, top: 20.w, right: 10.w, bottom: 20.h),
left: 5.w, top: 20.w, right: 10.w, bottom: 20.h),
child: Image.asset( child: Image.asset(
state.agree.value state.agree.value ? 'images/icon_round_select.png' : 'images/icon_round_unSelect.png',
? 'images/icon_round_select.png'
: 'images/icon_round_unSelect.png',
width: 35.w, width: 35.w,
height: 35.w, height: 35.w,
), ),
@ -185,37 +179,30 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
child: RichText( child: RichText(
text: TextSpan( text: TextSpan(
text: '我已阅读并同意'.tr, text: '我已阅读并同意'.tr,
style: TextStyle( style: TextStyle(color: const Color(0xff333333), fontSize: 20.sp),
color: const Color(0xff333333), fontSize: 20.sp),
children: <InlineSpan>[ children: <InlineSpan>[
WidgetSpan( WidgetSpan(
alignment: PlaceholderAlignment.middle, alignment: PlaceholderAlignment.middle,
child: GestureDetector( child: GestureDetector(
child: Text('${'用户协议'.tr}', child:
style: TextStyle( Text('${'用户协议'.tr}', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
color: AppColors.mainColor,
fontSize: 20.sp)),
onTap: () { onTap: () {
Get.toNamed(Routers.webviewShowPage, Get.toNamed(Routers.webviewShowPage, arguments: <String, String>{
arguments: <String, String>{ 'url': XSConstantMacro.userAgreementURL,
'url': XSConstantMacro.userAgreementURL, 'title': '用户协议'.tr
'title': '用户协议'.tr });
});
}, },
)), )),
WidgetSpan( WidgetSpan(
alignment: PlaceholderAlignment.middle, alignment: PlaceholderAlignment.middle,
child: GestureDetector( child: GestureDetector(
child: Text('${'隐私政策'.tr}', child:
style: TextStyle( Text('${'隐私政策'.tr}', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
color: AppColors.mainColor,
fontSize: 20.sp)),
onTap: () { onTap: () {
Get.toNamed(Routers.webviewShowPage, Get.toNamed(Routers.webviewShowPage, arguments: <String, String>{
arguments: <String, String>{ 'url': XSConstantMacro.privacyPolicyURL,
'url': XSConstantMacro.privacyPolicyURL, 'title': '隐私政策'.tr
'title': '隐私政策'.tr });
});
}, },
)), )),
], ],
@ -268,44 +255,19 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
height: 50.h, height: 50.h,
// color: Colors.red, // color: Colors.red,
child: Center( child: Center(
child: Text('${'忘记密码'.tr}', child: Text('${'忘记密码'.tr}', style: TextStyle(fontSize: 22.sp, color: AppColors.mainColor)),
style: TextStyle(
fontSize: 22.sp, color: AppColors.mainColor)),
), ),
), ),
onTap: () { onTap: () {
Navigator.pushNamed( Navigator.pushNamed(context, Routers.starLockForgetPasswordPage);
context, Routers.starLockForgetPasswordPage);
}, },
), ),
Expanded(
child: SizedBox(
width: 10.sp,
)),
Obx(() => Visibility(
visible: state.isCheckVerifyEnable.value &&
state.currentLanguage == 'zh_CN',
child: GestureDetector(
child: SizedBox(
// width: 150.w,
height: 50.h,
// color: Colors.red,
child: Center(
child: Text('一键登录'.tr,
style: TextStyle(
fontSize: 22.sp,
color: AppColors.mainColor)),
),
),
onTap: () {
logic.oneClickLoginAction(context);
},
),
))
], ],
), ),
], ],
)); ),
),
);
} }
Widget loginInput( Widget loginInput(
@ -346,8 +308,7 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
inputFormatters: inputFormatters, inputFormatters: inputFormatters,
decoration: InputDecoration( decoration: InputDecoration(
// //
contentPadding: const EdgeInsets.only( contentPadding: const EdgeInsets.only(top: 8.0, left: -19.0, right: -15.0, bottom: 8.0),
top: 8.0, left: -19.0, right: -15.0, bottom: 8.0),
labelText: label, labelText: label,
labelStyle: TextStyle(fontSize: 22.sp), labelStyle: TextStyle(fontSize: 22.sp),
hintStyle: TextStyle(fontSize: 22.sp), hintStyle: TextStyle(fontSize: 22.sp),

View File

@ -84,14 +84,13 @@ class StarLockRegisterLogic extends BaseGetXController {
} }
Future<void> sendValidationCode() async { Future<void> sendValidationCode() async {
final SendValidationCodeEntity entity = final SendValidationCodeEntity entity = await ApiRepository.to.sendValidationCodeUnLogin(
await ApiRepository.to.sendValidationCodeUnLogin( // state.countryCode.value,
// state.countryCode.value, countryCode: state.countryCode.value.toString(),
countryCode: state.countryCode.value.toString(), account: state.phoneOrEmailStr.value,
account: state.phoneOrEmailStr.value, channel: state.isIphoneType.value ? '1' : '2',
channel: state.isIphoneType.value ? '1' : '2', codeType: '1',
codeType: '1', xWidth: state.xWidth.value.toString());
xWidth: state.xWidth.value.toString());
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
_startTimer(); _startTimer();
} else {} } else {}
@ -100,13 +99,17 @@ class StarLockRegisterLogic extends BaseGetXController {
Future<void> checkIpAction() async { Future<void> checkIpAction() async {
final CheckIPEntity entity = await ApiRepository.to.checkIpAction(ip: ''); final CheckIPEntity entity = await ApiRepository.to.checkIpAction(ip: '');
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
if (entity.data!.abbreviation != 'CN') {
showToast('当前国家不支持手机验证码注册,请使用邮箱进行注册'.tr);
state.isIphoneType.value = false;
return;
}
if (state.countryName.value != entity.data!.name) { if (state.countryName.value != entity.data!.name) {
ShowTipView().showSureAlertDialog( ShowTipView().showSureAlertDialog(
'国家地区的选择将影响数据安全,你当前选择的是'.tr + '国家地区的选择将影响数据安全,你当前选择的是'.tr + '${state.countryName.value},' + '请确认后再继续'.tr,
'${state.countryName.value},' + tipTitle: '确认国家或地区'.tr,
'请确认后再继续'.tr, sureStr: '我知道了'.tr,
tipTitle: '确认国家或地区'.tr, );
sureStr: '我知道了'.tr);
} }
} }
} }
@ -138,19 +141,16 @@ class StarLockRegisterLogic extends BaseGetXController {
// //
void _resetCanSub() { void _resetCanSub() {
state.canSub.value = state.pwdIsOK && state.canSub.value = state.pwdIsOK && state.codeIsOK && state.phoneOrEmailStr.value.isNotEmpty;
state.codeIsOK &&
state.phoneOrEmailStr.value.isNotEmpty;
} }
// //
void _resetCanSendCode() { void _resetCanSendCode() {
state.canSendCode.value = state.canSendCode.value = state.pwdIsOK && state.phoneOrEmailStr.value.isNotEmpty;
state.pwdIsOK && state.phoneOrEmailStr.value.isNotEmpty;
} }
@override @override
void onReady() { void onReady() async {
super.onReady(); super.onReady();
XSConstantMacro().getDeviceInfoData().then((Map<String, dynamic> data) { XSConstantMacro().getDeviceInfoData().then((Map<String, dynamic> data) {
@ -159,5 +159,7 @@ class StarLockRegisterLogic extends BaseGetXController {
// //
AppLog.log('获取设备信息时出错: $error'); AppLog.log('获取设备信息时出错: $error');
}); });
await checkIpAction();
} }
} }

View File

@ -4,7 +4,10 @@ import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:star_lock/app_settings/app_settings.dart'; import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/login/register/entity/checkIP_entity.dart';
import 'package:star_lock/login/register/starLock_register_state.dart'; import 'package:star_lock/login/register/starLock_register_state.dart';
import 'package:star_lock/network/api_repository.dart';
import 'package:star_lock/tools/baseGetXController.dart';
import '../../appRouters.dart'; import '../../appRouters.dart';
import '../../app_settings/app_colors.dart'; import '../../app_settings/app_colors.dart';
@ -28,13 +31,14 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xFFFFFFFF), backgroundColor: const Color(0xFFFFFFFF),
appBar: TitleAppBar( appBar: TitleAppBar(barTitle: '注册'.tr, haveBack: true, backgroundColor: AppColors.mainColor),
barTitle: '注册'.tr, body: GestureDetector(
haveBack: true, onTap: () {
backgroundColor: AppColors.mainColor), FocusScope.of(context).unfocus();
body: ListView( },
child: ListView(
padding: EdgeInsets.only(top: 40.h, left: 40.w, right: 40.w), padding: EdgeInsets.only(top: 40.h, left: 40.w, right: 40.w),
children: <Widget>[ children: <Widget>[
topSelectCountryAndRegionWidget(), topSelectCountryAndRegionWidget(),
@ -63,7 +67,9 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
), ),
_buildBottomAgreement() _buildBottomAgreement()
], ],
)); ),
),
);
} }
Widget topSelectCountryAndRegionWidget() { Widget topSelectCountryAndRegionWidget() {
@ -78,8 +84,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
height: 60.h, height: 60.h,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30.h)), borderRadius: BorderRadius.all(Radius.circular(30.h)),
border: border: Border.all(width: 1.0, color: AppColors.greyLineColor)),
Border.all(width: 1.0, color: AppColors.greyLineColor)),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
GestureDetector( GestureDetector(
@ -93,18 +98,13 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
decoration: state.isIphoneType.value decoration: state.isIphoneType.value
? BoxDecoration( ? BoxDecoration(
color: AppColors.mainColor, color: AppColors.mainColor,
borderRadius: borderRadius: BorderRadius.all(Radius.circular(30.h)),
BorderRadius.all(Radius.circular(30.h)), border: Border.all(width: 1.0, color: AppColors.greyLineColor))
border: Border.all(
width: 1.0, color: AppColors.greyLineColor))
: null, : null,
child: Center( child: Center(
child: Text( child: Text(
'手机'.tr, '手机'.tr,
style: TextStyle( style: TextStyle(color: state.isIphoneType.value ? Colors.white : Colors.black),
color: state.isIphoneType.value
? Colors.white
: Colors.black),
), ),
), ),
), ),
@ -121,19 +121,14 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
decoration: !state.isIphoneType.value decoration: !state.isIphoneType.value
? BoxDecoration( ? BoxDecoration(
color: AppColors.mainColor, color: AppColors.mainColor,
borderRadius: borderRadius: BorderRadius.all(Radius.circular(30.h)),
BorderRadius.all(Radius.circular(30.h)), border: Border.all(width: 1.0, color: AppColors.greyLineColor))
border: Border.all(
width: 1.0,
color: AppColors.greyLineColor))
: null, : null,
child: Center( child: Center(
child: Text( child: Text(
'邮箱'.tr, '邮箱'.tr,
style: TextStyle( style: TextStyle(
color: !state.isIphoneType.value color: !state.isIphoneType.value ? Colors.white : Colors.black,
? Colors.white
: Colors.black,
), ),
), ),
), ),
@ -164,9 +159,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
children: <Widget>[ children: <Widget>[
SizedBox(width: 5.w), SizedBox(width: 5.w),
Expanded( Expanded(
child: Text('你所在的国家/地区'.tr, child: Text('你所在的国家/地区'.tr, style: TextStyle(fontSize: 26.sp, color: AppColors.blackColor))),
style: TextStyle(
fontSize: 26.sp, color: AppColors.blackColor))),
SizedBox(width: 20.w), SizedBox(width: 20.w),
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
@ -176,8 +169,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
? '${state.countryName.value} +${state.countryCode.value}' ? '${state.countryName.value} +${state.countryCode.value}'
: state.countryName.value, : state.countryName.value,
textAlign: TextAlign.end, textAlign: TextAlign.end,
style: TextStyle( style: TextStyle(fontSize: 26.sp, color: AppColors.blackColor),
fontSize: 26.sp, color: AppColors.blackColor),
) )
], ],
), ),
@ -212,9 +204,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
Padding( Padding(
padding: EdgeInsets.only(right: 5.w, left: 5.w), padding: EdgeInsets.only(right: 5.w, left: 5.w),
child: Image.asset( child: Image.asset(
state.isIphoneType.value state.isIphoneType.value ? 'images/icon_login_account.png' : 'images/icon_login_email.png',
? 'images/icon_login_account.png'
: 'images/icon_login_email.png',
width: 30.w, width: 30.w,
height: 30.w, height: 30.w,
), ),
@ -248,8 +238,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
SizedBox(height: 15.w), SizedBox(height: 15.w),
Text( Text(
'密码必须是8-20位至少包括数字/字母/符号中的2种'.tr, '密码必须是8-20位至少包括数字/字母/符号中的2种'.tr,
style: style: TextStyle(color: AppColors.placeholderTextColor, fontSize: 20.sp),
TextStyle(color: AppColors.placeholderTextColor, fontSize: 20.sp),
), ),
SizedBox(height: 10.w), SizedBox(height: 10.w),
LoginInput( LoginInput(
@ -298,15 +287,20 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
Obx(() => GestureDetector( Obx(() => GestureDetector(
onTap: (state.canSendCode.value && state.canResend.value) onTap: (state.canSendCode.value && state.canResend.value)
? () async { ? () async {
final CheckIPEntity entity = await ApiRepository.to.checkIpAction(ip: '');
if (entity.errorCode!.codeIsSuccessful) {
if (entity.data!.abbreviation != 'CN') {
logic.showToast('当前国家不支持手机验证码注册,请使用邮箱进行注册'.tr);
return;
}
}
// Navigator.pushNamed(context, Routers.safetyVerificationPage, arguments: {"countryCode":"+86", "account":state.phoneOrEmailStr.value}); // Navigator.pushNamed(context, Routers.safetyVerificationPage, arguments: {"countryCode":"+86", "account":state.phoneOrEmailStr.value});
final Object? result = await Navigator.pushNamed( final Object? result = await Navigator.pushNamed(context, Routers.safetyVerificationPage,
context, Routers.safetyVerificationPage,
arguments: <String, Object>{ arguments: <String, Object>{
'countryCode': state.countryCode, 'countryCode': state.countryCode,
'account': state.phoneOrEmailStr.value 'account': state.phoneOrEmailStr.value
}); });
state.xWidth.value = state.xWidth.value = (result! as Map<String, dynamic>)['xWidth'];
(result! as Map<String, dynamic>)['xWidth'];
logic.sendValidationCode(); logic.sendValidationCode();
} }
: null, : null,
@ -315,10 +309,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
// height: 60.h, // height: 60.h,
padding: EdgeInsets.all(10.h), padding: EdgeInsets.all(10.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: color: (state.canSendCode.value && state.canResend.value) ? AppColors.mainColor : Colors.grey,
(state.canSendCode.value && state.canResend.value)
? AppColors.mainColor
: Colors.grey,
borderRadius: BorderRadius.circular(5)), borderRadius: BorderRadius.circular(5)),
child: Center( child: Center(
child: Text(state.btnText.value, child: Text(state.btnText.value,
@ -347,9 +338,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
logic.changeAgreeState(); logic.changeAgreeState();
}, },
child: Image.asset( child: Image.asset(
state.agree.value state.agree.value ? 'images/icon_round_select.png' : 'images/icon_round_unSelect.png',
? 'images/icon_round_select.png'
: 'images/icon_round_unSelect.png',
width: 30.w, width: 30.w,
height: 30.w, height: 30.w,
))), ))),
@ -365,29 +354,19 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
WidgetSpan( WidgetSpan(
alignment: PlaceholderAlignment.middle, alignment: PlaceholderAlignment.middle,
child: GestureDetector( child: GestureDetector(
child: Text('${'用户协议'.tr}', child: Text('${'用户协议'.tr}', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
style: TextStyle(
color: AppColors.mainColor, fontSize: 20.sp)),
onTap: () { onTap: () {
Get.toNamed(Routers.webviewShowPage, Get.toNamed(Routers.webviewShowPage,
arguments: <String, String>{ arguments: <String, String>{'url': XSConstantMacro.userAgreementURL, 'title': '用户协议'.tr});
'url': XSConstantMacro.userAgreementURL,
'title': '用户协议'.tr
});
}, },
)), )),
WidgetSpan( WidgetSpan(
alignment: PlaceholderAlignment.middle, alignment: PlaceholderAlignment.middle,
child: GestureDetector( child: GestureDetector(
child: Text('${'隐私政策'.tr}', child: Text('${'隐私政策'.tr}', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
style: TextStyle(
color: AppColors.mainColor, fontSize: 20.sp)),
onTap: () { onTap: () {
Get.toNamed(Routers.webviewShowPage, Get.toNamed(Routers.webviewShowPage,
arguments: <String, String>{ arguments: <String, String>{'url': XSConstantMacro.privacyPolicyURL, 'title': '隐私政策'.tr});
'url': XSConstantMacro.privacyPolicyURL,
'title': '隐私政策'.tr
});
}, },
)), )),
], ],

View File

@ -62,10 +62,8 @@ FutureOr<void> main() async {
} }
}); });
// //ToDo: // ios则初始化获取到voip token
// runApp(MultiProvider(providers: [ // token callkit
// ChangeNotifierProvider(create: (_) => DebugInfoModel()),
// ], child: MyApp(isLogin: isLogin)));
if (Platform.isIOS) { if (Platform.isIOS) {
CallKitHandler.setupListener(); CallKitHandler.setupListener();
String? token = await CallKitHandler.getVoipToken(); String? token = await CallKitHandler.getVoipToken();
@ -111,20 +109,4 @@ Future<void> privacySDKInitialization() async {
await jpushProvider.initJPushService(); await jpushProvider.initJPushService();
NotificationService().init(); // NotificationService().init(); //
// /// ip如果属于国内才进行初始化
// final CheckIPEntity entity = await ApiRepository.to.checkIpAction(ip: '');
// if (entity.errorCode!.codeIsSuccessful) {
// String currentLanguage =
// CurrentLocaleTool.getCurrentLocaleString(); //
// // ip是国内的且选的是中文才初始化一键登录
// if (entity.data!.abbreviation?.toLowerCase() == 'cn' &&
// currentLanguage == 'zh_CN') {
// //
// final StarLockLoginLogic loginLogic = Get.put(StarLockLoginLogic());
// await JverifyOneClickLoginManage();
// loginLogic.state.isCheckVerifyEnable.value =
// await JverifyOneClickLoginManage().checkVerifyEnable();
// eventBus.fire(AgreePrivacyAgreement());
// }
// }
} }

View File

@ -0,0 +1,11 @@
extension DateTimeExtensions on DateTime {
/// DateTime 00:00:00.000
DateTime get withoutTime {
return DateTime(year, month, day);
}
///
bool isSameDate(DateTime other) {
return year == other.year && month == other.month && day == other.day;
}
}

View File

@ -125,4 +125,9 @@ class DoorLockLogDataItem {
data['recordDetailStr'] = recordDetailStr; data['recordDetailStr'] = recordDetailStr;
return data; return data;
} }
@override
String toString() {
return 'DoorLockLogDataItem{recordId: $recordId, lockId: $lockId, lockAlias: $lockAlias, recordType: $recordType, recordTypeName: $recordTypeName, username: $username, operateDate: $operateDate, imagesUrl: $imagesUrl, videoUrl: $videoUrl, headUrl: $headUrl, userid: $userid, keyboardPwd: $keyboardPwd, recordStr: $recordStr, recordDetailStr: $recordDetailStr}';
}
} }

View File

@ -3,11 +3,15 @@ import 'dart:async';
import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:star_lock/apm/apm_helper.dart'; import 'package:star_lock/apm/apm_helper.dart';
import 'package:star_lock/appRouters.dart';
import 'package:star_lock/app_settings/app_settings.dart'; import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/date_time_extensions.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart';
import 'package:star_lock/main/lockDetail/lockOperatingRecord/lockOperatingRecordGetLastRecordTime_entity.dart'; import 'package:star_lock/main/lockDetail/lockOperatingRecord/lockOperatingRecordGetLastRecordTime_entity.dart';
import 'package:star_lock/mine/valueAddedServices/advancedFeaturesWeb/advancedFeaturesWeb_entity.dart';
import 'package:star_lock/tools/commonDataManage.dart'; import 'package:star_lock/tools/commonDataManage.dart';
import 'package:star_lock/tools/dateTool.dart'; import 'package:star_lock/tools/dateTool.dart';
import 'package:star_lock/tools/eventBusEventManage.dart'; import 'package:star_lock/tools/eventBusEventManage.dart';
@ -235,13 +239,15 @@ class DoorLockLogLogic extends BaseGetXController {
lockId: state.keyInfos.value.lockId!, lockId: state.keyInfos.value.lockId!,
lockEventType: state.dropdownValue.value, lockEventType: state.dropdownValue.value,
pageNo: pageNo, pageNo: pageNo,
pageSize: int.parse(pageSize), pageSize: 1000,
startDate: state.startDate.value, startDate: state.startDate.value,
endDate: state.endDate.value); endDate: state.endDate.value);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
// //
state.lockLogItemList.addAll(entity.data!.itemList!); state.lockLogItemList.addAll(entity.data!.itemList!);
state.lockLogItemList.refresh(); state.lockLogItemList.refresh();
state.weekEventList.addAll(entity.data!.itemList!);
state.weekEventList.refresh();
// //
pageNo++; pageNo++;
} }
@ -358,6 +364,7 @@ class DoorLockLogLogic extends BaseGetXController {
@override @override
Future<void> onInit() async { Future<void> onInit() async {
_setWeekRange();
super.onInit(); super.onInit();
// //
@ -370,6 +377,48 @@ class DoorLockLogLogic extends BaseGetXController {
} }
} }
void _setWeekRange() {
final now = DateTime.now();
// 1=7=
int weekday = now.weekday; // 1-7
//
// : 0, : 1, ..., : 6
int daysToSubtract = weekday - 1; // 1
// 00:00:00.000
DateTime startOfWeek = DateTime(now.year, now.month, now.day)
.subtract(Duration(days: daysToSubtract));
// 23:59:59.999
DateTime endOfWeek = startOfWeek
.add(Duration(days: 6)) // 6
.add(Duration(hours: 23, minutes: 59, seconds: 59, milliseconds: 999));
//
state.startDate.value = startOfWeek.millisecondsSinceEpoch;
state.endDate.value = endOfWeek.millisecondsSinceEpoch;
}
//
void refreshWeek() {
_setWeekRange();
}
getWebPlayUrl() async {
final AdvancedFeaturesWebEntity entity =
await ApiRepository.to.getServicePackageBuyUrl();
if (entity.errorCode!.codeIsSuccessful) {
state.cloudStorageWebViewUrl.value = entity.data!.cloudStorage!;
final uploadReportBuyRequest = await ApiRepository.to
.uploadReportBuyRequest(lockId: state.keyInfos.value.lockId!);
if (uploadReportBuyRequest.errorCode!.codeIsSuccessful) {
Get.toNamed(Routers.advancedFeaturesWebPage, arguments: <String, int>{
'webBuyType': XSConstantMacro.webBuyTypeCloudStorage,
});
}
}
}
@override @override
Future<void> onClose() async { Future<void> onClose() async {
super.onClose(); super.onClose();

View File

@ -1,12 +1,18 @@
import 'package:flustars/flustars.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:star_lock/appRouters.dart'; import 'package:star_lock/appRouters.dart';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/date_time_extensions.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_logic.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_logic.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/exportRecordDialog/exportRecordDialog_page.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/exportRecordDialog/exportRecordDialog_page.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/week_calendar_view.dart';
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart'; import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart'; import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart';
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail_image.dart'; import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail_image.dart';
@ -32,8 +38,39 @@ class DoorLockLogPage extends StatefulWidget {
} }
class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware { class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
final ScrollController _scrollController = ScrollController();
final DoorLockLogLogic logic = Get.put(DoorLockLogLogic()); final DoorLockLogLogic logic = Get.put(DoorLockLogLogic());
final DoorLockLogState state = Get.find<DoorLockLogLogic>().state; final DoorLockLogState state = Get.find<DoorLockLogLogic>().state;
bool _isAtBottom = false;
@override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
}
void _onScroll() {
final max = _scrollController.position.maxScrollExtent;
final current = _scrollController.position.pixels;
AppLog.log('current:${current}');
// 5
if (current >= max - 5) {
if (!_isAtBottom) {
setState(() {
_isAtBottom = true;
});
print('✅ 已滑动到 timelines 列表底部!');
//
}
} else {
if (_isAtBottom) {
setState(() {
_isAtBottom = false;
});
}
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -45,8 +82,7 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
backgroundColor: AppColors.mainColor, backgroundColor: AppColors.mainColor,
actionsList: <Widget>[ actionsList: <Widget>[
Visibility( Visibility(
visible: CommonDataManage().currentKeyInfo.isLockOwner == 1 || visible: CommonDataManage().currentKeyInfo.isLockOwner == 1 || CommonDataManage().currentKeyInfo.keyRight == 1,
CommonDataManage().currentKeyInfo.keyRight == 1,
child: GestureDetector( child: GestureDetector(
child: Image.asset( child: Image.asset(
'images/icon_tips_Q.png', 'images/icon_tips_Q.png',
@ -55,27 +91,20 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
color: Colors.white, color: Colors.white,
), ),
onTap: () { onTap: () {
ShowTipView().showSureAlertDialog( ShowTipView().showSureAlertDialog('1.锁没有联网密码、IC卡、指纹等开门记录无法实时上传可以点击右上角按钮然后读取记录。'.tr + '\n' + '2.如果您需要保留历史记录,可以点击右上角按钮,然后导出记录'.tr,
'1.锁没有联网密码、IC卡、指纹等开门记录无法实时上传可以点击右上角按钮然后读取记录。'.tr + tipTitle: '看不到操作记录,可能原因有'.tr, sureStr: '我知道了'.tr);
'\n' +
'2.如果您需要保留历史记录,可以点击右上角按钮,然后导出记录'.tr,
tipTitle: '看不到操作记录,可能原因有'.tr,
sureStr: '我知道了'.tr);
}, },
)), )),
Visibility( Visibility(
visible: CommonDataManage().currentKeyInfo.isLockOwner == 1 || visible: CommonDataManage().currentKeyInfo.isLockOwner == 1 || CommonDataManage().currentKeyInfo.keyRight == 1,
CommonDataManage().currentKeyInfo.keyRight == 1,
child: PopupMenuButton<String>( child: PopupMenuButton<String>(
onSelected: _onMenuItemSelected, onSelected: _onMenuItemSelected,
color: Colors.black, color: Colors.black,
itemBuilder: (BuildContext context) { itemBuilder: (BuildContext context) {
return <PopupMenuEntry<String>>[ return <PopupMenuEntry<String>>[
_buildCustomPopupMenuItem('读取记录'.tr), _buildCustomPopupMenuItem('读取记录'.tr),
if (CommonDataManage().currentKeyInfo.isLockOwner == 1) if (CommonDataManage().currentKeyInfo.isLockOwner == 1) const PopupMenuDivider(),
const PopupMenuDivider(), if (CommonDataManage().currentKeyInfo.isLockOwner == 1) _buildCustomPopupMenuItem('清空记录'.tr),
if (CommonDataManage().currentKeyInfo.isLockOwner == 1)
_buildCustomPopupMenuItem('清空记录'.tr),
const PopupMenuDivider(), const PopupMenuDivider(),
_buildCustomPopupMenuItem('导出记录'.tr), _buildCustomPopupMenuItem('导出记录'.tr),
]; ];
@ -93,17 +122,28 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
body: Column( body: Column(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[topAdvancedCalendarWidget(), eventDropDownWidget(), Expanded(child: timeLineView())],
topAdvancedCalendarWidget(), ),
Divider( floatingActionButton: Visibility(
height: 1, visible: _isAtBottom,
color: AppColors.greyLineColor, child: FloatingActionButton(
indent: 30.w, onPressed: () {
endIndent: 30.w, _scrollController.animateTo(
0.0,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(48.w),
), ),
eventDropDownWidget(), backgroundColor: AppColors.mainColor,
Expanded(child: timeLineView()) child: Icon(
], Icons.arrow_upward,
color: Colors.white,
size: 48.w,
),
),
), ),
); );
} }
@ -141,8 +181,7 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
builder: (BuildContext context) { builder: (BuildContext context) {
return ExportRecordDialog( return ExportRecordDialog(
onExport: (String filePath) { onExport: (String filePath) {
Get.toNamed(Routers.exportSuccessPage, Get.toNamed(Routers.exportSuccessPage, arguments: <String, String>{'filePath': filePath});
arguments: <String, String>{'filePath': filePath});
}, },
); );
}, },
@ -150,88 +189,14 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
} }
} }
// switch (value) {
// case "读取记录".tr:
// {
// logic.mockNetworkDataRequest(isRefresh: true);
// }
// break;
// case '清空记录'.tr:
// {
// ShowCupertinoAlertView().showClearOperationRecordAlert(
// clearClick: () {
// logic.clearOperationRecordRequest();
// });
// }
// break;
// case '导出记录':
// {
// showDialog(
// context: context,
// builder: (BuildContext context) {
// return ExportRecordDialog(
// onExport: (String filePath) {
// Get.toNamed(Routers.exportSuccessPage,
// arguments: <String, String>{'filePath': filePath});
// },
// );
// },
// );
// }
// break;
// }
// }
// //
Widget topAdvancedCalendarWidget() { Widget topAdvancedCalendarWidget() {
final ThemeData theme = Theme.of(context); return Container(
return Theme( margin: EdgeInsets.only(top: 20.h, left: 30.w, bottom: 10.h, right: 20.w),
data: theme.copyWith( child: Column(
textTheme: theme.textTheme.copyWith( crossAxisAlignment: CrossAxisAlignment.start,
titleMedium: theme.textTheme.titleMedium!.copyWith( children: [
fontSize: 16, _buildWeekCalendar(),
color: theme.colorScheme.secondary,
),
bodyLarge: theme.textTheme.bodyLarge!.copyWith(
fontSize: 14,
color: Colors.black54,
),
bodyMedium: theme.textTheme.bodyMedium!.copyWith(
fontSize: 12,
color: Colors.black87,
),
),
primaryColor: AppColors.mainColor,
highlightColor: Colors.yellow,
disabledColor: Colors.grey,
),
child: Stack(
children: <Widget>[
AdvancedCalendar(
controller: state.calendarControllerCustom,
events: state.events,
weekLineHeight: 48.0,
startWeekDay: 1,
innerDot: true,
keepLineSize: true,
calendarTextStyle: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w400,
height: 1.3125,
letterSpacing: 0,
),
),
Positioned(
top: 8.0,
right: 8.0,
child: Obx(() => Text(
'${state.currentSelectDate.value.year}${''.tr}${state.currentSelectDate.value.month}${''.tr}',
style: theme.textTheme.titleMedium!.copyWith(
fontSize: 16,
color: theme.colorScheme.secondary,
),
)),
),
], ],
), ),
); );
@ -267,40 +232,158 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16.w), borderRadius: BorderRadius.circular(16.w),
), ),
child: Obx(() => EasyRefreshTool( child: Obx(
onRefresh: () async { () => state.lockLogItemList.isNotEmpty
logic.mockNetworkDataRequest(isRefresh: true); ? Timeline.tileBuilder(
}, controller: _scrollController,
onLoad: () async { builder: _timelineBuilderWidget(),
logic.mockNetworkDataRequest(isRefresh: false); theme: TimelineThemeData(
}, nodePosition: 0.04, //
child: state.lockLogItemList.isNotEmpty connectorTheme: const ConnectorThemeData(
? Timeline.tileBuilder( thickness: 1.0,
builder: _timelineBuilderWidget(), color: AppColors.greyLineColor,
theme: TimelineThemeData( indent: 0.5,
nodePosition: 0.04, //
connectorTheme: const ConnectorThemeData(
thickness: 1.0,
color: AppColors.greyLineColor,
indent: 0.5,
),
indicatorTheme: const IndicatorThemeData(
size: 8.0,
color: AppColors.greyLineColor,
position: 0.4,
),
), ),
) indicatorTheme: const IndicatorThemeData(
: NoData())), size: 8.0,
color: AppColors.greyLineColor,
position: 0.4,
),
),
)
: NoData(),
),
); );
} }
String formatTimestampToDateTimeYYYYMMDD(int timestampMs) {
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestampMs);
DateFormat formatter = DateFormat('MM${''.tr}dd${''.tr}'); // 2025-08-18 14:30
return formatter.format(dateTime);
}
String formatTimestampToHHmm(int timestampMs) {
// 2. DateTime
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestampMs);
// 3. 使 DateFormat "HH:mm"
DateFormat formatter = DateFormat('HH:mm');
return formatter.format(dateTime);
}
bool _checkIsVideoOrImagesType(DoorLockLogDataItem item) {
final recordType = item.recordType;
switch (recordType) {
case 130:
case 220:
return true;
default:
return false;
}
}
String _buildIDByType(DoorLockLogDataItem item) {
final recordType = item.recordType;
switch (recordType) {
case 10:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '指纹'.tr + '开锁'.tr + '${_formatUserNameOrId(item)}';
case 20:
return '${formatTimestampToHHmm(item.operateDate!)} ' +
'密码'.tr +
'开锁'.tr +
'${_formatUserNameOrId(item)}' +
'${'密码'.tr}${item.keyboardPwd}';
case 30:
return '${formatTimestampToHHmm(item.operateDate!)} ' + ''.tr + '开锁'.tr + '${_formatUserNameOrId(item)}';
case 40:
if (item.username != null && item.username != '') {
return '${formatTimestampToHHmm(item.operateDate!)} ' + '蓝牙'.tr + '开锁'.tr + '${_formatUserNameOrId(item)}';
} else {
return '${formatTimestampToHHmm(item.operateDate!)} ' + '蓝牙'.tr + '开锁'.tr + '' + 'ID'.tr + '${item.userid}';
}
case 50:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '组合模式'.tr + '开锁'.tr + '${_formatUserNameOrId(item)}';
case 60:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '添加'.tr + '指纹'.tr + '${_formatUserNameOrId(item)}';
case 70:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '添加'.tr + '密码'.tr + '${_formatUserNameOrId(item)}';
case 80:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '添加'.tr + ''.tr + '${_formatUserNameOrId(item)}';
case 90:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '删除'.tr + '指纹'.tr + '${_formatUserNameOrId(item)}';
case 100:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '删除'.tr + '密码'.tr + '${_formatUserNameOrId(item)}';
case 110:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '删除'.tr + ''.tr + '${_formatUserNameOrId(item)}';
case 160:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '人脸'.tr + '开锁'.tr + '${_formatUserNameOrId(item)}';
case 190:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '胁迫指纹'.tr + '开锁'.tr + '${_formatUserNameOrId(item)}';
case 200:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '胁迫密码'.tr + '开锁'.tr + '${_formatUserNameOrId(item)}';
case 210:
return '${formatTimestampToHHmm(item.operateDate!)} ' + '胁迫卡片'.tr + '开锁'.tr + '${_formatUserNameOrId(item)}';
default:
return item.recordStr ?? '';
}
}
//
String _formatUserNameOrId(DoorLockLogDataItem item) {
final recordStr = item.recordStr;
final idMatch = RegExp(r'ID[:](\w+)').firstMatch(recordStr ?? '');
final idValue = idMatch?.group(1) ?? '';
final name = item.username ?? '';
// ID: ID ID:xxx
if (name.isNotEmpty) {
final idInNameMatch = RegExp(r'^ID[:].+').hasMatch(name);
if (idInNameMatch) {
return name; // "ID:123"
} else {
return '${'昵称'.tr}$name'; //
}
}
// 使 recordStr ID
return 'ID$idValue';
}
Color _buildTextColorByType(DoorLockLogDataItem item) {
final recordType = item.recordType;
switch (recordType) {
case 120:
case 150:
case 130:
case 190:
case 200:
case 210:
case 220:
return Colors.red;
default:
return Colors.black;
}
}
TimelineTileBuilder _timelineBuilderWidget() { TimelineTileBuilder _timelineBuilderWidget() {
return TimelineTileBuilder.fromStyle( return TimelineTileBuilder.fromStyle(
contentsAlign: ContentsAlign.basic, contentsAlign: ContentsAlign.basic,
itemCount: state.lockLogItemList.length, itemCount: state.lockLogItemList.length,
contentsBuilder: (BuildContext context, int index) { contentsBuilder: (BuildContext context, int index) {
final DoorLockLogDataItem timelineData = state.lockLogItemList[index]; final DoorLockLogDataItem timelineData = state.lockLogItemList[index];
// 👇 videoUrl build
int? firstVideoIndex = state.lockLogItemList.indexWhere((item) => _checkIsVideoOrImagesType(item));
bool isInvalid = _checkIsVideoOrImagesType(timelineData) &&
((timelineData.imagesUrl == null && timelineData.videoUrl == null) || (timelineData.videoUrl == '' && timelineData.imagesUrl == ''));
String typeText = '';
if (timelineData.recordType == 130) {
typeText = '图像'.tr;
} else if (timelineData.recordType == 220) {
typeText = '视频'.tr;
}
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
Get.toNamed( Get.toNamed(
@ -309,18 +392,45 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
); );
}, },
child: Padding( child: Padding(
padding: EdgeInsets.only(left: 20.w, top: 20.h), padding: EdgeInsets.only(left: 20.w, top: 20.h, right: 20.w),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Text( Text('${formatTimestampToDateTimeYYYYMMDD(timelineData.operateDate!)}',
timelineData.recordStr ?? '', style: TextStyle(
textAlign: TextAlign.left, fontSize: 20.sp,
style: TextStyle( )),
color: Colors.black, // 使 SingleChildScrollView
fontSize: 24.sp, SingleChildScrollView(
fontWeight: FontWeight.w600, scrollDirection: Axis.horizontal, //
child: RichText(
textAlign: TextAlign.left,
text: TextSpan(
style: TextStyle(
color: _buildTextColorByType(timelineData),
fontSize: 24.sp,
fontWeight: FontWeight.w600,
),
children: [
TextSpan(
text: _buildIDByType(timelineData) + (isInvalid ? '${typeText}' + '已失效'.tr + '' : ''),
),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Visibility(
visible: isInvalid,
child: Icon(
Icons.error,
size: 24.sp,
color: Colors.red,
),
),
),
],
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
), ),
), ),
SizedBox( SizedBox(
@ -336,8 +446,70 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
), ),
), ),
SizedBox( SizedBox(
height: 20.h, height: 12.h,
), ),
Visibility(
visible: _checkIsVideoOrImagesType(timelineData) && index == firstVideoIndex,
child: GestureDetector(
onTap: () async {
await logic.getWebPlayUrl();
},
child: Container(
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
children: [
//
TextSpan(
text:
'${'您的图像和视频数据仅保留'.tr} ${state.rollingStorageDays.value} ${''.tr} ,${state.rollingStorageDays.value} ${''.tr} ${'后图像和视频数据将会失效,开通'.tr}',
style: TextStyle(
color: Colors.grey,
fontSize: 16.sp,
fontWeight: FontWeight.w600,
height: 1.8,
),
),
// 🔥
TextSpan(
text: '云存会员'.tr,
style: TextStyle(
color: AppColors.mainColor,
fontSize: 22.sp,
fontWeight: FontWeight.w800,
//
decoration: TextDecoration.underline,
decorationThickness: 1.5,
height: 1.8,
),
recognizer: TapGestureRecognizer()
..onTap = () async {
// 👉
print('点击了“云存会员”');
await logic.getWebPlayUrl();
// Navigator.push(context, MaterialPageRoute(builder: ...));
},
),
//
TextSpan(
text: '服务,图像视频信息随心存!'.tr,
style: TextStyle(
color: Colors.grey,
fontSize: 16.sp,
fontWeight: FontWeight.w600,
height: 1.8,
),
),
],
),
),
),
),
)
], ],
), ),
), ),
@ -352,9 +524,7 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) { if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) {
final lockLogItemList = state.lockLogItemList.value; final lockLogItemList = state.lockLogItemList.value;
final list = lockLogItemList final list = lockLogItemList
.where((e) => .where((e) => (e.videoUrl != null && e.videoUrl!.isNotEmpty) || (e.imagesUrl != null && e.imagesUrl!.isNotEmpty))
(e.videoUrl != null && e.videoUrl!.isNotEmpty) ||
(e.imagesUrl != null && e.imagesUrl!.isNotEmpty))
.map( .map(
(e) => RecordListData( (e) => RecordListData(
videoUrl: e.videoUrl, videoUrl: e.videoUrl,
@ -365,16 +535,13 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
), ),
) )
.toList(); .toList();
final selectDateString = final selectDateString = DateTool().dateToYMDString(state.startDate.value.toString());
DateTool().dateToYMDString(state.startDate.value.toString()); final cloudStorageData = CloudStorageData(date: selectDateString, recordList: list);
final cloudStorageData =
CloudStorageData(date: selectDateString, recordList: list);
Get.toNamed(Routers.videoLogDetailPage, arguments: <String, Object>{ Get.toNamed(Routers.videoLogDetailPage, arguments: <String, Object>{
'recordData': recordData, 'recordData': recordData,
'videoDataList': [cloudStorageData] 'videoDataList': [cloudStorageData]
}); });
} else if (recordData.imagesUrl != null && } else if (recordData.imagesUrl != null && recordData.imagesUrl!.isNotEmpty) {
recordData.imagesUrl!.isNotEmpty) {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
@ -385,8 +552,7 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
); );
} }
}, },
child: ((recordData.imagesUrl != null && recordData.imagesUrl != '') || child: ((recordData.imagesUrl != null && recordData.imagesUrl != '') || (recordData.videoUrl != null && recordData.videoUrl != ''))
(recordData.videoUrl != null && recordData.videoUrl != ''))
? Container( ? Container(
width: 260.w, width: 260.w,
height: 260.h, height: 260.h,
@ -404,8 +570,7 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
_buildImageOrVideoItem(RecordListData recordData) { _buildImageOrVideoItem(RecordListData recordData) {
if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) { if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) {
return _buildVideoItem(recordData); return _buildVideoItem(recordData);
} else if (recordData.imagesUrl != null && } else if (recordData.imagesUrl != null && recordData.imagesUrl!.isNotEmpty) {
recordData.imagesUrl!.isNotEmpty) {
return _buildImageItem(recordData); return _buildImageItem(recordData);
} else { } else {
return SizedBox.shrink(); return SizedBox.shrink();
@ -422,8 +587,7 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
child: Image.network( child: Image.network(
recordData.imagesUrl!, recordData.imagesUrl!,
fit: BoxFit.cover, fit: BoxFit.cover,
errorBuilder: errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) {
(BuildContext context, Object error, StackTrace? stackTrace) {
// //
return Image.asset( return Image.asset(
'images/icon_unHaveData.png', // 'images/icon_unHaveData.png', //
@ -484,4 +648,53 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
} }
state.ifCurrentScreen.value = false; state.ifCurrentScreen.value = false;
} }
List<DateTime> getCurrentWeekDates() {
final now = DateTime.now();
// weekday: 1=, 2=, ..., 7=
//
// weekday == 7 0
final int daysSinceSunday = now.weekday % 7; // =1 -> %7=1, =7 -> %7=0
final List<DateTime> weekDates = [];
for (int i = 0; i < 7; i++) {
final DateTime day = DateTime(
now.year,
now.month,
now.day - daysSinceSunday + i, //
);
weekDates.add(day);
}
return weekDates;
}
Widget _buildWeekCalendar() {
return Obx(() {
final list = state.weekEventList.value;
final dateSet = list
.map((e) => DateTime.fromMillisecondsSinceEpoch(e.operateDate!))
.map((dt) => dt.withoutTime) //
.toSet(); // Set
AppLog.log('dateSet:${dateSet}');
return WeekCalendarView(
hasData: (DateTime date) {
return dateSet.contains(date.withoutTime);
},
onDateSelected: (DateTime date) async {
print('外部收到选中: $date');
state.operateDate = date.millisecondsSinceEpoch;
state.startDate.value = DateTime(date.year, date.month, date.day).millisecondsSinceEpoch;
state.endDate.value = DateTime(date.year, date.month, date.day, 23, 59, 59, 999).millisecondsSinceEpoch;
await logic.mockNetworkDataRequest(isRefresh: true);
},
onWeekChanged: (DateTime start, DateTime end) {
state.startDate.value = start.millisecondsSinceEpoch;
state.endDate.value = end.millisecondsSinceEpoch;
logic.mockNetworkDataRequest(isRefresh: true);
},
);
});
}
} }

View File

@ -1,5 +1,5 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get/get_rx/get_rx.dart';
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart'; import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart';
import 'package:star_lock/tools/advancedCalendar/src/controller.dart'; import 'package:star_lock/tools/advancedCalendar/src/controller.dart';
@ -13,10 +13,15 @@ class DoorLockLogState {
DoorLockLogState() { DoorLockLogState() {
keyInfos.value = Get.arguments['keyInfo']; keyInfos.value = Get.arguments['keyInfo'];
} }
final Rx<DoorLockLogEntity> lockLogEntity = DoorLockLogEntity().obs; final Rx<DoorLockLogEntity> lockLogEntity = DoorLockLogEntity().obs;
final Rx<LockListInfoItemEntity> keyInfos = LockListInfoItemEntity().obs; final Rx<LockListInfoItemEntity> keyInfos = LockListInfoItemEntity().obs;
final RxList<DoorLockLogDataItem> lockLogItemList = final RxList<DoorLockLogDataItem> lockLogItemList =
<DoorLockLogDataItem>[].obs; <DoorLockLogDataItem>[].obs;
final RxList<DoorLockLogDataItem> weekEventList =
<DoorLockLogDataItem>[].obs;
final RxList<DoorLockLogDataItem> dayEventList =
<DoorLockLogDataItem>[].obs;
final AdvancedCalendarController calendarControllerToday = final AdvancedCalendarController calendarControllerToday =
AdvancedCalendarController.today(); AdvancedCalendarController.today();
final AdvancedCalendarController calendarControllerCustom = final AdvancedCalendarController calendarControllerCustom =
@ -31,7 +36,7 @@ class DoorLockLogState {
.millisecondsSinceEpoch .millisecondsSinceEpoch
.obs; .obs;
final RxInt endDate = DateTime( final RxInt endDate = DateTime(
DateTime.now().year, DateTime.now().month, DateTime.now().day + 1) DateTime.now().year, DateTime.now().month, DateTime.now().day + 1)
.subtract(const Duration(milliseconds: 1)) .subtract(const Duration(milliseconds: 1))
.millisecondsSinceEpoch .millisecondsSinceEpoch
.obs; .obs;
@ -69,4 +74,6 @@ class DoorLockLogState {
int logCountPage = 10; // int logCountPage = 10; //
Rx<DateTime> currentSelectDate = DateTime.now().obs; Rx<DateTime> currentSelectDate = DateTime.now().obs;
bool isLockReceiveResponse = false; // bool isLockReceiveResponse = false; //
RxString cloudStorageWebViewUrl = ''.obs;
RxInt rollingStorageDays = 3.obs; //
} }

View File

@ -0,0 +1,220 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:star_lock/app_settings/app_colors.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/date_time_extensions.dart';
class WeekCalendarView extends StatefulWidget {
//
final bool Function(DateTime date)? hasData;
final void Function(DateTime date)? onDateSelected; //
final void Function(DateTime start, DateTime end)? onWeekChanged;
const WeekCalendarView({
Key? key,
this.hasData,
this.onDateSelected,
this.onWeekChanged,
}) : super(key: key);
@override
_WeekCalendarViewState createState() => _WeekCalendarViewState();
}
class _WeekCalendarViewState extends State<WeekCalendarView> {
final PageController _pageController = PageController(initialPage: 500);
int _currentPage = 500;
// DateTime
late DateTime _selectedDate;
@override
void initState() {
super.initState();
_selectedDate = DateTime.now().withoutTime; //
}
// page
List<DateTime> _getWeekDatesForPage(int page) {
final now = DateTime.now();
final baseSunday =
DateTime(now.year, now.month, now.day - (now.weekday % 7));
final daysOffset = (page - 500) * 7;
final targetSunday = baseSunday.add(Duration(days: daysOffset));
return List.generate(
7,
(i) => DateTime(
targetSunday.year, targetSunday.month, targetSunday.day + i));
}
//
bool _isToday(DateTime date) {
final now = DateTime.now();
return date.year == now.year &&
date.month == now.month &&
date.day == now.day;
}
//
bool _isSelected(DateTime date) {
return date.year == _selectedDate.year &&
date.month == _selectedDate.month &&
date.day == _selectedDate.day;
}
//
bool _hasData(DateTime date) {
return widget.hasData?.call(date.withoutTime) ?? false;
}
void _onDateSelected(DateTime date) {
setState(() {
_selectedDate = date.withoutTime;
});
//
widget.onDateSelected?.call(date);
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//
_buildWeekRangeLabel(_currentPage),
SizedBox(height: 10.h),
SizedBox(
height: 100.h,
child: PageView.builder(
controller: _pageController,
itemCount: 1000,
itemBuilder: (context, page) {
final weekDates = _getWeekDatesForPage(page);
return Row(
children: weekDates.asMap().entries.map((entry) {
final int index = entry.key;
final DateTime date = entry.value;
final bool isSelected = _isSelected(date);
final bool hasData = _hasData(date);
final bool isToday = _isToday(date);
//
Color textColor;
if (isSelected) {
textColor = Colors.white; //
} else if (hasData) {
textColor = Colors.black; //
} else if (isToday) {
textColor = Colors.black; //
} else {
textColor = Colors.grey; //
}
//
Color? bgColor;
if (isSelected) {
bgColor = AppColors.mainColor; //
}
//
return GestureDetector(
onTap: () => _onDateSelected(date),
child: Container(
padding: EdgeInsets.all(4.w),
width: 75.w,
height: 75.w,
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(50.r),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
[
'简写周日',
'简写周一',
'简写周二',
'简写周三',
'简写周四',
'简写周五',
'简写周六'
][index]
.tr,
style: TextStyle(
fontSize: 14.sp,
color: textColor,
fontWeight: FontWeight.w400,
),
),
Text(
date.day.toString(),
style: TextStyle(
fontSize: 26.sp,
color: textColor,
fontWeight: FontWeight.w600,
),
),
if (isToday && !isSelected) //
SizedBox(height: 2.h),
if (isToday && !isSelected)
Container(
width: 6.w,
height: 6.w,
decoration: BoxDecoration(
color: AppColors.mainColor,
shape: BoxShape.circle,
),
),
],
),
),
);
}).toList(),
);
},
onPageChanged: (page) {
setState(() {
_currentPage = page;
});
//
final dates = _getWeekDatesForPage(page);
final startOfWeek = dates.first;
final endOfWeek = dates.last;
//
widget.onWeekChanged?.call(startOfWeek, endOfWeek);
},
),
),
],
);
}
Widget _buildWeekRangeLabel(int page) {
final dates = _getWeekDatesForPage(page);
final start = dates[0];
final end = dates[6];
String label;
if (start.year == end.year) {
// "2025年8月18日 - 8月24日"
label =
'${start.year}${''.tr}${start.month}${''.tr}${start.day}${''.tr} - ${end.month}${''.tr}${end.day}${''.tr}';
} else {
// "2024年12月31日 - 2025年1月6日"
label =
'${start.year}${''.tr}${start.month}${''.tr}${start.day}${''.tr} - ${end.year}${''.tr}${end.month}${''.tr}${end.day}${''.tr}';
}
return Text(
label,
style: TextStyle(fontSize: 24.sp, fontWeight: FontWeight.w600),
);
}
}

View File

@ -316,6 +316,7 @@ class FaceListLogic extends BaseGetXController {
{required bool isRefresh}) async { {required bool isRefresh}) async {
if (isRefresh) { if (isRefresh) {
state.faceItemListData.clear(); state.faceItemListData.clear();
state.faceItemListData.refresh();
pageNo = 1; pageNo = 1;
} }
final FingerprintListDataEntity entity = final FingerprintListDataEntity entity =

View File

@ -253,10 +253,10 @@ class AddFingerprintLogic extends BaseGetXController {
final List<int> getTokenList = changeStringListToIntList(token!); final List<int> getTokenList = changeStringListToIntList(token!);
String startTime = DateTool().dateToHNString(state.effectiveDateTime.value); String startTime = DateTool().dateToHNString(state.effectiveDateTime.value);
String endTime = DateTool().dateToHNString(state.failureDateTime.value); String endTime = DateTool().dateToHNString(state.failureDateTime.value);
if (F.isSKY) { // if (F.isSKY) {
startTime = '255:00'; // startTime = '255:00';
endTime = '255:00'; // endTime = '255:00';
} // }
final String command = SenderAddFingerprintWithTimeCycleCoercionCommand( final String command = SenderAddFingerprintWithTimeCycleCoercionCommand(
keyID: '1', keyID: '1',
@ -281,7 +281,6 @@ class AddFingerprintLogic extends BaseGetXController {
privateKey: getPrivateKeyList, privateKey: getPrivateKeyList,
token: getTokenList, token: getTokenList,
).toString(); ).toString();
showBlueConnetctToastTimer(action: () async { showBlueConnetctToastTimer(action: () async {
final String getMobile = (await Storage.getMobile())!; final String getMobile = (await Storage.getMobile())!;
ApmHelper.instance.trackEvent('add_fingerprint', { ApmHelper.instance.trackEvent('add_fingerprint', {
@ -460,14 +459,7 @@ class AddFingerprintLogic extends BaseGetXController {
@override @override
void onReady() { void onReady() {
super.onReady(); super.onReady();
_initReplySubscription(); _initReplySubscription();
}
@override
void onInit() {
super.onInit();
senderAddFingerprint(); senderAddFingerprint();
} }

View File

@ -122,26 +122,26 @@ class _AddFingerprintPageState extends State<AddFingerprintPage> with RouteAware
String getIconNumber(int number) { String getIconNumber(int number) {
String iconPath = ''; String iconPath = '';
switch (number) { switch (number) {
case 0:
iconPath = 'images/main/icon_addFingerprint_fingerprint_one.png';
break;
case 1: case 1:
iconPath = 'images/main/icon_addFingerprint_fingerprint_two.png'; iconPath = 'images/main/addFingerprint/1.jpg';
break; break;
case 2: case 2:
iconPath = 'images/main/icon_addFingerprint_fingerprint_three.png'; iconPath = 'images/main/addFingerprint/2.jpg';
break; break;
case 3: case 3:
iconPath = 'images/main/icon_addFingerprint_fingerprint_four.png'; iconPath = 'images/main/addFingerprint/3.jpg';
break; break;
case 4: case 4:
iconPath = 'images/main/icon_addFingerprint_fingerprint_five.png'; iconPath = 'images/main/addFingerprint/4.jpg';
break; break;
case 5: case 5:
iconPath = 'images/main/icon_addFingerprint_fingerprint_six.png'; iconPath = 'images/main/addFingerprint/5.jpg';
break;
case 6:
iconPath = 'images/main/addFingerprint/6.jpg';
break; break;
default: default:
iconPath = 'images/main/icon_addFingerprint_fingerprint_six.png'; iconPath = 'images/main/addFingerprint/0.jpg';
break; break;
} }
return iconPath; return iconPath;

View File

@ -25,11 +25,9 @@ class FingerprintListLogic extends BaseGetXController {
late StreamSubscription<Reply> _replySubscription; late StreamSubscription<Reply> _replySubscription;
void _initReplySubscription() { void _initReplySubscription() {
_replySubscription = _replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) {
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) {
// () // ()
if ((reply is SenderAddFingerprintWithTimeCycleCoercionReply) && if ((reply is SenderAddFingerprintWithTimeCycleCoercionReply) && (state.ifCurrentScreen.value == true)) {
(state.ifCurrentScreen.value == true)) {
_replyAddFingerprintBegin(reply); _replyAddFingerprintBegin(reply);
} }
@ -57,13 +55,10 @@ class FingerprintListLogic extends BaseGetXController {
break; break;
case 0x06: case 0x06:
// //
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 =
changeStringListToIntList(privateKey!);
final List<String>? signKey = final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
await Storage.getStringList(saveBlueSignKey);
final List<int> signKeyDataList = changeStringListToIntList(signKey!); final List<int> signKeyDataList = changeStringListToIntList(signKey!);
final List<int> token = reply.data.sublist(5, 9); final List<int> token = reply.data.sublist(5, 9);
@ -257,20 +252,16 @@ class FingerprintListLogic 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) {
// var publicKey = await Storage.getStringList(saveBluePublicKey); // var publicKey = await Storage.getStringList(saveBluePublicKey);
// List<int> publicKeyDataList = changeStringListToIntList(publicKey!); // List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
final List<String>? signKey = final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
await Storage.getStringList(saveBlueSignKey);
final List<int> signKeyDataList = changeStringListToIntList(signKey!); final List<int> signKeyDataList = changeStringListToIntList(signKey!);
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 =
changeStringListToIntList(privateKey!);
final List<String>? token = await Storage.getStringList(saveBlueToken); final List<String>? token = await Storage.getStringList(saveBlueToken);
final List<int> getTokenList = changeStringListToIntList(token!); final List<int> getTokenList = changeStringListToIntList(token!);
@ -298,8 +289,7 @@ class FingerprintListLogic extends BaseGetXController {
privateKey: getPrivateKeyList, privateKey: getPrivateKeyList,
token: getTokenList, token: getTokenList,
isBeforeAddUser: false); isBeforeAddUser: false);
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
if (state.ifCurrentScreen.value == true) { if (state.ifCurrentScreen.value == true) {
@ -337,15 +327,15 @@ class FingerprintListLogic extends BaseGetXController {
*/ */
// //
Future<FingerprintListDataEntity> getFingerprintsListData( Future<FingerprintListDataEntity> getFingerprintsListData({required bool isRefresh}) async {
{required bool isRefresh}) async {
// //
if (isRefresh) { if (isRefresh) {
state.fingerprintItemListData.clear();
pageNo = 1; pageNo = 1;
state.fingerprintItemListData.clear();
state.fingerprintItemListData.refresh();
} }
final FingerprintListDataEntity entity =
await ApiRepository.to.getFingerprintsListData( final FingerprintListDataEntity entity = await ApiRepository.to.getFingerprintsListData(
lockId: state.lockId.value.toString(), lockId: state.lockId.value.toString(),
pageNo: pageNo.toString(), pageNo: pageNo.toString(),
pageSize: pageSize.toString(), pageSize: pageSize.toString(),
@ -381,10 +371,7 @@ class FingerprintListLogic extends BaseGetXController {
type = '0'; type = '0';
} }
final LoginEntity entity = await ApiRepository.to.deletFingerprintsData( final LoginEntity entity = await ApiRepository.to.deletFingerprintsData(
fingerprintId: fingerprintId, fingerprintId: fingerprintId, lockId: state.lockId.value.toString(), type: type, deleteType: '1');
lockId: state.lockId.value.toString(),
type: type,
deleteType: '1');
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
if (state.isDeletAll == false) { if (state.isDeletAll == false) {
showToast('删除成功'.tr, something: () { showToast('删除成功'.tr, something: () {
@ -402,9 +389,7 @@ class FingerprintListLogic extends BaseGetXController {
late StreamSubscription _teamEvent; late StreamSubscription _teamEvent;
void _initRefreshAction() { void _initRefreshAction() {
_teamEvent = eventBus _teamEvent = eventBus.on<OtherTypeRefreshListEvent>().listen((OtherTypeRefreshListEvent event) async {
.on<OtherTypeRefreshListEvent>()
.listen((OtherTypeRefreshListEvent event) async {
// //
await getFingerprintsListData(isRefresh: true); await getFingerprintsListData(isRefresh: true);
}); });
@ -415,8 +400,7 @@ class FingerprintListLogic extends BaseGetXController {
String keyTypeStr = ''; // String keyTypeStr = ''; //
// (fingerprintItemData.fingerprintType! != 1) ? (fingerprintItemData.endDate! < DateTime.now().millisecondsSinceEpoch ? "已失效" : "") : "" // (fingerprintItemData.fingerprintType! != 1) ? (fingerprintItemData.endDate! < DateTime.now().millisecondsSinceEpoch ? "已失效" : "") : ""
if (fingerprintItemData.fingerprintStatus == 1) { if (fingerprintItemData.fingerprintStatus == 1) {
if (fingerprintItemData.startDate! > if (fingerprintItemData.startDate! > DateTime.now().millisecondsSinceEpoch) {
DateTime.now().millisecondsSinceEpoch) {
keyTypeStr = '未生效'.tr; keyTypeStr = '未生效'.tr;
} }
} else if (fingerprintItemData.fingerprintStatus == 2) { } else if (fingerprintItemData.fingerprintStatus == 2) {
@ -428,8 +412,7 @@ class FingerprintListLogic extends BaseGetXController {
String getKeyDateType(FingerprintItemData fingerprintItemData) { String getKeyDateType(FingerprintItemData fingerprintItemData) {
String keyDateTypeStr = ''; // :1;23:4 String keyDateTypeStr = ''; // :1;23:4
if (fingerprintItemData.fingerprintType! == 1) { if (fingerprintItemData.fingerprintType! == 1) {
keyDateTypeStr = keyDateTypeStr = "${DateTool().dateToYMDHNString(fingerprintItemData.createDate.toString())} ${"永久".tr}";
"${DateTool().dateToYMDHNString(fingerprintItemData.createDate.toString())} ${"永久".tr}";
} else if (fingerprintItemData.fingerprintType! == 2) { } else if (fingerprintItemData.fingerprintType! == 2) {
keyDateTypeStr = keyDateTypeStr =
'${DateTool().dateToYMDHNString(fingerprintItemData.startDate.toString())} - ${DateTool().dateToYMDHNString(fingerprintItemData.endDate.toString())} ${'限时'.tr}'; '${DateTool().dateToYMDHNString(fingerprintItemData.startDate.toString())} - ${DateTool().dateToYMDHNString(fingerprintItemData.endDate.toString())} ${'限时'.tr}';
@ -442,11 +425,10 @@ class FingerprintListLogic extends BaseGetXController {
// //
Future<void> refreshIndividualKeys({required int fingerprintId}) async { Future<void> refreshIndividualKeys({required int fingerprintId}) async {
final FingerprintEntity entity = final FingerprintEntity entity = await ApiRepository.to.getFingerprintsData(fingerprintId);
await ApiRepository.to.getFingerprintsData(fingerprintId);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
final int index = state.fingerprintItemListData.indexWhere( final int index =
(FingerprintItemData item) => item.fingerprintId == fingerprintId); state.fingerprintItemListData.indexWhere((FingerprintItemData item) => item.fingerprintId == fingerprintId);
state.fingerprintItemListData.removeAt(index); state.fingerprintItemListData.removeAt(index);
state.fingerprintItemListData.insert(index, entity.data!); state.fingerprintItemListData.insert(index, entity.data!);
} }

View File

@ -0,0 +1,147 @@
import 'dart:convert';
class ActivateInfoResponse {
ActivateInfoResponse({
this.description,
this.errorCode,
this.data, // List<ActivateInfo>
this.errorMsg,
});
ActivateInfoResponse.fromJson(dynamic json) {
description = json['description'];
errorCode = json['errorCode'];
// ActivateInfo
data = json['data'] != null ? ActivateInfo.fromJson(json['data']) : null;
errorMsg = json['errorMsg'];
}
String? description;
int? errorCode;
ActivateInfo? data; // List<ActivateInfo>
String? errorMsg;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['description'] = description;
map['errorCode'] = errorCode;
if (data != null) {
// ActivateInfo JSON
map['data'] = data!.toJson();
}
map['errorMsg'] = errorMsg;
return map;
}
@override
String toString() {
return 'ActivateInfoResponse{description: $description, errorCode: $errorCode, data: $data, errorMsg: $errorMsg}';
}
}
class ActivateInfo {
String? authCode;
String? activatedAt;
Map<String, dynamic>? extraParams; // Map
ActivateInfo({
this.authCode,
this.activatedAt,
this.extraParams,
});
ActivateInfo.fromJson(dynamic json) {
authCode = json['auth_code'] ?? '';
activatedAt = json['activated_at'] ?? '';
// extraParams Map
if (json['extra_params'] != null) {
if (json['extra_params'] is Map) {
extraParams = json['extra_params'];
} else if (json['extra_params'] is String) {
// JSON
try {
extraParams = jsonDecode(json['extra_params']);
} catch (e) {
// null map
extraParams = {};
}
}
} else {
extraParams = {};
}
}
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['authCode'] = authCode;
map['activatedAt'] = activatedAt;
map['extraParams'] = extraParams;
return map;
}
@override
String toString() {
return 'ActivateInfo{authCode: $authCode, activatedAt: $activatedAt, extraParams: $extraParams}';
}
}
class TppSupportResponse {
TppSupportResponse({
this.description,
this.errorCode,
this.data, // List<ActivateInfo>
this.errorMsg,
});
TppSupportResponse.fromJson(dynamic json) {
description = json['description'];
errorCode = json['errorCode'];
// json['data'] List<ActivateInfo>
data = json['data'] != null ? (json['data'] as List).map((item) => TppSupportInfo.fromJson(item)).toList() : [];
errorMsg = json['errorMsg'];
}
String? description;
int? errorCode;
List<TppSupportInfo>? data; // List<ActivateInfo>
String? errorMsg;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['description'] = description;
map['errorCode'] = errorCode;
if (data != null) {
// List<ActivateInfo> JSON
map['data'] = data!.map((item) => item.toJson()).toList();
}
map['errorMsg'] = errorMsg;
return map;
}
@override
String toString() {
return 'TppSupportResponse{description: $description, errorCode: $errorCode, data: $data, errorMsg: $errorMsg}';
}
}
class TppSupportInfo {
int? platform;
String? platformName;
TppSupportInfo({
this.platform,
this.platformName,
});
TppSupportInfo.fromJson(dynamic json) {
platform = json['platform'] as int? ?? -1;
platformName = json['platform_name'] as String? ?? '';
}
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['platform'] = platform;
map['platform_name'] = platformName;
return map;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -34,11 +34,7 @@ import '../../lockMian/entity/lockListInfo_entity.dart';
import 'lockDetail_logic.dart'; import 'lockDetail_logic.dart';
class LockDetailPage extends StatefulWidget { class LockDetailPage extends StatefulWidget {
const LockDetailPage( const LockDetailPage({required this.isOnlyOneData, required this.lockListInfoItemEntity, Key? key}) : super(key: key);
{required this.isOnlyOneData,
required this.lockListInfoItemEntity,
Key? key})
: super(key: key);
final bool isOnlyOneData; final bool isOnlyOneData;
final LockListInfoItemEntity lockListInfoItemEntity; final LockListInfoItemEntity lockListInfoItemEntity;
@ -46,29 +42,26 @@ class LockDetailPage extends StatefulWidget {
State<LockDetailPage> createState() => _LockDetailPageState(); State<LockDetailPage> createState() => _LockDetailPageState();
} }
class _LockDetailPageState extends State<LockDetailPage> class _LockDetailPageState extends State<LockDetailPage> with TickerProviderStateMixin, RouteAware {
with TickerProviderStateMixin, RouteAware {
// with RouteAware // with RouteAware
final LockDetailLogic logic = Get.put(LockDetailLogic()); final LockDetailLogic logic = Get.put(LockDetailLogic());
final LockDetailState state = Get.find<LockDetailLogic>().state; final LockDetailState state = Get.find<LockDetailLogic>().state;
@override @override
void initState() { void initState() {
super.initState(); state.animationController = AnimationController(duration: const Duration(seconds: 1), vsync: this);
state.animationController?.repeat();
state.animationController =
AnimationController(duration: const Duration(seconds: 1), vsync: this);
state.animationController!.repeat();
//StatusListener //StatusListener
state.animationController!.addStatusListener((AnimationStatus status) { state.animationController?.addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) { if (status == AnimationStatus.completed) {
state.animationController!.reset(); state.animationController?.reset();
state.animationController!.forward(); state.animationController?.forward();
} else if (status == AnimationStatus.dismissed) { } else if (status == AnimationStatus.dismissed) {
state.animationController!.reset(); state.animationController?.reset();
state.animationController!.forward(); state.animationController?.forward();
} }
}); });
super.initState();
state.pageController.addListener(() { state.pageController.addListener(() {
state.currentPage.value = state.pageController.page!.round(); state.currentPage.value = state.pageController.page!.round();
@ -77,9 +70,7 @@ class _LockDetailPageState extends State<LockDetailPage>
_initRefreshLockDetailInfoDataEventAction(); _initRefreshLockDetailInfoDataEventAction();
logic.initReplySubscription(); logic.initReplySubscription();
logic.initLockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceAction(); logic.initLockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceAction();
logic.loadData( logic.loadData(lockListInfoItemEntity: widget.lockListInfoItemEntity, isOnlyOneData: widget.isOnlyOneData);
lockListInfoItemEntity: widget.lockListInfoItemEntity,
isOnlyOneData: widget.isOnlyOneData);
} }
@override @override
@ -95,9 +86,8 @@ class _LockDetailPageState extends State<LockDetailPage>
void _initRefreshLockDetailInfoDataEventAction() { void _initRefreshLockDetailInfoDataEventAction() {
// eventBus // eventBus
_lockRefreshLockDetailInfoDataEvent = eventBus _lockRefreshLockDetailInfoDataEvent =
.on<RefreshLockDetailInfoDataEvent>() eventBus.on<RefreshLockDetailInfoDataEvent>().listen((RefreshLockDetailInfoDataEvent event) {
.listen((RefreshLockDetailInfoDataEvent event) {
setState(() {}); setState(() {});
}); });
} }
@ -109,17 +99,12 @@ class _LockDetailPageState extends State<LockDetailPage>
// //
Widget xhjWidget() { Widget xhjWidget() {
final bool isShowTip = (state.keyInfos.value.keyType == final bool isShowTip = (state.keyInfos.value.keyType == XSConstantMacro.keyTypeTime ||
XSConstantMacro.keyTypeTime ||
state.keyInfos.value.keyType == XSConstantMacro.keyTypeLoop) && state.keyInfos.value.keyType == XSConstantMacro.keyTypeLoop) &&
(DateTool().compareTimeGetDaysFromNow(state.keyInfos.value.endDate!) <= (DateTool().compareTimeGetDaysFromNow(state.keyInfos.value.endDate!) <= 15 &&
15 && DateTool().compareTimeGetDaysFromNow(state.keyInfos.value.endDate!) >= 0) &&
DateTool()
.compareTimeGetDaysFromNow(state.keyInfos.value.endDate!) >=
0) &&
(state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusNormalUse || (state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusNormalUse ||
state.keyInfos.value.keyStatus == state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusWaitReceive);
XSConstantMacro.keyStatusWaitReceive);
return Scaffold( return Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
body: Obx(() { body: Obx(() {
@ -141,8 +126,7 @@ class _LockDetailPageState extends State<LockDetailPage>
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(color: const Color(0xffCBA74B), fontSize: 24.sp)),
color: const Color(0xffCBA74B), fontSize: 24.sp)),
), ),
), ),
SizedBox(height: 10.h), SizedBox(height: 10.h),
@ -161,10 +145,7 @@ class _LockDetailPageState extends State<LockDetailPage>
SizedBox( SizedBox(
height: 20.h, height: 20.h,
), ),
labelText( labelText(img: 'images/icon_slider_horizontal.png', text: '功能'.tr, child: bottomWidget()),
img: 'images/icon_slider_horizontal.png',
text: '功能'.tr,
child: bottomWidget()),
btnText( btnText(
img: 'images/main/icon_main_set.png', img: 'images/main/icon_main_set.png',
text: '设置'.tr, text: '设置'.tr,
@ -172,17 +153,13 @@ class _LockDetailPageState extends State<LockDetailPage>
if (state.openDoorBtnisUneable.value == false) { if (state.openDoorBtnisUneable.value == false) {
return; return;
} }
Get.toNamed(Routers.lockSetPage, Get.toNamed(Routers.lockSetPage, arguments: <String, Object?>{
arguments: <String, Object?>{ 'lockId': state.keyInfos.value.lockId,
'lockId': state.keyInfos.value.lockId, 'isOnlyOneData': state.isOnlyOneData
'isOnlyOneData': state.isOnlyOneData });
});
}), }),
if (!F.isProductionEnv) if (!F.isProductionEnv)
labelText( labelText(img: 'images/icon_puzzlepiece_extension.png', text: '配件'.tr, child: attachmentWidget()),
img: 'images/icon_puzzlepiece_extension.png',
text: '配件'.tr,
child: attachmentWidget()),
], ],
), ),
), ),
@ -201,24 +178,21 @@ class _LockDetailPageState extends State<LockDetailPage>
); );
} }
Widget btnText( Widget btnText({required String img, required String text, required var onTap}) {
{required String img, required String text, required var onTap}) {
return GestureDetector( return GestureDetector(
onTap: onTap, onTap: onTap,
child: Container( child: Container(
margin: EdgeInsets.symmetric(horizontal: 0.05.sw, vertical: 15.h), margin: EdgeInsets.symmetric(horizontal: 0.05.sw, vertical: 15.h),
padding: EdgeInsets.symmetric(horizontal: 0.05.sw, vertical: 30.h), padding: EdgeInsets.symmetric(horizontal: 0.05.sw, vertical: 30.h),
decoration: BoxDecoration( decoration:
color: Colors.white, BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16.r), boxShadow: <BoxShadow>[
borderRadius: BorderRadius.circular(16.r), BoxShadow(
boxShadow: <BoxShadow>[ color: Colors.black.withOpacity(0.15),
BoxShadow( offset: const Offset(0, 0),
color: Colors.black.withOpacity(0.15), blurRadius: 5.r,
offset: const Offset(0, 0), spreadRadius: 0,
blurRadius: 5.r, ),
spreadRadius: 0, ]),
),
]),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
FlavorsImg( FlavorsImg(
@ -247,22 +221,18 @@ class _LockDetailPageState extends State<LockDetailPage>
); );
} }
Widget labelText( Widget labelText({required String img, required String text, required Widget child}) {
{required String img, required String text, required Widget child}) {
return Container( return Container(
margin: EdgeInsets.symmetric(horizontal: 0.05.sw, vertical: 15.h), margin: EdgeInsets.symmetric(horizontal: 0.05.sw, vertical: 15.h),
padding: EdgeInsets.symmetric(horizontal: 0.05.sw, vertical: 15.h), padding: EdgeInsets.symmetric(horizontal: 0.05.sw, vertical: 15.h),
decoration: BoxDecoration( decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16.r), boxShadow: <BoxShadow>[
color: Colors.white, BoxShadow(
borderRadius: BorderRadius.circular(16.r), color: Colors.black.withOpacity(0.15),
boxShadow: <BoxShadow>[ offset: const Offset(0, 0),
BoxShadow( blurRadius: 5.r,
color: Colors.black.withOpacity(0.15), spreadRadius: 0,
offset: const Offset(0, 0), ),
blurRadius: 5.r, ]),
spreadRadius: 0,
),
]),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Row( Row(
@ -328,13 +298,10 @@ class _LockDetailPageState extends State<LockDetailPage>
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[ children: <Widget>[
Image.asset(showElectricIcon(state.electricQuantity.value), Image.asset(showElectricIcon(state.electricQuantity.value), width: 30.w, height: 24.w),
width: 30.w, height: 24.w),
SizedBox(width: 2.w), SizedBox(width: 2.w),
Text('${state.electricQuantity.value}%', Text('${state.electricQuantity.value}%',
style: TextStyle( style: TextStyle(fontSize: 18.sp, color: AppColors.darkGrayTextColor)),
fontSize: 18.sp,
color: AppColors.darkGrayTextColor)),
SizedBox(width: 2.w), SizedBox(width: 2.w),
Icon( Icon(
Icons.info, // 使 warning Icons.info, // 使 warning
@ -345,24 +312,17 @@ class _LockDetailPageState extends State<LockDetailPage>
], ],
), ),
Visibility( Visibility(
visible: state visible: state.keyInfos.value.lockFeature!.isSupportBackupBattery == 1,
.keyInfos.value.lockFeature!.isSupportBackupBattery ==
1,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[ children: <Widget>[
FlavorsImg( FlavorsImg(
child: Image.asset( child: Image.asset(showElectricIcon(state.electricQuantityStandby.value),
showElectricIcon( width: 30.w, height: 24.w),
state.electricQuantityStandby.value),
width: 30.w,
height: 24.w),
), ),
SizedBox(width: 2.w), SizedBox(width: 2.w),
Text('${state.electricQuantityStandby.value}%', Text('${state.electricQuantityStandby.value}%',
style: TextStyle( style: TextStyle(fontSize: 18.sp, color: AppColors.darkGrayTextColor)),
fontSize: 18.sp,
color: AppColors.darkGrayTextColor)),
SizedBox(width: 2.w), SizedBox(width: 2.w),
FlavorsImg( FlavorsImg(
child: Icon( child: Icon(
@ -386,8 +346,7 @@ class _LockDetailPageState extends State<LockDetailPage>
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
if (state.openDoorBtnisUneable.value == true) { if (state.openDoorBtnisUneable.value == true) {
logic.functionBlocker logic.functionBlocker.block(isNeedRealNameAuthThenOpenLock);
.block(isNeedRealNameAuthThenOpenLock);
} }
}, },
onLongPressStart: (LongPressStartDetails details) { onLongPressStart: (LongPressStartDetails details) {
@ -457,12 +416,10 @@ class _LockDetailPageState extends State<LockDetailPage>
right: 90.w, right: 90.w,
bottom: 1, bottom: 1,
child: Obx(() => Visibility( child: Obx(() => Visibility(
visible: visible: state.keyInfos.value.lockSetting!.remoteUnlock == 1,
state.keyInfos.value.lockSetting!.remoteUnlock == 1,
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
ShowCupertinoAlertView().isToRemoteUnLockAlert( ShowCupertinoAlertView().isToRemoteUnLockAlert(remoteUnlockAction: () {
remoteUnlockAction: () {
if (state.keyInfos.value.hasGateway != 1) { if (state.keyInfos.value.hasGateway != 1) {
logic.showToast('附近没有可用网关'.tr); logic.showToast('附近没有可用网关'.tr);
} }
@ -508,34 +465,24 @@ class _LockDetailPageState extends State<LockDetailPage>
return ListView( return ListView(
children: <Widget>[ children: <Widget>[
Visibility( Visibility(
visible: visible: (state.keyInfos.value.keyType == XSConstantMacro.keyTypeTime ||
(state.keyInfos.value.keyType == XSConstantMacro.keyTypeTime || state.keyInfos.value.keyType == XSConstantMacro.keyTypeLoop) && //
state.keyInfos.value.keyType == (DateTool().compareTimeGetDaysFromNow(state.keyInfos.value.endDate!) <= 15 &&
XSConstantMacro.keyTypeLoop) && // DateTool().compareTimeGetDaysFromNow(state.keyInfos.value.endDate!) >= 0) && // 030
(DateTool().compareTimeGetDaysFromNow( (state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusNormalUse ||
state.keyInfos.value.endDate!) <= state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusWaitReceive) // 使
15 &&
DateTool().compareTimeGetDaysFromNow(
state.keyInfos.value.endDate!) >=
0) && // 030
(state.keyInfos.value.keyStatus ==
XSConstantMacro.keyStatusNormalUse ||
state.keyInfos.value.keyStatus ==
XSConstantMacro.keyStatusWaitReceive) // 使
, ,
child: Container( child: Container(
// height: 30.h, // height: 30.h,
width: 1.sw, width: 1.sw,
color: const Color(0xFFFBEFD4), color: const Color(0xFFFBEFD4),
padding: padding: EdgeInsets.only(top: 8.h, bottom: 8.h, right: 10.w, left: 10.h),
EdgeInsets.only(top: 8.h, bottom: 8.h, right: 10.w, left: 10.h),
child: Text( child: Text(
"${"钥匙将在".tr}${DateTool().compareTimeGetDaysFromNow(state.keyInfos.value.endDate!)}${"天后失效".tr}", "${"钥匙将在".tr}${DateTool().compareTimeGetDaysFromNow(state.keyInfos.value.endDate!)}${"天后失效".tr}",
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: style: TextStyle(color: const Color(0xffCBA74B), fontSize: 24.sp)),
TextStyle(color: const Color(0xffCBA74B), fontSize: 24.sp)),
), ),
), ),
Stack(children: <Widget>[ Stack(children: <Widget>[
@ -618,16 +565,11 @@ class _LockDetailPageState extends State<LockDetailPage>
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[ children: <Widget>[
FlavorsImg( FlavorsImg(
child: Image.asset( child: Image.asset(showElectricIcon(state.electricQuantity.value), width: 30.w, height: 24.w),
showElectricIcon(state.electricQuantity.value),
width: 30.w,
height: 24.w),
), ),
SizedBox(width: 2.w), SizedBox(width: 2.w),
Text('${state.electricQuantity.value}%', Text('${state.electricQuantity.value}%',
style: TextStyle( style: TextStyle(fontSize: 18.sp, color: AppColors.darkGrayTextColor)),
fontSize: 18.sp,
color: AppColors.darkGrayTextColor)),
SizedBox(width: 2.w), SizedBox(width: 2.w),
state.keyInfos.value.network?.isOnline == 1 state.keyInfos.value.network?.isOnline == 1
? Icon( ? Icon(
@ -649,24 +591,17 @@ class _LockDetailPageState extends State<LockDetailPage>
), ),
), ),
Visibility( Visibility(
visible: state visible: state.keyInfos.value.lockFeature!.isSupportBackupBattery == 1,
.keyInfos.value.lockFeature!.isSupportBackupBattery ==
1,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[ children: <Widget>[
FlavorsImg( FlavorsImg(
child: Image.asset( child: Image.asset(showElectricIcon(state.electricQuantityStandby.value),
showElectricIcon( width: 30.w, height: 24.w),
state.electricQuantityStandby.value),
width: 30.w,
height: 24.w),
), ),
SizedBox(width: 2.w), SizedBox(width: 2.w),
Text('${state.electricQuantityStandby.value}%', Text('${state.electricQuantityStandby.value}%',
style: TextStyle( style: TextStyle(fontSize: 18.sp, color: AppColors.darkGrayTextColor)),
fontSize: 18.sp,
color: AppColors.darkGrayTextColor)),
SizedBox(width: 2.w), SizedBox(width: 2.w),
FlavorsImg( FlavorsImg(
child: Icon( child: Icon(
@ -756,12 +691,10 @@ class _LockDetailPageState extends State<LockDetailPage>
right: 90.w, right: 90.w,
bottom: 1, bottom: 1,
child: Obx(() => Visibility( child: Obx(() => Visibility(
visible: visible: state.keyInfos.value.lockSetting!.remoteUnlock == 1,
state.keyInfos.value.lockSetting!.remoteUnlock == 1,
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
ShowCupertinoAlertView().isToRemoteUnLockAlert( ShowCupertinoAlertView().isToRemoteUnLockAlert(remoteUnlockAction: () {
remoteUnlockAction: () {
if (state.keyInfos.value.hasGateway != 1) { if (state.keyInfos.value.hasGateway != 1) {
logic.showToast('附近没有可用网关'.tr); logic.showToast('附近没有可用网关'.tr);
} }
@ -792,10 +725,7 @@ class _LockDetailPageState extends State<LockDetailPage>
logic.getKeyStatusTextAndShow(), logic.getKeyStatusTextAndShow(),
maxLines: 2, maxLines: 2,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(fontSize: 22.sp, color: AppColors.btnDisableColor, fontWeight: FontWeight.w500),
fontSize: 22.sp,
color: AppColors.btnDisableColor,
fontWeight: FontWeight.w500),
), ),
), ),
), ),
@ -818,8 +748,7 @@ class _LockDetailPageState extends State<LockDetailPage>
Widget adminInfoView({bool center = true, bool max = true}) { Widget adminInfoView({bool center = true, bool max = true}) {
return Row( return Row(
mainAxisAlignment: mainAxisAlignment: center ? MainAxisAlignment.center : MainAxisAlignment.start,
center ? MainAxisAlignment.center : MainAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Row( Row(
mainAxisSize: max ? MainAxisSize.max : MainAxisSize.min, mainAxisSize: max ? MainAxisSize.max : MainAxisSize.min,
@ -834,11 +763,8 @@ class _LockDetailPageState extends State<LockDetailPage>
Text( Text(
state.keyInfos.value.isLockOwner == 1 state.keyInfos.value.isLockOwner == 1
? '超级管理员英文'.tr ? '超级管理员英文'.tr
: (state.keyInfos.value.keyRight == 1 : (state.keyInfos.value.keyRight == 1 ? '授权管理员英文'.tr : '普通用户'.tr),
? '授权管理员英文'.tr style: TextStyle(fontSize: 20.sp, color: AppColors.darkGrayTextColor),
: '普通用户'.tr),
style: TextStyle(
fontSize: 20.sp, color: AppColors.darkGrayTextColor),
), ),
SizedBox(width: 40.w), SizedBox(width: 40.w),
], ],
@ -860,9 +786,7 @@ class _LockDetailPageState extends State<LockDetailPage>
'网关设备英文'.tr, '网关设备英文'.tr,
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 20.sp,
color: state.keyInfos.value.hasGateway == 1 color: state.keyInfos.value.hasGateway == 1 ? AppColors.mainColor : AppColors.btnDisableColor),
? AppColors.mainColor
: AppColors.btnDisableColor),
), ),
SizedBox(width: 20.w), SizedBox(width: 20.w),
], ],
@ -874,18 +798,14 @@ class _LockDetailPageState extends State<LockDetailPage>
child: Image.asset('images/main/icon_lockDetail_needNetwork.png', child: Image.asset('images/main/icon_lockDetail_needNetwork.png',
width: 24.w, width: 24.w,
height: 20.w, height: 20.w,
color: state.isOpenLockNeedOnline.value == 1 color: state.isOpenLockNeedOnline.value == 1 ? AppColors.mainColor : AppColors.btnDisableColor),
? AppColors.mainColor
: AppColors.btnDisableColor),
), ),
SizedBox(width: 6.w), SizedBox(width: 6.w),
Text( Text(
'手机需联网英文'.tr, '手机需联网英文'.tr,
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 20.sp,
color: state.isOpenLockNeedOnline.value == 1 color: state.isOpenLockNeedOnline.value == 1 ? AppColors.mainColor : AppColors.btnDisableColor),
? AppColors.mainColor
: AppColors.btnDisableColor),
), ),
], ],
) )
@ -893,9 +813,19 @@ class _LockDetailPageState extends State<LockDetailPage>
); );
} }
// Widget xhjBuildRotationTransition({required double width, required double height}) {
Widget xhjBuildRotationTransition( // animationController null
{required double width, required double height}) { if (state.animationController == null) {
return Positioned(
child: Image.asset(
'images/icon_circle_dotted.png',
width: width,
height: height,
color: state.isOpenPassageMode.value == 1 ? Colors.red : AppColors.mainColor,
),
);
}
return Positioned( return Positioned(
child: RotationTransition( child: RotationTransition(
// //
@ -907,17 +837,29 @@ class _LockDetailPageState extends State<LockDetailPage>
'images/icon_circle_dotted.png', 'images/icon_circle_dotted.png',
width: width, width: width,
height: height, height: height,
color: state.isOpenPassageMode.value == 1 color: state.isOpenPassageMode.value == 1 ? Colors.red : AppColors.mainColor,
? Colors.red
: AppColors.mainColor,
), ),
), ),
); );
} }
// //
Widget buildRotationTransition( Widget buildRotationTransition({required double width, required double height}) {
{required double width, required double height}) { //
if (state.animationController == null) {
return Positioned(
child: FlavorsImg(
child: Image.asset(
state.isOpenPassageMode.value == 1
? 'images/main/icon_main_normallyOpenMode_circle.png'
: 'images/main/icon_main_openLockBtn_circle.png',
width: width,
height: height,
),
),
);
}
return Positioned( return Positioned(
child: RotationTransition( child: RotationTransition(
// //
@ -949,9 +891,7 @@ class _LockDetailPageState extends State<LockDetailPage>
margin: EdgeInsets.symmetric(vertical: 10.0.w, horizontal: 6.0.w), margin: EdgeInsets.symmetric(vertical: 10.0.w, horizontal: 6.0.w),
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: state.currentPage.value == index color: state.currentPage.value == index ? AppColors.mainColor : Colors.grey,
? AppColors.mainColor
: Colors.grey,
), ),
); );
}), }),
@ -997,8 +937,7 @@ class _LockDetailPageState extends State<LockDetailPage>
// '开门器', state.bottomBtnisUneable.value, () {})); // '开门器', state.bottomBtnisUneable.value, () {}));
// //
showWidgetArr.add(bottomItem('images/main/icon_main_addLock.png', '新增配件'.tr, showWidgetArr.add(bottomItem('images/main/icon_main_addLock.png', '新增配件'.tr, state.bottomBtnisEable.value, () {
state.bottomBtnisEable.value, () {
Navigator.pushNamed(context, Routers.accessoriesListPage); Navigator.pushNamed(context, Routers.accessoriesListPage);
})); }));
@ -1015,8 +954,7 @@ class _LockDetailPageState extends State<LockDetailPage>
crossAxisSpacing: 0.h, crossAxisSpacing: 0.h,
mainAxisExtent: 90.0, // item mainAxisExtent: 90.0, // item
), ),
itemCount: (state.keyInfos.value.isLockOwner == 1 || itemCount: (state.keyInfos.value.isLockOwner == 1 || state.keyInfos.value.keyRight == 1)
state.keyInfos.value.keyRight == 1)
? getAllWidget().length ? getAllWidget().length
: getNormalWidget().length, : getNormalWidget().length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
@ -1041,8 +979,7 @@ class _LockDetailPageState extends State<LockDetailPage>
// //
List<Widget> getBottomWidget() { List<Widget> getBottomWidget() {
if (state.keyInfos.value.isLockOwner == 1 || if (state.keyInfos.value.isLockOwner == 1 || state.keyInfos.value.keyRight == 1) {
state.keyInfos.value.keyRight == 1) {
// //
return getAllWidget(); return getAllWidget();
} else { } else {
@ -1062,22 +999,17 @@ class _LockDetailPageState extends State<LockDetailPage>
// })); // }));
// } // }
// //
showWidgetArr.add(bottomItem('images/main/icon_main_operatingRecord.png', showWidgetArr
'操作记录'.tr, state.bottomBtnisEable.value, () { .add(bottomItem('images/main/icon_main_operatingRecord.png', '操作记录'.tr, state.bottomBtnisEable.value, () {
Get.toNamed(Routers.doorLockLogPage, Get.toNamed(Routers.doorLockLogPage,
arguments: <String, LockListInfoItemEntity>{ arguments: <String, LockListInfoItemEntity>{'keyInfo': state.keyInfos.value});
'keyInfo': state.keyInfos.value
});
})); }));
// //
if (F.isSKY) { if (F.isSKY) {
showWidgetArr showWidgetArr.add(bottomItem('images/main/icon_main_set.png', '设置'.tr, true, () {
.add(bottomItem('images/main/icon_main_set.png', '设置'.tr, true, () { Get.toNamed(Routers.lockSetPage,
Get.toNamed(Routers.lockSetPage, arguments: <String, Object?>{ arguments: <String, Object?>{'lockId': state.keyInfos.value.lockId, 'isOnlyOneData': state.isOnlyOneData});
'lockId': state.keyInfos.value.lockId,
'isOnlyOneData': state.isOnlyOneData
});
})); }));
} }
@ -1097,26 +1029,22 @@ class _LockDetailPageState extends State<LockDetailPage>
// } // }
// //
showWidgetArr.add(bottomItem('images/main/icon_main_electronicKey.png', showWidgetArr
'电子钥匙'.tr, state.bottomBtnisEable.value, () { .add(bottomItem('images/main/icon_main_electronicKey.png', '电子钥匙'.tr, state.bottomBtnisEable.value, () {
Get.toNamed(Routers.electronicKeyListPage); Get.toNamed(Routers.electronicKeyListPage);
})); }));
// //
if (state.keyInfos.value.lockFeature!.password == 1) { if (state.keyInfos.value.lockFeature!.password == 1) {
showWidgetArr.add(bottomItem('images/main/icon_main_password.png', showWidgetArr.add(bottomItem('images/main/icon_main_password.png', '密码'.tr, state.bottomBtnisEable.value, () {
'密码'.tr, state.bottomBtnisEable.value, () {
Get.toNamed(Routers.passwordKeyListPage, Get.toNamed(Routers.passwordKeyListPage,
arguments: <String, LockListInfoItemEntity>{ arguments: <String, LockListInfoItemEntity>{'keyInfo': state.keyInfos.value});
'keyInfo': state.keyInfos.value
});
})); }));
} }
// ic卡 // ic卡
if (state.keyInfos.value.lockFeature!.icCard == 1) { if (state.keyInfos.value.lockFeature!.icCard == 1) {
showWidgetArr.add(bottomItem('images/main/icon_main_icCard.png', ''.tr, showWidgetArr.add(bottomItem('images/main/icon_main_icCard.png', ''.tr, state.bottomBtnisEable.value, () {
state.bottomBtnisEable.value, () {
Get.toNamed(Routers.cardListPage, arguments: <String, int?>{ Get.toNamed(Routers.cardListPage, arguments: <String, int?>{
'lockId': state.keyInfos.value.lockId, 'lockId': state.keyInfos.value.lockId,
}); });
@ -1125,8 +1053,7 @@ class _LockDetailPageState extends State<LockDetailPage>
// //
if (state.keyInfos.value.lockFeature!.fingerprint == 1) { if (state.keyInfos.value.lockFeature!.fingerprint == 1) {
showWidgetArr.add(bottomItem('images/main/icon_main_fingerprint.png', showWidgetArr.add(bottomItem('images/main/icon_main_fingerprint.png', '指纹'.tr, state.bottomBtnisEable.value, () {
'指纹'.tr, state.bottomBtnisEable.value, () {
Get.toNamed(Routers.fingerprintListPage, arguments: <String, int?>{ Get.toNamed(Routers.fingerprintListPage, arguments: <String, int?>{
'lockId': state.keyInfos.value.lockId, 'lockId': state.keyInfos.value.lockId,
}); });
@ -1135,8 +1062,8 @@ class _LockDetailPageState extends State<LockDetailPage>
// //
if (state.keyInfos.value.lockFeature!.bluetoothRemoteControl == 1) { if (state.keyInfos.value.lockFeature!.bluetoothRemoteControl == 1) {
showWidgetArr.add(bottomItem('images/main/icon_main_remoteControl.png', showWidgetArr
'遥控'.tr, state.bottomBtnisEable.value, () { .add(bottomItem('images/main/icon_main_remoteControl.png', '遥控'.tr, state.bottomBtnisEable.value, () {
Get.toNamed(Routers.remoteControlListPage, arguments: <String, int?>{ Get.toNamed(Routers.remoteControlListPage, arguments: <String, int?>{
'lockId': state.keyInfos.value.lockId, 'lockId': state.keyInfos.value.lockId,
}); });
@ -1146,9 +1073,7 @@ class _LockDetailPageState extends State<LockDetailPage>
//-> //->
if (state.keyInfos.value.lockFeature!.d3Face == 1) { if (state.keyInfos.value.lockFeature!.d3Face == 1) {
showWidgetArr.add( showWidgetArr.add(
bottomItem( bottomItem('images/main/icon_face.png', '人脸'.tr, state.bottomBtnisEable.value, () {
'images/main/icon_face.png', '人脸'.tr, state.bottomBtnisEable.value,
() {
Get.toNamed(Routers.faceListPage, arguments: <String, int?>{ Get.toNamed(Routers.faceListPage, arguments: <String, int?>{
'lockId': state.keyInfos.value.lockId, 'lockId': state.keyInfos.value.lockId,
}); });
@ -1158,9 +1083,7 @@ class _LockDetailPageState extends State<LockDetailPage>
if (state.keyInfos.value.lockFeature!.isSupportIris == 1) { if (state.keyInfos.value.lockFeature!.isSupportIris == 1) {
showWidgetArr.add( showWidgetArr.add(
bottomItem( bottomItem('images/main/icon_iris.png', '虹膜'.tr, state.bottomBtnisEable.value, () {
'images/main/icon_iris.png', '虹膜'.tr, state.bottomBtnisEable.value,
() {
Get.toNamed(Routers.irisListPage, arguments: <String, int?>{ Get.toNamed(Routers.irisListPage, arguments: <String, int?>{
'lockId': state.keyInfos.value.lockId, 'lockId': state.keyInfos.value.lockId,
}); });
@ -1170,9 +1093,7 @@ class _LockDetailPageState extends State<LockDetailPage>
if (state.keyInfos.value.lockFeature!.palmVein == 1) { if (state.keyInfos.value.lockFeature!.palmVein == 1) {
showWidgetArr.add( showWidgetArr.add(
bottomItem( bottomItem('images/main/icon_palm.png', '掌静脉'.tr, state.bottomBtnisEable.value, () {
'images/main/icon_palm.png', '掌静脉'.tr, state.bottomBtnisEable.value,
() {
Get.toNamed(Routers.palmListPage, arguments: <String, int?>{ Get.toNamed(Routers.palmListPage, arguments: <String, int?>{
'lockId': state.keyInfos.value.lockId, 'lockId': state.keyInfos.value.lockId,
}); });
@ -1183,8 +1104,7 @@ class _LockDetailPageState extends State<LockDetailPage>
//-> //->
if (state.keyInfos.value.lockFeature!.isSupportCatEye == 1) { if (state.keyInfos.value.lockFeature!.isSupportCatEye == 1) {
showWidgetArr.add( showWidgetArr.add(
bottomItem('images/main/icon_catEyes.png', '监控'.tr, bottomItem('images/main/icon_catEyes.png', '监控'.tr, state.bottomBtnisEable.value, () async {
state.bottomBtnisEable.value, () async {
logic.sendMonitorMessage(); logic.sendMonitorMessage();
}), }),
); );
@ -1192,33 +1112,28 @@ class _LockDetailPageState extends State<LockDetailPage>
// //
if (state.keyInfos.value.isLockOwner == 1) { if (state.keyInfos.value.isLockOwner == 1) {
showWidgetArr.add(bottomItem('images/main/icon_main_authorizedAdmin.png', showWidgetArr
'授权管理员'.tr, state.bottomBtnisEable.value, () { .add(bottomItem('images/main/icon_main_authorizedAdmin.png', '授权管理员'.tr, state.bottomBtnisEable.value, () {
Get.toNamed(Routers.authorizedAdminListPage, Get.toNamed(Routers.authorizedAdminListPage,
arguments: <String, LockListInfoItemEntity>{ arguments: <String, LockListInfoItemEntity>{'keyInfo': state.keyInfos.value});
'keyInfo': state.keyInfos.value
});
})); }));
} }
final List<Widget> endWiddget = <Widget>[]; final List<Widget> endWiddget = <Widget>[];
endWiddget.add( endWiddget.add(
// //
bottomItem('images/main/icon_main_operatingRecord.png', '操作记录'.tr, bottomItem('images/main/icon_main_operatingRecord.png', '操作记录'.tr, state.bottomBtnisEable.value, () {
state.bottomBtnisEable.value, () {
// Get.toNamed(Routers.lockOperatingRecordPage, // Get.toNamed(Routers.lockOperatingRecordPage,
// arguments: {"keyInfo": state.keyInfos.value}); // arguments: {"keyInfo": state.keyInfos.value});
Get.toNamed(Routers.doorLockLogPage, Get.toNamed(Routers.doorLockLogPage,
arguments: <String, LockListInfoItemEntity>{ arguments: <String, LockListInfoItemEntity>{'keyInfo': state.keyInfos.value});
'keyInfo': state.keyInfos.value
});
}), }),
); );
if (state.keyInfos.value.lockFeature!.isSupportCatEye == 1) { if (state.keyInfos.value.lockFeature!.isSupportCatEye == 1) {
// //
endWiddget.add(bottomItem('images/main/icon_lockDetail_videoLog.png', endWiddget
'视频日志'.tr, state.bottomBtnisEable.value, () { .add(bottomItem('images/main/icon_lockDetail_videoLog.png', '视频日志'.tr, state.bottomBtnisEable.value, () {
Get.toNamed(Routers.videoLogPage, arguments: <String, int?>{ Get.toNamed(Routers.videoLogPage, arguments: <String, int?>{
'lockId': state.keyInfos.value.lockId, 'lockId': state.keyInfos.value.lockId,
}); });
@ -1227,12 +1142,10 @@ class _LockDetailPageState extends State<LockDetailPage>
if (!F.isProductionEnv) { if (!F.isProductionEnv) {
endWiddget.add( endWiddget.add(
// //
bottomItem('images/main/icon_lockDetail_messageReminding.png', bottomItem('images/main/icon_lockDetail_messageReminding.png', '消息提醒'.tr, state.bottomBtnisEable.value, () {
'消息提醒'.tr, state.bottomBtnisEable.value, () {
Get.toNamed(Routers.msgNotificationPage, arguments: <String, int?>{ Get.toNamed(Routers.msgNotificationPage, arguments: <String, int?>{
'lockId': state.keyInfos.value.lockId, 'lockId': state.keyInfos.value.lockId,
'isSupportCatEye': 'isSupportCatEye': state.keyInfos.value.lockFeature!.isSupportCatEye,
state.keyInfos.value.lockFeature!.isSupportCatEye,
}); });
}), }),
); );
@ -1254,8 +1167,7 @@ class _LockDetailPageState extends State<LockDetailPage>
return showWidgetArr; return showWidgetArr;
} }
Widget bottomItem( Widget bottomItem(String iconUrl, String name, bool bottomBtnisEable, Function() onClick) {
String iconUrl, String name, bool bottomBtnisEable, Function() onClick) {
final Widget child = F.sw( final Widget child = F.sw(
skyCall: () => Container( skyCall: () => Container(
color: Colors.white, color: Colors.white,
@ -1268,9 +1180,7 @@ class _LockDetailPageState extends State<LockDetailPage>
child: Image.asset(iconUrl, child: Image.asset(iconUrl,
width: 42.w, width: 42.w,
height: 42.w, height: 42.w,
color: bottomBtnisEable color: bottomBtnisEable ? AppColors.mainColor : AppColors.lockDetailBottomBtnUneable,
? AppColors.mainColor
: AppColors.lockDetailBottomBtnUneable,
fit: BoxFit.fitWidth), fit: BoxFit.fitWidth),
), ),
SizedBox(height: 5.h), SizedBox(height: 5.h),
@ -1278,9 +1188,7 @@ class _LockDetailPageState extends State<LockDetailPage>
child: Text(name, child: Text(name,
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 20.sp,
color: bottomBtnisEable color: bottomBtnisEable ? AppColors.blackColor : AppColors.lockDetailBottomBtnUneable),
? AppColors.blackColor
: AppColors.lockDetailBottomBtnUneable),
textAlign: TextAlign.center)) textAlign: TextAlign.center))
], ],
), ),
@ -1298,9 +1206,7 @@ class _LockDetailPageState extends State<LockDetailPage>
child: Image.asset(iconUrl, child: Image.asset(iconUrl,
width: 42.w, width: 42.w,
height: 42.w, height: 42.w,
color: bottomBtnisEable color: bottomBtnisEable ? AppColors.mainColor : AppColors.lockDetailBottomBtnUneable,
? AppColors.mainColor
: AppColors.lockDetailBottomBtnUneable,
fit: BoxFit.fitWidth), fit: BoxFit.fitWidth),
), ),
SizedBox(height: 15.h), SizedBox(height: 15.h),
@ -1313,9 +1219,7 @@ class _LockDetailPageState extends State<LockDetailPage>
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 20.sp,
height: 1.0, height: 1.0,
color: bottomBtnisEable color: bottomBtnisEable ? AppColors.blackColor : AppColors.lockDetailBottomBtnUneable),
? AppColors.blackColor
: AppColors.lockDetailBottomBtnUneable),
), ),
], ],
), ),
@ -1347,18 +1251,14 @@ class _LockDetailPageState extends State<LockDetailPage>
Widget _unlockSuccessWidget() { Widget _unlockSuccessWidget() {
String lockAlias = state.keyInfos.value.lockAlias!; String lockAlias = state.keyInfos.value.lockAlias!;
final TextStyle lockAliasTextStyle = final TextStyle lockAliasTextStyle = TextStyle(color: AppColors.placeholderTextColor, fontSize: 24.sp);
TextStyle(color: AppColors.placeholderTextColor, fontSize: 24.sp);
final TextPainter textPainter = TextPainter( final TextPainter textPainter = TextPainter(
text: TextSpan(text: lockAlias, style: lockAliasTextStyle), text: TextSpan(text: lockAlias, style: lockAliasTextStyle), maxLines: 1, textDirection: TextDirection.ltr)
maxLines: 1,
textDirection: TextDirection.ltr)
..layout(minWidth: 0, maxWidth: double.infinity); ..layout(minWidth: 0, maxWidth: double.infinity);
final double textSizeWidth = textPainter.size.width; // final double textSizeWidth = textPainter.size.width; //
if (textSizeWidth > 358.w * 2 - 20) { if (textSizeWidth > 358.w * 2 - 20) {
lockAlias = lockAlias = '${lockAlias.substring(0, lockAlias.length > 25 ? 25 : lockAlias.length)}...';
'${lockAlias.substring(0, lockAlias.length > 25 ? 25 : lockAlias.length)}...';
} }
return Center( return Center(
child: Stack( child: Stack(
@ -1378,17 +1278,13 @@ class _LockDetailPageState extends State<LockDetailPage>
Text(state.iSOpenLock.value == true ? '已开锁'.tr : '已闭锁'.tr, Text(state.iSOpenLock.value == true ? '已开锁'.tr : '已闭锁'.tr,
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(color: AppColors.mainColor, fontSize: 32.sp, fontWeight: FontWeight.w600)),
color: AppColors.mainColor,
fontSize: 32.sp,
fontWeight: FontWeight.w600)),
SizedBox( SizedBox(
height: 10.h, height: 10.h,
), ),
Text( Text(
lockAlias, lockAlias,
style: TextStyle( style: TextStyle(color: AppColors.placeholderTextColor, fontSize: 24.sp),
color: AppColors.placeholderTextColor, fontSize: 24.sp),
maxLines: 2, maxLines: 2,
), ),
SizedBox( SizedBox(
@ -1396,8 +1292,7 @@ class _LockDetailPageState extends State<LockDetailPage>
), ),
Text( Text(
getCurrentFormattedTime(), getCurrentFormattedTime(),
style: TextStyle( style: TextStyle(color: AppColors.darkGrayTextColor, fontSize: 24.sp),
color: AppColors.darkGrayTextColor, fontSize: 24.sp),
) )
], ],
)), )),
@ -1468,7 +1363,7 @@ class _LockDetailPageState extends State<LockDetailPage>
// } // }
state.iSOpenLock.value = true; state.iSOpenLock.value = true;
state.openLockBtnState.value = 1; state.openLockBtnState.value = 1;
state.animationController!.forward(); state.animationController?.forward();
AppLog.log('点击开锁'); AppLog.log('点击开锁');
if (isOpenLockNeedOnline) { if (isOpenLockNeedOnline) {
// //
@ -1476,10 +1371,7 @@ class _LockDetailPageState extends State<LockDetailPage>
// AppLog.log('点击开锁 state.openDoorModel = 0 不需要联网'); // AppLog.log('点击开锁 state.openDoorModel = 0 不需要联网');
// FlutterBuglyPlugin.reportException(exceptionName: '点击了不需要联网开锁'); // FlutterBuglyPlugin.reportException(exceptionName: '点击了不需要联网开锁');
BuglyTool.uploadException( BuglyTool.uploadException(
message: '点击了不需要联网开锁', message: '点击了不需要联网开锁', detail: '点击了不需要联网开锁 openDoorModel:${state.openDoorModel}', upload: false, begin: true);
detail: '点击了不需要联网开锁 openDoorModel:${state.openDoorModel}',
upload: false,
begin: true);
AppLog.log('点击开锁 state.openDoorModel = 0 不需要联网'); AppLog.log('点击开锁 state.openDoorModel = 0 不需要联网');
logic.openDoorAction(); logic.openDoorAction();
} else { } else {
@ -1488,10 +1380,7 @@ class _LockDetailPageState extends State<LockDetailPage>
// AppLog.log('点击开锁 state.openDoorModel = 2 需要联网'); // AppLog.log('点击开锁 state.openDoorModel = 2 需要联网');
// FlutterBuglyPlugin.reportException(exceptionName: '点击了需要联网开锁'); // FlutterBuglyPlugin.reportException(exceptionName: '点击了需要联网开锁');
BuglyTool.uploadException( BuglyTool.uploadException(
message: '点击了需要联网开锁', message: '点击了需要联网开锁', detail: '点击了需要联网开锁 openDoorModel:${state.openDoorModel}', upload: false, begin: true);
detail: '点击了需要联网开锁 openDoorModel:${state.openDoorModel}',
upload: false,
begin: true);
AppLog.log('点击开锁 state.openDoorModel = 2 需要联网'); AppLog.log('点击开锁 state.openDoorModel = 2 需要联网');
logic.getLockNetToken(); logic.getLockNetToken();
} }
@ -1503,7 +1392,7 @@ class _LockDetailPageState extends State<LockDetailPage>
} }
state.iSOpenLock.value = false; state.iSOpenLock.value = false;
state.openLockBtnState.value = 1; state.openLockBtnState.value = 1;
state.animationController!.forward(); state.animationController?.forward();
EasyLoading.showToast('正在尝试闭锁……'.tr, duration: 1000.milliseconds); EasyLoading.showToast('正在尝试闭锁……'.tr, duration: 1000.milliseconds);
AppLog.log('长按闭锁'); AppLog.log('长按闭锁');
if (state.isOpenLockNeedOnline.value == 0) { if (state.isOpenLockNeedOnline.value == 0) {
@ -1526,11 +1415,10 @@ class _LockDetailPageState extends State<LockDetailPage>
state.closedUnlockSuccessfulTimer?.cancel(); state.closedUnlockSuccessfulTimer?.cancel();
_lockRefreshLockDetailInfoDataEvent?.cancel(); _lockRefreshLockDetailInfoDataEvent?.cancel();
state.replySubscription.cancel(); state.replySubscription.cancel();
state.lockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceEvent state.lockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceEvent?.cancel();
?.cancel();
state.LockSetChangeSetRefreshLockDetailWithTypeSubscription?.cancel(); state.LockSetChangeSetRefreshLockDetailWithTypeSubscription?.cancel();
if (state.animationController != null) { if (state.animationController != null) {
state.animationController!.dispose(); state.animationController?.dispose();
state.animationController = null; state.animationController = null;
} }
super.dispose(); super.dispose();

View File

@ -58,8 +58,26 @@ class LockDetailState {
int logCountPage = 10; // int logCountPage = 10; //
RxInt nextAuthTime = 0.obs; // RxInt nextAuthTime = 0.obs; //
// LockDetailState() { int countReq = 10;//
// Map map = Get.arguments; RxInt indexCount = 0.obs;// 0/5
// lockCount = map["lockCount"];
// } int uploadPasswordPage = 0;//
List<int> uploadPasswordDataList = <int>[];//
int uploadCardPage = 0;//
List<int> uploadCardDataList = <int>[];//
int uploadFingerprintPage = 0;//
List<int> uploadFingerprintDataList = <int>[];//
int uploadFacePage = 0;//
List<int> uploadFaceDataList = <int>[];//
int uploadPalmVeinPage = 0;//
List<int> uploadPalmVeinDataList = <int>[];//
int uploadRemoteControlPage = 0;//
List<int> uploadRemoteControlDataList = <int>[];//
List<int> uploadLockSetDataList = <int>[];//
} }

View File

@ -0,0 +1,7 @@
import 'package:star_lock/main/lockDetail/lockSet/aiAssistant/ai_assistant_state.dart';
import 'package:star_lock/tools/baseGetXController.dart';
class AiAssistantLogic extends BaseGetXController{
final AiAssistantState state = AiAssistantState();
}

View File

@ -0,0 +1,90 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:star_lock/app_settings/app_colors.dart';
import 'package:star_lock/main/lockDetail/lockSet/aiAssistant/ai_assistant_logic.dart';
import 'package:star_lock/main/lockDetail/lockSet/aiAssistant/ai_assistant_state.dart';
import 'package:star_lock/tools/commonItem.dart';
import 'package:star_lock/tools/titleAppBar.dart';
class AiAssistantPage extends StatefulWidget {
const AiAssistantPage({Key? key}) : super(key: key);
@override
State<AiAssistantPage> createState() => _AiAssistantPageState();
}
class _AiAssistantPageState extends State<AiAssistantPage> {
final AiAssistantLogic logic = Get.put(AiAssistantLogic());
final AiAssistantState state = Get.find<AiAssistantLogic>().state;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: TitleAppBar(barTitle: 'AI助理设置'.tr, haveBack: true, backgroundColor: AppColors.mainColor),
body: Container(
width: 1.sw,
padding: EdgeInsets.symmetric(horizontal: 20.w),
margin: EdgeInsets.only(top: 20.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset(
'images/other/ai.png',
height: 250.h,
fit: BoxFit.cover,
),
SizedBox(
height: 50.h,
),
Text(
'AI助理的支持依赖网络授权下载打开功能开关时请保证手机数据网络的正常连接'.tr,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20.sp,
color: Colors.grey,
fontWeight: FontWeight.w500,
),
),
SizedBox(
height: 50.h,
),
CommonItem(
leftTitel: 'Ai语音菜单'.tr,
rightTitle: '',
isHaveLine: true,
// 线
isHaveDirection: false,
isHaveRightWidget: true,
rightWidget: CupertinoSwitch(
value: false,
onChanged: (value) {},
),
action: () {
logic.showToast('功能待开放'.tr);
},
),
CommonItem(
leftTitel: 'Ai智能语音交互'.tr,
rightTitle: '',
isHaveLine: false,
// 线
isHaveDirection: false,
isHaveRightWidget: true,
rightWidget: CupertinoSwitch(
value: false,
onChanged: (value) {},
),
action: () {
logic.showToast('功能待开放'.tr);
},
)
],
),
),
);
}
}

View File

@ -0,0 +1,12 @@
import 'package:get/get.dart';
import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSetInfo_entity.dart';
class AiAssistantState {
AiAssistantState() {
final map = Get.arguments;
lockSetInfoData.value = map['lockSetInfoData'];
}
Rx<LockSetInfoData> lockSetInfoData = LockSetInfoData().obs;
}

View File

@ -35,10 +35,7 @@ class _BasicInformationPageState extends State<BasicInformationPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: AppColors.mainBackgroundColor, backgroundColor: AppColors.mainBackgroundColor,
appBar: TitleAppBar( appBar: TitleAppBar(barTitle: '基本信息'.tr, haveBack: true, backgroundColor: AppColors.mainColor),
barTitle: '基本信息'.tr,
haveBack: true,
backgroundColor: AppColors.mainColor),
body: ListView( body: ListView(
children: <Widget>[ children: <Widget>[
Obx(() => CommonItem( Obx(() => CommonItem(
@ -48,8 +45,7 @@ class _BasicInformationPageState extends State<BasicInformationPage> {
isHaveLine: true)), isHaveLine: true)),
Obx(() => CommonItem( Obx(() => CommonItem(
leftTitel: 'MAC/ID', leftTitel: 'MAC/ID',
rightTitle: rightTitle: "${state.lockBasicInfo.value.mac ?? ""}/${state.lockBasicInfo.value.lockId ?? ""}",
"${state.lockBasicInfo.value.mac ?? ""}/${state.lockBasicInfo.value.lockId ?? ""}",
allHeight: 70.h, allHeight: 70.h,
isHaveLine: true)), isHaveLine: true)),
// Obx(() => CommonItem( // Obx(() => CommonItem(
@ -67,22 +63,17 @@ class _BasicInformationPageState extends State<BasicInformationPage> {
), ),
Obx(() => CommonItem( Obx(() => CommonItem(
leftTitel: '电量'.tr, leftTitel: '电量'.tr,
rightTitle: rightTitle: '${state.lockBasicInfo.value.electricQuantity ?? 0}%',
'${state.lockBasicInfo.value.electricQuantity ?? 0}%',
isHaveLine: true, isHaveLine: true,
isHaveDirection: true, isHaveDirection: true,
action: () { action: () {
Get.toNamed(Routers.uploadElectricQuantityPage, Get.toNamed(Routers.uploadElectricQuantityPage,
arguments: <String, LockSetInfoData>{ arguments: <String, LockSetInfoData>{'lockSetInfoData': state.lockSetInfoData.value});
'lockSetInfoData': state.lockSetInfoData.value
});
})), })),
Obx(() => CommonItem( Obx(() => CommonItem(
leftTitel: '有效期'.tr, leftTitel: '有效期'.tr,
rightTitle: logic.getUseKeyTypeStr( rightTitle: logic.getUseKeyTypeStr(state.lockBasicInfo.value.startDate,
state.lockBasicInfo.value.startDate, state.lockBasicInfo.value.endDate, state.lockBasicInfo.value.keyType),
state.lockBasicInfo.value.endDate,
state.lockBasicInfo.value.keyType),
allHeight: 70.h, allHeight: 70.h,
isHaveLine: true)), isHaveLine: true)),
Obx(() => Visibility( Obx(() => Visibility(
@ -104,28 +95,19 @@ class _BasicInformationPageState extends State<BasicInformationPage> {
)), )),
SizedBox(height: 10.h), SizedBox(height: 10.h),
Obx(() => Visibility( Obx(() => Visibility(
visible: state.lockBasicInfo.value.isLockOwner == 1 || visible: state.lockBasicInfo.value.isLockOwner == 1 || state.lockBasicInfo.value.keyRight == 1,
state.lockBasicInfo.value.keyRight == 1, child: lockDataListItem('名称'.tr, state.lockBasicInfo.value.lockAlias ?? '', () async {
child: lockDataListItem(
'名称'.tr, state.lockBasicInfo.value.lockAlias ?? '',
() async {
var data = await Get.toNamed(Routers.editLockNamePage, var data = await Get.toNamed(Routers.editLockNamePage,
arguments: <String, LockSetInfoData>{ arguments: <String, LockSetInfoData>{'lockSetInfoData': state.lockSetInfoData.value});
'lockSetInfoData': state.lockSetInfoData.value
});
if (data != null) { if (data != null) {
setState(() { setState(() {
state.lockBasicInfo.value = data['lockBasicInfo']; state.lockBasicInfo.value = data['lockBasicInfo'];
}); });
} }
}))), }))),
Obx(() => lockDataListItem( Obx(() => lockDataListItem('锁分组'.tr, state.lockBasicInfo.value.groupName ?? '', () async {
'锁分组'.tr, state.lockBasicInfo.value.groupName ?? '',
() async {
Get.toNamed(Routers.lockSelectGroupingPage, Get.toNamed(Routers.lockSelectGroupingPage,
arguments: <String, LockSetInfoData>{ arguments: <String, LockSetInfoData>{'lockSetInfoData': state.lockSetInfoData.value})!
'lockSetInfoData': state.lockSetInfoData.value
})!
.then((val) { .then((val) {
if (val != null) { if (val != null) {
// mockNetworkDataRequest(); // mockNetworkDataRequest();
@ -142,22 +124,41 @@ class _BasicInformationPageState extends State<BasicInformationPage> {
isHaveDirection: true, isHaveDirection: true,
action: () { action: () {
Get.toNamed(Routers.adminOpenLockPasswordPage, Get.toNamed(Routers.adminOpenLockPasswordPage,
arguments: <String, LockSetInfoData>{ arguments: <String, LockSetInfoData>{'lockSetInfoData': state.lockSetInfoData.value});
'lockSetInfoData': state.lockSetInfoData.value
});
}), }),
)), )),
Obx(() => Visibility( Obx(
visible: (state.lockBasicInfo.value.lockName ?? '') () => Visibility(
.contains('T9A'), visible: state.lockSetInfoData.value.lockFeature?.wifi == 1,
child: CommonItem( child: CommonItem(
leftTitel: '当前网络'.tr, leftTitel: '当前网络'.tr,
rightTitle: rightTitle: state.lockBasicInfo.value.networkInfo?.wifiName ?? '-',
state.lockBasicInfo.value.networkInfo?.wifiName ?? allHeight: 70.h,
'-', isHaveLine: true),
allHeight: 70.h, ),
isHaveLine: true), ),
)), Obx(
() => Visibility(
visible: state.lockSetInfoData.value.lockFeature?.wifi == 1,
child: CommonItem(
leftTitel: '网络信号强度'.tr,
rightTitle: '-',
allHeight: 70.h,
isHaveLine: true,
),
),
),
Obx(
() => Visibility(
visible: state.lockSetInfoData.value.lockFeature?.wifi == 1,
child: CommonItem(
leftTitel: '设备时区'.tr,
rightTitle: '-',
allHeight: 70.h,
isHaveLine: true,
),
),
),
// Obx(() => CommonItem( // Obx(() => CommonItem(
// leftTitel: '位置信息'.tr, // leftTitel: '位置信息'.tr,
// // rightTitle: state.lockBasicInfo.value.address ?? "-", // // rightTitle: state.lockBasicInfo.value.address ?? "-",
@ -190,14 +191,12 @@ class _BasicInformationPageState extends State<BasicInformationPage> {
)); ));
} }
Widget lockDataListItem( Widget lockDataListItem(String leftTitle, String conentStr, Function()? action) {
String leftTitle, String conentStr, Function()? action) {
return GestureDetector( return GestureDetector(
onTap: action, onTap: action,
child: Container( child: Container(
// height: 70.h, // height: 70.h,
padding: padding: EdgeInsets.only(left: 20.w, right: 10.w, top: 15.h, bottom: 15.h),
EdgeInsets.only(left: 20.w, right: 10.w, top: 15.h, bottom: 15.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
border: Border( border: Border(

View File

@ -89,27 +89,27 @@ class _CatEyeCustomModePageState extends State<CatEyeCustomModePage> {
SizedBox( SizedBox(
height: 30.h, height: 30.h,
), ),
Container( // Container(
margin: EdgeInsets.only(left: 20.w), // margin: EdgeInsets.only(left: 20.w),
child: CommonItem( // child: CommonItem(
leftTitel: '实时画面'.tr, // leftTitel: '实时画面'.tr,
rightTitle: state.realTimeMode.value, // rightTitle: state.realTimeMode.value,
isHaveLine: false, // isHaveLine: false,
isHaveDirection: true, // isHaveDirection: true,
isHaveRightWidget: false, // isHaveRightWidget: false,
action: () { // action: () {
Navigator.pushNamed(context, Routers.liveVideoPage, // Navigator.pushNamed(context, Routers.liveVideoPage,
arguments: { // arguments: {
'lockSetInfoData': state.lockSetInfoData.value, // 'lockSetInfoData': state.lockSetInfoData.value,
'catEyeConfigData': state.lockSetInfoData.value // 'catEyeConfigData': state.lockSetInfoData.value
.lockSettingInfo!.catEyeConfig!.isNotEmpty // .lockSettingInfo!.catEyeConfig!.isNotEmpty
? state.lockSetInfoData.value.lockSettingInfo! // ? state.lockSetInfoData.value.lockSettingInfo!
.catEyeConfig![0] // .catEyeConfig![0]
: null // : null
}); // });
}, // },
), // ),
) // )
], ],
), ),
), ),

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/blue/blue_manage.dart'; import 'package:star_lock/blue/blue_manage.dart';
import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsWithParameters.dart'; import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsWithParameters.dart';
import 'package:star_lock/blue/io_reply.dart'; import 'package:star_lock/blue/io_reply.dart';
@ -82,30 +83,31 @@ class CatEyeSetLogic extends BaseGetXController {
// //
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
dismissEasyLoading(); dismissEasyLoading();
AppLog.log('state.settingOptions.value:${state.settingOptions.value}');
switch (state.settingOptions.value) { switch (state.settingOptions.value) {
case 1: // case 1: //
{ {
updateAutoLightScreenConfig(); await updateAutoLightScreenConfig();
} }
break; break;
case 2: // case 2: //
{ {
updateStayWarnConfig(); await updateStayWarnConfig();
} }
break; break;
case 3: // case 3: //
{ {
updateAbnormalWarnConfig(); await updateAbnormalWarnConfig();
} }
break; break;
case 4: // case 4: //
{ {
updateLightScreenTimeConfig(); await updateLightScreenTimeConfig();
} }
break; break;
case 5: // case 5: //
{ {
updateCatEyeModeConfig(); await updateCatEyeModeConfig();
} }
break; break;
default: default:
@ -288,6 +290,7 @@ class CatEyeSetLogic extends BaseGetXController {
.catEyeConfig![0] .catEyeConfig![0]
.catEyeModeConfig .catEyeModeConfig
?.realTimeMode = state.catEyeConfig.value.realTimeMode; ?.realTimeMode = state.catEyeConfig.value.realTimeMode;
eventBus eventBus
.fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value)); .fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value));
} }
@ -456,6 +459,10 @@ class CatEyeSetLogic extends BaseGetXController {
} }
void sendBlueMessage() { void sendBlueMessage() {
showEasyLoading();
showBlueConnetctToastTimer(action: () {
dismissEasyLoading();
});
final message = _buildCatEyeSetBlueMessage(); final message = _buildCatEyeSetBlueMessage();
BlueManage().blueSendData(BlueManage().connectDeviceName, BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState connectionState) async { (BluetoothConnectionState connectionState) async {

View File

@ -80,12 +80,12 @@ class _CatEyeSetPageState extends State<CatEyeSetPage> {
isHaveRightWidget: true, isHaveRightWidget: true,
rightWidget: _otherToDoSwitch(2), rightWidget: _otherToDoSwitch(2),
)), )),
Obx(() => CommonItem( // Obx(() => CommonItem(
leftTitel: '异常警告'.tr, // leftTitel: '异常警告'.tr,
rightTitle: '', // rightTitle: '',
isHaveLine: true, // isHaveLine: true,
isHaveRightWidget: true, // isHaveRightWidget: true,
rightWidget: _otherToDoSwitch(3))), // rightWidget: _otherToDoSwitch(3))),
//ToDo //ToDo
CommonItem( CommonItem(
leftTitel: '呼叫目标'.tr, leftTitel: '呼叫目标'.tr,

View File

@ -442,10 +442,13 @@ class LockSetLogic extends BaseGetXController {
} }
// //
Future<LockSetInfoEntity> getLockSettingInfoData() async { Future<LockSetInfoEntity> getLockSettingInfoData({
bool isUnShowLoading = false,
}) async {
final LockSetInfoEntity entity = final LockSetInfoEntity entity =
await ApiRepository.to.getLockSettingInfoData( await ApiRepository.to.getLockSettingInfoData(
lockId: state.lockId.toString(), lockId: state.lockId.toString(),
isUnShowLoading: isUnShowLoading,
); );
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
state.lockSetInfoData.value = entity.data!; state.lockSetInfoData.value = entity.data!;
@ -718,7 +721,7 @@ class LockSetLogic extends BaseGetXController {
records: records, records: records,
isUnShowLoading: true); isUnShowLoading: true);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
await getLockSettingInfoData(); await getLockSettingInfoData(isUnShowLoading: true);
update(); update();
} }
} }

Some files were not shown because too many files have changed in this diff Show More